mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-21 15:43:51 +08:00
feat: add configurable opacity and blur settings for the transparent theme background
This commit is contained in:
32
src/App.vue
32
src/App.vue
@@ -49,6 +49,26 @@ const backgroundImages = ref<string[]>([])
|
||||
const activeImageIndex = ref(0)
|
||||
const isTransparentTheme = computed(() => globalTheme.name.value === 'transparent')
|
||||
|
||||
function getStoredNumber(key: string, fallback: number, min: number, max: number) {
|
||||
const parsed = Number.parseFloat(localStorage.getItem(key) || '')
|
||||
if (!Number.isFinite(parsed)) return fallback
|
||||
|
||||
return Math.min(max, Math.max(min, parsed))
|
||||
}
|
||||
|
||||
function applyTransparentBackgroundSettings() {
|
||||
document.documentElement.style.setProperty(
|
||||
'--transparent-background-poster-opacity',
|
||||
getStoredNumber('transparency-background-poster-opacity', 1, 0, 1).toString(),
|
||||
)
|
||||
document.documentElement.style.setProperty(
|
||||
'--transparent-background-blur',
|
||||
`${getStoredNumber('transparency-background-blur', 16, 0, 30)}px`,
|
||||
)
|
||||
}
|
||||
|
||||
applyTransparentBackgroundSettings()
|
||||
|
||||
// 心跳检测
|
||||
let heartbeatInterval: number | null = null
|
||||
|
||||
@@ -266,7 +286,11 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<div class="app-wrapper">
|
||||
<!-- 透明主题背景 -->
|
||||
<div v-if="backgroundImages.length > 0 && (isTransparentTheme || !isLogin)" class="background-container">
|
||||
<div
|
||||
v-if="backgroundImages.length > 0 && (isTransparentTheme || !isLogin)"
|
||||
class="background-container"
|
||||
:class="{ 'is-transparent-theme': isTransparentTheme && isLogin }"
|
||||
>
|
||||
<div
|
||||
v-for="(imageUrl, index) in backgroundImages"
|
||||
:key="`bg-${index}-${loginStateKey}`"
|
||||
@@ -331,11 +355,15 @@ onUnmounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.background-container.is-transparent-theme .background-image.active {
|
||||
opacity: var(--transparent-background-poster-opacity, 1);
|
||||
}
|
||||
|
||||
/* 全局磨砂层 */
|
||||
.global-blur-layer {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
backdrop-filter: blur(16px);
|
||||
backdrop-filter: blur(var(--transparent-background-blur, 16px));
|
||||
background-color: rgba(128, 128, 128, 30%);
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
|
||||
@@ -58,6 +58,8 @@ const customCSS = ref('')
|
||||
// 透明度相关
|
||||
const transparencyOpacity = ref(parseFloat(localStorage.getItem('transparency-opacity') || '0.3'))
|
||||
const transparencyBlur = ref(parseFloat(localStorage.getItem('transparency-blur') || '10'))
|
||||
const backgroundPosterOpacity = ref(parseFloat(localStorage.getItem('transparency-background-poster-opacity') || '1'))
|
||||
const backgroundBlur = ref(parseFloat(localStorage.getItem('transparency-background-blur') || '16'))
|
||||
const transparencyLevel = ref(localStorage.getItem('transparency-level') || 'medium')
|
||||
const isTransparentTheme = computed(() => currentThemeName.value === 'transparent')
|
||||
const showTransparencyDialog = ref(false)
|
||||
@@ -383,6 +385,15 @@ async function saveCustomCSS() {
|
||||
function applyTransparencySettings() {
|
||||
const root = document.documentElement
|
||||
|
||||
if (!Number.isFinite(backgroundPosterOpacity.value)) {
|
||||
backgroundPosterOpacity.value = 1
|
||||
}
|
||||
backgroundPosterOpacity.value = Math.min(1, Math.max(0, backgroundPosterOpacity.value))
|
||||
if (!Number.isFinite(backgroundBlur.value)) {
|
||||
backgroundBlur.value = 16
|
||||
}
|
||||
backgroundBlur.value = Math.min(30, Math.max(0, backgroundBlur.value))
|
||||
|
||||
// 设置CSS变量
|
||||
root.style.setProperty('--transparent-opacity', transparencyOpacity.value.toString())
|
||||
root.style.setProperty('--transparent-opacity-light', (transparencyOpacity.value * 0.67).toString())
|
||||
@@ -390,10 +401,14 @@ function applyTransparencySettings() {
|
||||
root.style.setProperty('--transparent-blur', `${transparencyBlur.value}px`)
|
||||
root.style.setProperty('--transparent-blur-light', `${transparencyBlur.value * 0.6}px`)
|
||||
root.style.setProperty('--transparent-blur-heavy', `${transparencyBlur.value * 1.6}px`)
|
||||
root.style.setProperty('--transparent-background-poster-opacity', backgroundPosterOpacity.value.toString())
|
||||
root.style.setProperty('--transparent-background-blur', `${backgroundBlur.value}px`)
|
||||
|
||||
// 保存到本地存储
|
||||
localStorage.setItem('transparency-opacity', transparencyOpacity.value.toString())
|
||||
localStorage.setItem('transparency-blur', transparencyBlur.value.toString())
|
||||
localStorage.setItem('transparency-background-poster-opacity', backgroundPosterOpacity.value.toString())
|
||||
localStorage.setItem('transparency-background-blur', backgroundBlur.value.toString())
|
||||
}
|
||||
|
||||
// 调整透明度预设
|
||||
@@ -434,10 +449,22 @@ function onBlurChange() {
|
||||
transparencyLevel.value = ''
|
||||
}
|
||||
|
||||
// 背景海报透明度变化处理
|
||||
function onBackgroundPosterOpacityChange() {
|
||||
applyTransparencySettings()
|
||||
}
|
||||
|
||||
// 背景磨砂变化处理
|
||||
function onBackgroundBlurChange() {
|
||||
applyTransparencySettings()
|
||||
}
|
||||
|
||||
// 重置透明度设置
|
||||
function resetTransparencySettings() {
|
||||
transparencyOpacity.value = 0.3
|
||||
transparencyBlur.value = 10
|
||||
backgroundPosterOpacity.value = 1
|
||||
backgroundBlur.value = 16
|
||||
transparencyLevel.value = 'medium'
|
||||
applyTransparencySettings()
|
||||
}
|
||||
@@ -821,6 +848,38 @@ onUnmounted(() => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 背景海报透明度滑动条 -->
|
||||
<div>
|
||||
<div class="d-flex align-center justify-space-between mb-2">
|
||||
<span class="text-body-2">{{ t('theme.backgroundPosterOpacity') }}</span>
|
||||
<span class="text-caption">{{ Math.round(backgroundPosterOpacity * 100) }}%</span>
|
||||
</div>
|
||||
<VSlider
|
||||
v-model="backgroundPosterOpacity"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
color="primary"
|
||||
@update:model-value="onBackgroundPosterOpacityChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 背景磨砂滑动条 -->
|
||||
<div>
|
||||
<div class="d-flex align-center justify-space-between mb-2">
|
||||
<span class="text-body-2">{{ t('theme.backgroundBlur') }}</span>
|
||||
<span class="text-caption">{{ backgroundBlur }}px</span>
|
||||
</div>
|
||||
<VSlider
|
||||
v-model="backgroundBlur"
|
||||
:min="0"
|
||||
:max="30"
|
||||
:step="1"
|
||||
color="primary"
|
||||
@update:model-value="onBackgroundBlurChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 预设按钮 -->
|
||||
<div>
|
||||
<span class="text-body-2 d-block mb-2">{{ t('common.preset') }}</span>
|
||||
|
||||
@@ -149,6 +149,8 @@ export default {
|
||||
transparencyAdjust: 'Transparency Adjustment',
|
||||
transparencyOpacity: 'Opacity',
|
||||
transparencyBlur: 'Blur',
|
||||
backgroundPosterOpacity: 'Background Opacity',
|
||||
backgroundBlur: 'Background Frosted Blur',
|
||||
transparencyReset: 'Reset',
|
||||
transparencyLow: 'Low Transparency',
|
||||
transparencyMedium: 'Medium Transparency',
|
||||
|
||||
@@ -149,6 +149,8 @@ export default {
|
||||
transparencyAdjust: '透明度调整',
|
||||
transparencyOpacity: '透明度',
|
||||
transparencyBlur: '模糊度',
|
||||
backgroundPosterOpacity: '背景透明度',
|
||||
backgroundBlur: '背景磨砂效果',
|
||||
transparencyReset: '重置',
|
||||
transparencyLow: '低透明度',
|
||||
transparencyMedium: '中等透明度',
|
||||
|
||||
@@ -149,6 +149,8 @@ export default {
|
||||
transparencyAdjust: '透明度調整',
|
||||
transparencyOpacity: '透明度',
|
||||
transparencyBlur: '模糊度',
|
||||
backgroundPosterOpacity: '背景透明度',
|
||||
backgroundBlur: '背景磨砂效果',
|
||||
transparencyReset: '重置',
|
||||
transparencyLow: '低透明度',
|
||||
transparencyMedium: '中等透明度',
|
||||
|
||||
Reference in New Issue
Block a user