mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 15:36:49 +08:00
Refine login glass effect and plugin menu icon
This commit is contained in:
+12
-3
@@ -68,9 +68,7 @@ const activeImageIndex = ref(0)
|
|||||||
const previousImageIndex = ref<number | null>(null)
|
const previousImageIndex = ref<number | null>(null)
|
||||||
const isTransparentTheme = computed(() => globalTheme.name.value === 'transparent')
|
const isTransparentTheme = computed(() => globalTheme.name.value === 'transparent')
|
||||||
const isLoginWallpaperRoute = computed(() => !isLogin.value && route.path === LOGIN_WALLPAPER_ROUTE)
|
const isLoginWallpaperRoute = computed(() => !isLogin.value && route.path === LOGIN_WALLPAPER_ROUTE)
|
||||||
const shouldUseTransparentBackgroundTreatment = computed(
|
const shouldUseTransparentBackgroundTreatment = computed(() => Boolean(isLogin.value) && isTransparentTheme.value)
|
||||||
() => (Boolean(isLogin.value) && isTransparentTheme.value) || isLoginWallpaperRoute.value,
|
|
||||||
)
|
|
||||||
const shouldLoadBackgroundImages = computed(
|
const shouldLoadBackgroundImages = computed(
|
||||||
() => isLoginWallpaperRoute.value || (Boolean(isLogin.value) && isTransparentTheme.value),
|
() => isLoginWallpaperRoute.value || (Boolean(isLogin.value) && isTransparentTheme.value),
|
||||||
)
|
)
|
||||||
@@ -89,6 +87,7 @@ let backgroundRequestController: AbortController | null = null
|
|||||||
let backgroundCrossfadeTimer: number | null = null
|
let backgroundCrossfadeTimer: number | null = null
|
||||||
let authenticatedStateTimer: number | null = null
|
let authenticatedStateTimer: number | null = null
|
||||||
|
|
||||||
|
// 读取并同步透明主题背景设置到根组件响应式状态。
|
||||||
function applyTransparentBackgroundSettings() {
|
function applyTransparentBackgroundSettings() {
|
||||||
const settings = applyStoredTransparencySettings()
|
const settings = applyStoredTransparencySettings()
|
||||||
|
|
||||||
@@ -96,6 +95,7 @@ function applyTransparentBackgroundSettings() {
|
|||||||
transparencyGlassQuality.value = settings.glassQuality
|
transparencyGlassQuality.value = settings.glassQuality
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 响应透明主题设置变更事件,刷新背景模糊和玻璃质量。
|
||||||
function handleTransparencySettingsChanged(event: Event) {
|
function handleTransparencySettingsChanged(event: Event) {
|
||||||
const { backgroundBlur, glassQuality } = (event as CustomEvent<TransparencySettings>).detail
|
const { backgroundBlur, glassQuality } = (event as CustomEvent<TransparencySettings>).detail
|
||||||
|
|
||||||
@@ -143,6 +143,7 @@ function updateHtmlThemeAttribute(themeName: string) {
|
|||||||
syncRootLaunchPalette()
|
syncRootLaunchPalette()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从本地存储重新同步主题偏好、DOM 主题属性和相关外观配置。
|
||||||
function syncThemePreferenceFromStorage() {
|
function syncThemePreferenceFromStorage() {
|
||||||
themeValue = localStorage.getItem('theme') || 'auto'
|
themeValue = localStorage.getItem('theme') || 'auto'
|
||||||
|
|
||||||
@@ -166,22 +167,26 @@ function syncThemePreferenceFromStorage() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 系统配色变化时,在自动主题模式下刷新当前实际主题。
|
||||||
function handleSystemThemeChange() {
|
function handleSystemThemeChange() {
|
||||||
if ((localStorage.getItem('theme') || 'auto') === 'auto') {
|
if ((localStorage.getItem('theme') || 'auto') === 'auto') {
|
||||||
syncThemePreferenceFromStorage()
|
syncThemePreferenceFromStorage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 页面重新可见时同步主题,修复后台期间设置被外部修改后的外观漂移。
|
||||||
function handleVisibilityThemeSync() {
|
function handleVisibilityThemeSync() {
|
||||||
if (document.visibilityState === 'visible') {
|
if (document.visibilityState === 'visible') {
|
||||||
syncThemePreferenceFromStorage()
|
syncThemePreferenceFromStorage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 页面从缓存或重新聚焦恢复时刷新主题偏好。
|
||||||
function handlePageShowThemeSync() {
|
function handlePageShowThemeSync() {
|
||||||
syncThemePreferenceFromStorage()
|
syncThemePreferenceFromStorage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清理背景图交叉淡入淡出定时器。
|
||||||
function clearBackgroundCrossfadeTimer() {
|
function clearBackgroundCrossfadeTimer() {
|
||||||
if (backgroundCrossfadeTimer) {
|
if (backgroundCrossfadeTimer) {
|
||||||
window.clearTimeout(backgroundCrossfadeTimer)
|
window.clearTimeout(backgroundCrossfadeTimer)
|
||||||
@@ -189,6 +194,7 @@ function clearBackgroundCrossfadeTimer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重置背景图交叉淡入淡出状态。
|
||||||
function resetBackgroundCrossfade() {
|
function resetBackgroundCrossfade() {
|
||||||
clearBackgroundCrossfadeTimer()
|
clearBackgroundCrossfadeTimer()
|
||||||
previousImageIndex.value = null
|
previousImageIndex.value = null
|
||||||
@@ -256,6 +262,7 @@ function startBackgroundRotation() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 停止登录页或透明主题背景图加载、重试和轮播。
|
||||||
function stopBackgroundLoading() {
|
function stopBackgroundLoading() {
|
||||||
backgroundRequestController?.abort()
|
backgroundRequestController?.abort()
|
||||||
backgroundRequestController = null
|
backgroundRequestController = null
|
||||||
@@ -269,6 +276,7 @@ function stopBackgroundLoading() {
|
|||||||
removeBackgroundTimer('background-rotation')
|
removeBackgroundTimer('background-rotation')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化登录后的全局设置和用户设置状态。
|
||||||
async function initializeAuthenticatedState() {
|
async function initializeAuthenticatedState() {
|
||||||
if (!isLogin.value) return
|
if (!isLogin.value) return
|
||||||
|
|
||||||
@@ -281,6 +289,7 @@ async function initializeAuthenticatedState() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 延迟初始化登录态数据,避开登录成功后的即时路由跳转窗口。
|
||||||
function scheduleAuthenticatedStateInitialization() {
|
function scheduleAuthenticatedStateInitialization() {
|
||||||
if (authenticatedStateTimer) {
|
if (authenticatedStateTimer) {
|
||||||
window.clearTimeout(authenticatedStateTimer)
|
window.clearTimeout(authenticatedStateTimer)
|
||||||
|
|||||||
+3
-13
@@ -8,7 +8,6 @@ import logo from '@images/logo.png'
|
|||||||
import { bufferToBase64Url, base64UrlToUint8Array, urlBase64ToUint8Array } from '@/@core/utils/navigator'
|
import { bufferToBase64Url, base64UrlToUint8Array, urlBase64ToUint8Array } from '@/@core/utils/navigator'
|
||||||
import { SUPPORTED_LOCALES, SupportedLocale } from '@/types/i18n'
|
import { SUPPORTED_LOCALES, SupportedLocale } from '@/types/i18n'
|
||||||
import { getCurrentLocale, setI18nLanguage } from '@/plugins/i18n'
|
import { getCurrentLocale, setI18nLanguage } from '@/plugins/i18n'
|
||||||
import { useTheme } from 'vuetify'
|
|
||||||
import { getNavMenus } from '@/router/i18n-menu'
|
import { getNavMenus } from '@/router/i18n-menu'
|
||||||
import { buildUserPermissionContext, filterMenusByPermission } from '@/utils/permission'
|
import { buildUserPermissionContext, filterMenusByPermission } from '@/utils/permission'
|
||||||
import type { ApiResponse } from '@/api/types'
|
import type { ApiResponse } from '@/api/types'
|
||||||
@@ -65,14 +64,6 @@ const langMenu = ref(false)
|
|||||||
// 当前语言
|
// 当前语言
|
||||||
const currentLocale = ref(getCurrentLocale())
|
const currentLocale = ref(getCurrentLocale())
|
||||||
|
|
||||||
// 当前主题
|
|
||||||
const vuetifyTheme = useTheme()
|
|
||||||
|
|
||||||
// 判断是否为透明主题
|
|
||||||
const isTransparentTheme = computed(() => {
|
|
||||||
return vuetifyTheme.name.value === 'transparent'
|
|
||||||
})
|
|
||||||
|
|
||||||
// 可用的语言列表
|
// 可用的语言列表
|
||||||
const locales = Object.values(SUPPORTED_LOCALES)
|
const locales = Object.values(SUPPORTED_LOCALES)
|
||||||
|
|
||||||
@@ -279,6 +270,7 @@ interface PassKeyFinishResponse {
|
|||||||
wizard: boolean
|
wizard: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 执行 PassKey WebAuthn 认证并返回登录完成信息。
|
||||||
async function authenticateWithPassKey(options: PassKeyAuthOptions = {}): Promise<PassKeyFinishResponse> {
|
async function authenticateWithPassKey(options: PassKeyAuthOptions = {}): Promise<PassKeyFinishResponse> {
|
||||||
const { username, isConditional = false, signal } = options
|
const { username, isConditional = false, signal } = options
|
||||||
|
|
||||||
@@ -734,8 +726,7 @@ onUnmounted(() => {
|
|||||||
<!-- 登录表单 -->
|
<!-- 登录表单 -->
|
||||||
<div v-if="!mfaDialog" class="auth-wrapper d-flex align-center justify-center">
|
<div v-if="!mfaDialog" class="auth-wrapper d-flex align-center justify-center">
|
||||||
<VCard
|
<VCard
|
||||||
class="auth-card login-card pa-7 pa-sm-9 w-full h-full login-card--enter"
|
class="auth-card login-card glass-effect pa-7 pa-sm-9 w-full h-full login-card--enter"
|
||||||
:class="{ 'glass-effect': !isTransparentTheme }"
|
|
||||||
max-width="24rem"
|
max-width="24rem"
|
||||||
flat
|
flat
|
||||||
>
|
>
|
||||||
@@ -997,7 +988,6 @@ onUnmounted(() => {
|
|||||||
z-index: 3;
|
z-index: 3;
|
||||||
border: 1px solid rgba(var(--v-border-color), calc(var(--v-border-opacity) * 0.6));
|
border: 1px solid rgba(var(--v-border-color), calc(var(--v-border-opacity) * 0.6));
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
backdrop-filter: blur(12px) saturate(140%);
|
|
||||||
background: rgba(var(--v-theme-surface), 0.6);
|
background: rgba(var(--v-theme-surface), 0.6);
|
||||||
inset-block-start: calc(env(safe-area-inset-top, 0px) + 16px);
|
inset-block-start: calc(env(safe-area-inset-top, 0px) + 16px);
|
||||||
inset-inline-end: calc(env(safe-area-inset-right, 0px) + 16px);
|
inset-inline-end: calc(env(safe-area-inset-right, 0px) + 16px);
|
||||||
@@ -1047,7 +1037,7 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 非透明主题:磨砂玻璃卡片 */
|
/* 登录卡片自身承载固定磨砂效果,避免跟随透明主题设置变化。 */
|
||||||
.glass-effect {
|
.glass-effect {
|
||||||
backdrop-filter: blur(28px) saturate(170%) !important;
|
backdrop-filter: blur(28px) saturate(170%) !important;
|
||||||
background: rgba(var(--v-theme-surface), 0.75) !important;
|
background: rgba(var(--v-theme-surface), 0.75) !important;
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ export function getNavMenus(t: Composer['t']): NavMenu[] {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('navItems.pluginManager'),
|
title: t('navItems.pluginManager'),
|
||||||
icon: 'mdi-apps',
|
icon: 'mdi-puzzle-outline',
|
||||||
to: '/plugins',
|
to: '/plugins',
|
||||||
header: t('menu.system'),
|
header: t('menu.system'),
|
||||||
admin: true,
|
admin: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user