mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 23:56:42 +08:00
feat: 添加透明主题支持及背景图片轮换功能
- 在 App.vue 中引入 API 获取背景图片,并实现背景图片的轮换功能。 - 更新主题切换逻辑,支持透明主题,并在主题变化时更新 HTML 属性。 - 在样式中添加透明主题的特定样式,确保各个组件在透明主题下的显示效果。
This commit is contained in:
@@ -195,11 +195,10 @@ onMounted(() => {
|
|||||||
<VIcon :icon="getThemeIcon" />
|
<VIcon :icon="getThemeIcon" />
|
||||||
</IconBtn>
|
</IconBtn>
|
||||||
</template>
|
</template>
|
||||||
<VList class="theme-switcher-list pt-0">
|
<VList class="theme-switcher-list pt-0 overflow-hidden">
|
||||||
<VCardItem class="theme-switcher-header">
|
<VCardItem class="theme-switcher-header">
|
||||||
<VCardTitle class="font-weight-medium text-primary">主题选择</VCardTitle>
|
<VCardTitle class="font-weight-medium text-primary">主题选择</VCardTitle>
|
||||||
</VCardItem>
|
</VCardItem>
|
||||||
|
|
||||||
<div class="theme-switcher-options px-2">
|
<div class="theme-switcher-options px-2">
|
||||||
<VListItem
|
<VListItem
|
||||||
v-for="theme in props.themes"
|
v-for="theme in props.themes"
|
||||||
@@ -271,8 +270,7 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.theme-switcher-options {
|
.theme-switcher-options {
|
||||||
max-block-size: 300px;
|
overflow-y: hidden;
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-option {
|
.theme-option {
|
||||||
|
|||||||
+141
-3
@@ -2,6 +2,7 @@
|
|||||||
import { useTheme } from 'vuetify'
|
import { useTheme } from 'vuetify'
|
||||||
import { checkPrefersColorSchemeIsDark } from '@/@core/utils'
|
import { checkPrefersColorSchemeIsDark } from '@/@core/utils'
|
||||||
import { ensureRenderComplete, removeEl } from './@core/utils/dom'
|
import { ensureRenderComplete, removeEl } from './@core/utils/dom'
|
||||||
|
import api from '@/api'
|
||||||
|
|
||||||
// 生效主题
|
// 生效主题
|
||||||
const { global: globalTheme } = useTheme()
|
const { global: globalTheme } = useTheme()
|
||||||
@@ -9,9 +10,61 @@ let themeValue = localStorage.getItem('theme') || 'light'
|
|||||||
const autoTheme = checkPrefersColorSchemeIsDark() ? 'dark' : 'light'
|
const autoTheme = checkPrefersColorSchemeIsDark() ? 'dark' : 'light'
|
||||||
globalTheme.name.value = themeValue === 'auto' ? autoTheme : themeValue
|
globalTheme.name.value = themeValue === 'auto' ? autoTheme : themeValue
|
||||||
|
|
||||||
|
// 更新data-theme属性以便CSS选择器能正确匹配
|
||||||
|
function updateHtmlThemeAttribute(themeName) {
|
||||||
|
document.documentElement.setAttribute('data-theme', themeName)
|
||||||
|
// 确保body元素也有相同的主题属性,以便更好地选择弹出窗口
|
||||||
|
document.body.setAttribute('data-theme', themeName)
|
||||||
|
}
|
||||||
|
|
||||||
// 显示状态
|
// 显示状态
|
||||||
const show = ref(false)
|
const show = ref(false)
|
||||||
|
|
||||||
|
// 背景图片
|
||||||
|
const backgroundImages = ref<string[]>([])
|
||||||
|
const activeImageIndex = ref(0)
|
||||||
|
const isTransparentTheme = computed(() => globalTheme.name.value === 'transparent')
|
||||||
|
let backgroundRotationTimer: NodeJS.Timeout | null = null
|
||||||
|
|
||||||
|
// 获取背景图片
|
||||||
|
async function fetchBackgroundImages() {
|
||||||
|
try {
|
||||||
|
backgroundImages.value = await api.get('/login/wallpapers')
|
||||||
|
console.log('获取背景图片成功:', backgroundImages.value)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('获取背景图片失败:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始背景图片轮换
|
||||||
|
function startBackgroundRotation() {
|
||||||
|
if (backgroundRotationTimer) clearInterval(backgroundRotationTimer)
|
||||||
|
|
||||||
|
if (backgroundImages.value.length > 1) {
|
||||||
|
backgroundRotationTimer = setInterval(() => {
|
||||||
|
activeImageIndex.value = (activeImageIndex.value + 1) % backgroundImages.value.length
|
||||||
|
}, 10000) // 每10秒切换一次
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听主题变化
|
||||||
|
watch(
|
||||||
|
() => globalTheme.name.value,
|
||||||
|
async newTheme => {
|
||||||
|
// 更新HTML属性
|
||||||
|
updateHtmlThemeAttribute(newTheme)
|
||||||
|
|
||||||
|
if (newTheme === 'transparent' && backgroundImages.value.length === 0) {
|
||||||
|
await fetchBackgroundImages()
|
||||||
|
startBackgroundRotation()
|
||||||
|
} else if (newTheme !== 'transparent' && backgroundRotationTimer) {
|
||||||
|
clearInterval(backgroundRotationTimer)
|
||||||
|
backgroundRotationTimer = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
// ApexCharts 全局配置
|
// ApexCharts 全局配置
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
@@ -43,6 +96,9 @@ if (window.Apex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
// 初始化data-theme属性
|
||||||
|
updateHtmlThemeAttribute(globalTheme.name.value)
|
||||||
|
|
||||||
ensureRenderComplete(() => {
|
ensureRenderComplete(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -56,10 +112,92 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (backgroundRotationTimer) {
|
||||||
|
clearInterval(backgroundRotationTimer)
|
||||||
|
backgroundRotationTimer = null
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VApp v-show="show">
|
<div class="app-wrapper">
|
||||||
<RouterView />
|
<!-- 透明主题背景 -->
|
||||||
</VApp>
|
<template v-if="isTransparentTheme && backgroundImages.length > 0">
|
||||||
|
<div class="background-container">
|
||||||
|
<div
|
||||||
|
v-for="(imageUrl, index) in backgroundImages"
|
||||||
|
:key="index"
|
||||||
|
class="background-image"
|
||||||
|
:class="{ 'active': index === activeImageIndex }"
|
||||||
|
:style="{ backgroundImage: `url(${imageUrl})` }"
|
||||||
|
></div>
|
||||||
|
<!-- 全局磨砂层 -->
|
||||||
|
<div class="global-blur-layer"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<VApp v-show="show" :class="{ 'transparent-app': isTransparentTheme }">
|
||||||
|
<RouterView />
|
||||||
|
</VApp>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
/* 全局样式 */
|
||||||
|
.app-wrapper {
|
||||||
|
position: relative;
|
||||||
|
inline-size: 100%;
|
||||||
|
min-block-size: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.background-container {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
block-size: 100%;
|
||||||
|
inline-size: 100%;
|
||||||
|
inset-block-start: 0;
|
||||||
|
inset-inline-start: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.background-image {
|
||||||
|
position: absolute;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
block-size: 100%;
|
||||||
|
inline-size: 100%;
|
||||||
|
inset-block-start: 0;
|
||||||
|
inset-inline-start: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 1.5s ease;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
background: linear-gradient(rgba(0, 0, 0, 30%) 0%, rgba(0, 0, 0, 60%) 100%);
|
||||||
|
block-size: 100%;
|
||||||
|
content: '';
|
||||||
|
inline-size: 100%;
|
||||||
|
inset-block-start: 0;
|
||||||
|
inset-inline-start: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全局磨砂层 */
|
||||||
|
.global-blur-layer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: rgba(0, 0, 0, 30%);
|
||||||
|
block-size: 100%;
|
||||||
|
inline-size: 100%;
|
||||||
|
inset-block-start: 0;
|
||||||
|
inset-inline-start: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<VDialog max-width="35rem" scrollable>
|
<VDialog max-width="35rem" scrollable>
|
||||||
<VCard>
|
<VCard>
|
||||||
<VCardTitle class="py-3 me-12">
|
<VCardTitle class="py-4 me-12">
|
||||||
<VIcon icon="mdi-download" class="me-2" />
|
<VIcon icon="mdi-download" class="me-2" />
|
||||||
<span v-if="title">{{ torrent?.site_name }} - {{ title }}</span>
|
<span v-if="title">{{ torrent?.site_name }} - {{ title }}</span>
|
||||||
<span v-else>确认下载</span>
|
<span v-else>确认下载</span>
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ onUnmounted(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="tab-header">
|
<div class="tab-header rounded-lg">
|
||||||
<div ref="tabsContainerRef" class="header-tabs" :class="{ 'show-indicator': showTabsScrollIndicator }">
|
<div ref="tabsContainerRef" class="header-tabs" :class="{ 'show-indicator': showTabsScrollIndicator }">
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in items"
|
v-for="(item, index) in items"
|
||||||
@@ -94,7 +94,6 @@ onUnmounted(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
background-color: rgba(var(--v-theme-background), 0.8);
|
|
||||||
border-block-end: 1px solid rgba(var(--v-theme-on-surface), 0.05);
|
border-block-end: 1px solid rgba(var(--v-theme-on-surface), 0.05);
|
||||||
inset-block-start: 0;
|
inset-block-start: 0;
|
||||||
margin-block-end: 16px;
|
margin-block-end: 16px;
|
||||||
@@ -127,7 +126,7 @@ onUnmounted(() => {
|
|||||||
&::after {
|
&::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1; // Ensure it's above the tabs but below other header elements if needed
|
z-index: 1; // Ensure it's above the tabs but below other header elements if needed
|
||||||
background: linear-gradient(to left, rgba(var(--v-theme-background), 1) 30%, transparent);
|
background: linear-gradient(to left, rgba(var(--v-theme-background), 10.3) 30%, transparent);
|
||||||
content: '';
|
content: '';
|
||||||
inline-size: 40px; // Width of the fade effect
|
inline-size: 40px; // Width of the fade effect
|
||||||
inset-block: 0;
|
inset-block: 0;
|
||||||
@@ -136,11 +135,6 @@ onUnmounted(() => {
|
|||||||
pointer-events: none; // Allow interaction with content behind it
|
pointer-events: none; // Allow interaction with content behind it
|
||||||
transition: opacity 0.2s ease-in-out;
|
transition: opacity 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show the indicator when the class is present
|
|
||||||
&.show-indicator::after {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-tab-icon {
|
.header-tab-icon {
|
||||||
|
|||||||
@@ -19,9 +19,14 @@ const themes: ThemeSwitcherTheme[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'purple',
|
name: 'purple',
|
||||||
title: '紫韵幽兰',
|
title: '幻紫',
|
||||||
icon: 'mdi-brightness-4',
|
icon: 'mdi-brightness-4',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'transparent',
|
||||||
|
title: '透明',
|
||||||
|
icon: 'mdi-gradient-vertical',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ onUnmounted(() => {
|
|||||||
</VFadeTransition>
|
</VFadeTransition>
|
||||||
|
|
||||||
<!-- 精简标题栏 -->
|
<!-- 精简标题栏 -->
|
||||||
<VCard v-if="isRefreshed" class="search-header d-flex align-center mb-4">
|
<VCard v-if="isRefreshed" class="search-header d-flex align-center mb-3">
|
||||||
<div class="search-info-container d-flex align-center flex-wrap">
|
<div class="search-info-container d-flex align-center flex-wrap">
|
||||||
<div class="search-title text-primary">资源搜索结果</div>
|
<div class="search-title text-primary">资源搜索结果</div>
|
||||||
<div class="search-tags d-flex flex-wrap">
|
<div class="search-tags d-flex flex-wrap">
|
||||||
@@ -225,7 +225,7 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<!-- 视图切换加载状态 -->
|
<!-- 视图切换加载状态 -->
|
||||||
<VFadeTransition>
|
<VFadeTransition>
|
||||||
<div v-if="isRefreshed && isViewChanging" class="view-changing-container">
|
<div v-if="isRefreshed && isViewChanging" class="view-changing-container rounded-lg">
|
||||||
<div class="view-changing-content">
|
<div class="view-changing-content">
|
||||||
<div class="pulse-loader">
|
<div class="pulse-loader">
|
||||||
<div class="pulse-circle"></div>
|
<div class="pulse-circle"></div>
|
||||||
@@ -327,7 +327,6 @@ onUnmounted(() => {
|
|||||||
/* 精简标题栏样式 */
|
/* 精简标题栏样式 */
|
||||||
.search-header {
|
.search-header {
|
||||||
border: 1px solid rgba(var(--v-theme-on-surface), 0.08);
|
border: 1px solid rgba(var(--v-theme-on-surface), 0.08);
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 5%);
|
|
||||||
padding-block: 12px;
|
padding-block: 12px;
|
||||||
padding-inline: 16px;
|
padding-inline: 16px;
|
||||||
}
|
}
|
||||||
@@ -390,7 +389,6 @@ onUnmounted(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
backdrop-filter: blur(8px);
|
backdrop-filter: blur(8px);
|
||||||
background-color: rgba(var(--v-theme-background), 0.7);
|
|
||||||
inset: 0;
|
inset: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const theme: VuetifyOptions['theme'] = {
|
|||||||
colors: {
|
colors: {
|
||||||
'primary': '#9155FD',
|
'primary': '#9155FD',
|
||||||
'secondary': '#8A8D93',
|
'secondary': '#8A8D93',
|
||||||
'on-secondary': '#fff',
|
'on-secondary': '#FFFFFF',
|
||||||
'success': '#56CA00',
|
'success': '#56CA00',
|
||||||
'info': '#16B1FF',
|
'info': '#16B1FF',
|
||||||
'warning': '#FFB400',
|
'warning': '#FFB400',
|
||||||
@@ -30,12 +30,12 @@ const theme: VuetifyOptions['theme'] = {
|
|||||||
'grey-800': '#424242',
|
'grey-800': '#424242',
|
||||||
'grey-900': '#212121',
|
'grey-900': '#212121',
|
||||||
'perfect-scrollbar-thumb': '#DBDADE',
|
'perfect-scrollbar-thumb': '#DBDADE',
|
||||||
'skin-bordered-background': '#fff',
|
'skin-bordered-background': '#FFFFFF',
|
||||||
'skin-bordered-surface': '#fff',
|
'skin-bordered-surface': '#FFFFFF',
|
||||||
},
|
},
|
||||||
|
|
||||||
variables: {
|
variables: {
|
||||||
'code-color': '#d400ff',
|
'code-color': '#D400FF',
|
||||||
'overlay-scrim-background': '#3A3541',
|
'overlay-scrim-background': '#3A3541',
|
||||||
'overlay-scrim-opacity': 0.5,
|
'overlay-scrim-opacity': 0.5,
|
||||||
'hover-opacity': 0.04,
|
'hover-opacity': 0.04,
|
||||||
@@ -59,7 +59,7 @@ const theme: VuetifyOptions['theme'] = {
|
|||||||
colors: {
|
colors: {
|
||||||
'primary': '#6E66ED',
|
'primary': '#6E66ED',
|
||||||
'secondary': '#8A8D93',
|
'secondary': '#8A8D93',
|
||||||
'on-secondary': '#fff',
|
'on-secondary': '#FFFFFF',
|
||||||
'success': '#56CA00',
|
'success': '#56CA00',
|
||||||
'info': '#16B1FF',
|
'info': '#16B1FF',
|
||||||
'warning': '#FFB400',
|
'warning': '#FFB400',
|
||||||
@@ -109,7 +109,7 @@ const theme: VuetifyOptions['theme'] = {
|
|||||||
colors: {
|
colors: {
|
||||||
'primary': '#9155FD',
|
'primary': '#9155FD',
|
||||||
'secondary': '#8A8D93',
|
'secondary': '#8A8D93',
|
||||||
'on-secondary': '#fff',
|
'on-secondary': '#FFFFFF',
|
||||||
'success': '#56CA00',
|
'success': '#56CA00',
|
||||||
'info': '#16B1FF',
|
'info': '#16B1FF',
|
||||||
'warning': '#FFB400',
|
'warning': '#FFB400',
|
||||||
@@ -155,6 +155,61 @@ const theme: VuetifyOptions['theme'] = {
|
|||||||
'shadow-key-ambient-opacity': 'rgba(20, 18, 33, 0.04)',
|
'shadow-key-ambient-opacity': 'rgba(20, 18, 33, 0.04)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
transparent: {
|
||||||
|
dark: true,
|
||||||
|
colors: {
|
||||||
|
'primary': '#A370F7',
|
||||||
|
'secondary': '#B794FF',
|
||||||
|
'on-secondary': '#FFFFFF',
|
||||||
|
'success': '#66BB6A',
|
||||||
|
'info': '#42A5F5',
|
||||||
|
'warning': '#FFA726',
|
||||||
|
'error': '#EF5350',
|
||||||
|
'on-primary': '#FFFFFF',
|
||||||
|
'on-success': '#FFFFFF',
|
||||||
|
'on-warning': '#FFFFFF',
|
||||||
|
'background': '#000000',
|
||||||
|
'on-background': '#E7E3FC',
|
||||||
|
'surface': 'rgba(30, 30, 30, 0.3)',
|
||||||
|
'on-surface': '#E7E3FC',
|
||||||
|
'surface-variant': 'rgba(30, 30, 30, 0.2)',
|
||||||
|
'on-surface-variant': 'rgba(255, 255, 255, 0.65)',
|
||||||
|
'grey-50': 'rgba(42, 46, 66, 0.15)',
|
||||||
|
'grey-100': 'rgba(71, 67, 96, 0.15)',
|
||||||
|
'grey-200': 'rgba(74, 80, 114, 0.15)',
|
||||||
|
'grey-300': 'rgba(94, 102, 146, 0.15)',
|
||||||
|
'grey-400': 'rgba(121, 131, 187, 0.15)',
|
||||||
|
'grey-500': 'rgba(134, 146, 208, 0.15)',
|
||||||
|
'grey-600': 'rgba(170, 179, 222, 0.15)',
|
||||||
|
'grey-700': 'rgba(182, 190, 227, 0.15)',
|
||||||
|
'grey-800': 'rgba(207, 211, 236, 0.15)',
|
||||||
|
'grey-900': 'rgba(231, 233, 246, 0.15)',
|
||||||
|
'perfect-scrollbar-thumb': 'rgba(158, 158, 190, 0.4)',
|
||||||
|
'skin-bordered-background': 'rgba(30, 30, 30, 0.3)',
|
||||||
|
'skin-bordered-surface': 'rgba(30, 30, 30, 0.3)',
|
||||||
|
'card-background': 'rgba(30, 30, 30, 0.3)',
|
||||||
|
},
|
||||||
|
variables: {
|
||||||
|
'code-color': '#6D9EEB',
|
||||||
|
'overlay-scrim-background': '0, 0, 0',
|
||||||
|
'overlay-scrim-opacity': 0.7,
|
||||||
|
'hover-opacity': 0.1,
|
||||||
|
'focus-opacity': 0.15,
|
||||||
|
'selected-opacity': 0.2,
|
||||||
|
'activated-opacity': 0.15,
|
||||||
|
'pressed-opacity': 0.2,
|
||||||
|
'dragged-opacity': 0.15,
|
||||||
|
'border-color': '#E7E3FC',
|
||||||
|
'table-header-background': 'rgba(30, 30, 30, 0.3)',
|
||||||
|
'custom-background': 'rgba(30, 30, 30, 0.3)',
|
||||||
|
'card-background': 'rgba(30, 30, 30, 0.3)',
|
||||||
|
|
||||||
|
// Shadows
|
||||||
|
'shadow-key-umbra-opacity': 'rgba(0, 0, 0, 0.07)',
|
||||||
|
'shadow-key-penumbra-opacity': 'rgba(0, 0, 0, 0.1)',
|
||||||
|
'shadow-key-ambient-opacity': 'rgba(0, 0, 0, 0.05)',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+89
-8
@@ -11,6 +11,7 @@ html.v-overlay-scroll-blocked {
|
|||||||
@media (width <= 768px){
|
@media (width <= 768px){
|
||||||
html.v-overlay-scroll-blocked {
|
html.v-overlay-scroll-blocked {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
--v-body-scroll-y: 0px !important;
|
--v-body-scroll-y: 0px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,8 +252,6 @@ html.v-overlay-scroll-blocked {
|
|||||||
|
|
||||||
.card-cover-blurred::before {
|
.card-cover-blurred::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
/* stylelint-disable-next-line property-no-vendor-prefix */
|
|
||||||
-webkit-backdrop-filter: blur(2px);
|
|
||||||
backdrop-filter: blur(2px);
|
backdrop-filter: blur(2px);
|
||||||
background: rgba(29, 39, 59, 48%);
|
background: rgba(29, 39, 59, 48%);
|
||||||
content: '';
|
content: '';
|
||||||
@@ -260,21 +259,15 @@ html.v-overlay-scroll-blocked {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.v-overlay__content .v-list{
|
.v-overlay__content .v-list{
|
||||||
/* stylelint-disable-next-line property-no-vendor-prefix */
|
|
||||||
-webkit-backdrop-filter: blur(6px);
|
|
||||||
backdrop-filter: blur(6px);
|
backdrop-filter: blur(6px);
|
||||||
background-color: rgb(var(--v-theme-surface), 0.9) !important;
|
background-color: rgb(var(--v-theme-surface), 0.9) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.v-overlay__content .v-card:not(.bg-primary){
|
.v-overlay__content .v-card:not(.bg-primary){
|
||||||
/* stylelint-disable-next-line property-no-vendor-prefix */
|
|
||||||
-webkit-backdrop-filter: blur(8px);
|
|
||||||
backdrop-filter: blur(8px);
|
backdrop-filter: blur(8px);
|
||||||
background-color: rgb(var(--v-theme-surface), 0.95) !important;
|
background-color: rgb(var(--v-theme-surface), 0.95) !important;
|
||||||
|
|
||||||
.v-list, .v-table {
|
.v-list, .v-table {
|
||||||
/* stylelint-disable-next-line property-no-vendor-prefix */
|
|
||||||
-webkit-backdrop-filter: none;
|
|
||||||
backdrop-filter: none;
|
backdrop-filter: none;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
}
|
}
|
||||||
@@ -322,3 +315,91 @@ html.v-overlay-scroll-blocked {
|
|||||||
.v-infinite-scroll__side {
|
.v-infinite-scroll__side {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 透明主题特殊样式
|
||||||
|
.transparent-app {
|
||||||
|
// 先将所有全局组件定义放在前面,避免CSS优先级问题
|
||||||
|
.v-application, .v-layout, .v-main, .layout-page-content {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 侧边导航栏
|
||||||
|
.layout-vertical-nav {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: rgba(var(--v-theme-surface), 0.5);
|
||||||
|
border-inline-end: 1px solid rgba(255, 255, 255, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导航栏
|
||||||
|
.navbar-blur::after {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片
|
||||||
|
.v-card:not(.no-blur) {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: rgba(var(--v-theme-surface), 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 列表
|
||||||
|
.v-list {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: rgba(var(--v-theme-surface), 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工具栏
|
||||||
|
.v-toolbar {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: rgba(var(--v-theme-surface), 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表格
|
||||||
|
.v-table {
|
||||||
|
background-color: rgba(var(--v-theme-surface), 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页脚
|
||||||
|
.v-footer {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: rgba(var(--v-theme-surface), 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面容器
|
||||||
|
.layout-content-wrapper {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 无内容区域的背景设为透明
|
||||||
|
.page-content-container {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对话框和菜单蒙层样式
|
||||||
|
.v-overlay__scrim {
|
||||||
|
background: rgba(var(--v-overlay-scrim-background), var(--v-overlay-scrim-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 折叠面板
|
||||||
|
.v-expansion-panel {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: rgba(var(--v-theme-surface), 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 透明主题下的弹出窗口样式
|
||||||
|
html[data-theme="transparent"] {
|
||||||
|
.v-overlay__content {
|
||||||
|
backdrop-filter: blur(10px) !important;
|
||||||
|
|
||||||
|
.v-card:not(.bg-primary) {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: rgb(var(--v-theme-surface), 0.5) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-list {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: rgb(var(--v-theme-surface), 0.5) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { isNullOrEmptyObject } from '@/@core/utils'
|
|||||||
import { useUserStore } from '@/stores'
|
import { useUserStore } from '@/stores'
|
||||||
import SubscribeEditDialog from '@/components/dialog/SubscribeEditDialog.vue'
|
import SubscribeEditDialog from '@/components/dialog/SubscribeEditDialog.vue'
|
||||||
import SearchSiteDialog from '@/components/dialog/SearchSiteDialog.vue'
|
import SearchSiteDialog from '@/components/dialog/SearchSiteDialog.vue'
|
||||||
|
import { useTheme } from 'vuetify'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const mediaProps = defineProps({
|
const mediaProps = defineProps({
|
||||||
@@ -30,6 +31,9 @@ const userStore = useUserStore()
|
|||||||
// 提示框
|
// 提示框
|
||||||
const $toast = useToast()
|
const $toast = useToast()
|
||||||
|
|
||||||
|
// 获取主题信息
|
||||||
|
const theme = useTheme()
|
||||||
|
|
||||||
// 媒体详情
|
// 媒体详情
|
||||||
const mediaDetail = ref<MediaInfo>({} as MediaInfo)
|
const mediaDetail = ref<MediaInfo>({} as MediaInfo)
|
||||||
|
|
||||||
@@ -72,6 +76,11 @@ const searchType = ref('title')
|
|||||||
// 选择站点对话框
|
// 选择站点对话框
|
||||||
const chooseSiteDialog = ref(false)
|
const chooseSiteDialog = ref(false)
|
||||||
|
|
||||||
|
// 计算主题是否为透明
|
||||||
|
const isNonTransparentTheme = computed(() => {
|
||||||
|
return theme.name.value !== 'transparent'
|
||||||
|
})
|
||||||
|
|
||||||
// 查询所有站点
|
// 查询所有站点
|
||||||
async function querySites() {
|
async function querySites() {
|
||||||
try {
|
try {
|
||||||
@@ -519,7 +528,7 @@ onBeforeMount(() => {
|
|||||||
<template>
|
<template>
|
||||||
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
||||||
<div v-if="mediaDetail.tmdb_id || mediaDetail.douban_id || mediaDetail.bangumi_id" class="max-w-8xl mx-auto px-4">
|
<div v-if="mediaDetail.tmdb_id || mediaDetail.douban_id || mediaDetail.bangumi_id" class="max-w-8xl mx-auto px-4">
|
||||||
<template v-if="getBackdropUrl || getPosterUrl">
|
<template v-if="(getBackdropUrl || getPosterUrl) && isNonTransparentTheme">
|
||||||
<div class="vue-media-back absolute left-0 top-0 w-full h-96">
|
<div class="vue-media-back absolute left-0 top-0 w-full h-96">
|
||||||
<VImg class="h-96" position="top" :src="getBackdropUrl || getPosterUrl" cover />
|
<VImg class="h-96" position="top" :src="getBackdropUrl || getPosterUrl" cover />
|
||||||
</div>
|
</div>
|
||||||
@@ -972,7 +981,6 @@ onBeforeMount(() => {
|
|||||||
),
|
),
|
||||||
linear-gradient(90deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%),
|
linear-gradient(90deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%),
|
||||||
linear-gradient(270deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%);
|
linear-gradient(270deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%);
|
||||||
box-shadow: 0 0 0 2px rgb(var(--v-theme-background));
|
|
||||||
margin-block-start: calc(-70px - env(safe-area-inset-top));
|
margin-block-start: calc(-70px - env(safe-area-inset-top));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ function loadMore({ done }: { done: any }) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="search-header d-none d-sm-flex">
|
<div class="search-header d-none d-sm-flex mb-3">
|
||||||
<!-- 页面头部和筛选栏 -->
|
<!-- 页面头部和筛选栏 -->
|
||||||
<VCard class="view-header rounded-xl">
|
<VCard class="view-header rounded-xl">
|
||||||
<div class="d-flex align-center flex-wrap pa-3">
|
<div class="d-flex align-center flex-wrap pa-3">
|
||||||
@@ -499,7 +499,7 @@ function loadMore({ done }: { done: any }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 移动端头部和筛选区域 -->
|
<!-- 移动端头部和筛选区域 -->
|
||||||
<VCard class="d-block d-sm-none search-header-mobile">
|
<VCard class="d-block d-sm-none search-header-mobile mb-3">
|
||||||
<!-- 移动端头部 -->
|
<!-- 移动端头部 -->
|
||||||
<div class="view-header">
|
<div class="view-header">
|
||||||
<div class="d-flex align-center flex-wrap pa-2">
|
<div class="d-flex align-center flex-wrap pa-2">
|
||||||
@@ -617,7 +617,6 @@ function loadMore({ done }: { done: any }) {
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
background-color: rgba(var(--v-theme-background), 0.95);
|
|
||||||
inset-block-start: 0;
|
inset-block-start: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ onMounted(() => {
|
|||||||
mode="intersect"
|
mode="intersect"
|
||||||
side="end"
|
side="end"
|
||||||
:items="displayDataList"
|
:items="displayDataList"
|
||||||
class="resource-list"
|
class="resource-list overflow-hidden"
|
||||||
@load="loadMore"
|
@load="loadMore"
|
||||||
>
|
>
|
||||||
<template #loading />
|
<template #loading />
|
||||||
@@ -607,7 +607,6 @@ onMounted(() => {
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
background-color: rgba(var(--v-theme-background), 0.95);
|
|
||||||
inset-block-start: 0;
|
inset-block-start: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,7 +614,6 @@ onMounted(() => {
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
background-color: rgba(var(--v-theme-background), 0.95);
|
|
||||||
inset-block-start: 0;
|
inset-block-start: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user