feat(display): background photo groups with blurred, compressed and original versions; veil, sway and blur options in the appearance panel [CI]
ci/woodpecker/push/main-amd64-build Pipeline was successful
ci/woodpecker/push/main-amd64-build Pipeline was successful
This commit is contained in:
1 parent
725fe17a7d
commit
044ce0c339
34 files changed
+255
-33
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useSyncExternalStore } from 'react'
|
||||
import { backgroundUrl, DEFAULT_PHOTO, PHOTOS } from './backgrounds'
|
||||
|
||||
/**
|
||||
* 展示页右下角「外观」里能调的参数:都是相对默认值的倍数(1 = 原样),存在浏览器里。
|
||||
@@ -23,10 +24,20 @@ export interface AppearanceSettings {
|
||||
bullet: boolean
|
||||
/** 鼠标拨动雪。 */
|
||||
mouse: boolean
|
||||
/** 背景在预先模糊的基础上再模糊多少(像素,0 是不再模糊)。 */
|
||||
/** 用哪张照片(id,见 backgrounds.ts)。 */
|
||||
photo: string
|
||||
/** 背景模糊:开是随主题的两张预先模糊过的图,关是不模糊的图(两张,也是随主题)。 */
|
||||
bgBlurred: boolean
|
||||
/** 背景模糊关着的时候:开是加载没压缩的原图(PNG,近 2MB 一张),关是压缩过的(JPG,不到 300KB)。 */
|
||||
bgOriginal: boolean
|
||||
/** 背景模糊开着的时候,在预先模糊的基础上再模糊多少(像素,0 是不再模糊)。 */
|
||||
bgBlur: number
|
||||
/** 背景跟着鼠标晃动的幅度(0 是不动,1 是默认)。 */
|
||||
/** 背景跟着鼠标晃动:总开关,关了背景就完全不动。 */
|
||||
sway: boolean
|
||||
/** 背景跟着鼠标晃动的幅度(1 是默认)。 */
|
||||
parallax: number
|
||||
/** 盖在背景图上的那层遮罩(亮色是白、暗色是灰)的浓度:0 是不盖,1 是默认(亮色 50%、暗色 62%)。 */
|
||||
bgVeil: number
|
||||
}
|
||||
|
||||
export const APPEARANCE_DEFAULTS: AppearanceSettings = {
|
||||
@@ -39,8 +50,13 @@ export const APPEARANCE_DEFAULTS: AppearanceSettings = {
|
||||
opacity: 1,
|
||||
bullet: true,
|
||||
mouse: true,
|
||||
photo: DEFAULT_PHOTO,
|
||||
bgBlurred: true,
|
||||
bgOriginal: false,
|
||||
bgBlur: 0,
|
||||
sway: true,
|
||||
parallax: 1,
|
||||
bgVeil: 1,
|
||||
}
|
||||
|
||||
/** 每个滑块的范围(和 AppearanceSettings 里同名的数值项对应)。 */
|
||||
@@ -53,6 +69,7 @@ export const APPEARANCE_RANGES = {
|
||||
opacity: { min: 0.2, max: 2.5, step: 0.05 },
|
||||
bgBlur: { min: 0, max: 30, step: 1 },
|
||||
parallax: { min: 0, max: 1.5, step: 0.05 },
|
||||
bgVeil: { min: 0, max: 1.6, step: 0.05 },
|
||||
} as const
|
||||
|
||||
const KEY = 'moshiro.appearance'
|
||||
@@ -64,7 +81,10 @@ function load(): AppearanceSettings {
|
||||
const merged: Record<string, unknown> = { ...APPEARANCE_DEFAULTS }
|
||||
for (const name of Object.keys(APPEARANCE_DEFAULTS) as (keyof AppearanceSettings)[]) {
|
||||
const value = saved[name]
|
||||
if (typeof value === typeof APPEARANCE_DEFAULTS[name]) merged[name] = value
|
||||
if (typeof value !== typeof APPEARANCE_DEFAULTS[name]) continue
|
||||
// 照片只认列表里有的,图删了、改名了就回到默认
|
||||
if (name === 'photo' && !PHOTOS.some((photo) => photo.id === value)) continue
|
||||
merged[name] = value
|
||||
}
|
||||
return merged as unknown as AppearanceSettings
|
||||
} catch {
|
||||
@@ -96,14 +116,28 @@ export function subscribeAppearance(listener: () => void): () => void {
|
||||
|
||||
export const useAppearance = () => useSyncExternalStore(subscribeAppearance, getAppearance)
|
||||
|
||||
/** 把背景的额外模糊写进 <html> 的 --bg-filter(display.css 里 .bg-layer 用它;不模糊的时候是 none,不给浏览器多一层滤镜)。 */
|
||||
/**
|
||||
* 把当前该用的背景图写进 <html> 的 --bg-image(照片、主题、背景模糊、不压缩一起决定用哪个版本;display.css 里 .bg-layer 用它),
|
||||
* 把遮罩的浓度写进 --bg-veil-scale,把背景的额外模糊写进 --bg-filter(不模糊的时候是 none,不给浏览器多一层滤镜),
|
||||
* 把晃动的开关写进 data-sway(关了就按窗口的原始比例铺满,display.css 里 data-sway='off')。切换主题时也重新算。
|
||||
*/
|
||||
export function useAppearanceVars() {
|
||||
useEffect(() => {
|
||||
const root = document.documentElement
|
||||
const apply = () => {
|
||||
const blur = getAppearance().bgBlur
|
||||
document.documentElement.style.setProperty('--bg-filter', blur > 0 ? `blur(${blur}px)` : 'none')
|
||||
const { bgBlur, bgBlurred, bgOriginal, photo, bgVeil, sway } = getAppearance()
|
||||
root.style.setProperty('--bg-veil-scale', String(bgVeil))
|
||||
root.style.setProperty('--bg-filter', bgBlurred && bgBlur > 0 ? `blur(${bgBlur}px)` : 'none')
|
||||
root.style.setProperty('--bg-image', `url("${backgroundUrl(photo, root.dataset.theme === 'dark', bgBlurred, bgOriginal)}")`)
|
||||
root.dataset.sway = sway ? 'on' : 'off'
|
||||
}
|
||||
apply()
|
||||
return subscribeAppearance(apply)
|
||||
const observer = new MutationObserver(apply)
|
||||
observer.observe(root, { attributes: true, attributeFilter: ['data-theme'] })
|
||||
const unsubscribe = subscribeAppearance(apply)
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
unsubscribe()
|
||||
}
|
||||
}, [])
|
||||
}
|
||||
Reference in new issue
Block a user