Add monochrome theme with grayscale filter (#4541)

This commit is contained in:
Zenith Rifle 2026-01-04 21:32:51 +08:00 committed by GitHub
parent 10fa9f6d17
commit 46b6ae53bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 186 additions and 39 deletions

View file

@ -14,10 +14,12 @@
* limitations under the License.
*/
import { catppuccinTheme } from './catppuccin'
import { monochromeTheme } from './monochrome'
import type { ThemeRegistry } from '../types'
export const themeRegistry: ThemeRegistry = {
catppuccin: catppuccinTheme,
monochrome: monochromeTheme,
}
export { catppuccinTheme }
export { catppuccinTheme, monochromeTheme }

View file

@ -0,0 +1,151 @@
import type { Theme } from '../types'
export const monochromeTheme: Theme = {
name: 'monochrome',
displayName: 'Monochrome',
preview: '#808080',
modes: {
light: {
brand: {
1: '#000000',
2: '#1a1a1a',
3: '#333333',
soft: '#666666'
},
bg: '#FFFFFF',
bgAlt: '#F5F5F5',
bgElv: 'rgba(255, 255, 255, 0.95)',
bgMark: '#E0E0E0',
text: {
1: '#000000',
2: '#333333',
3: '#808080'
},
button: {
brand: {
bg: '#000000',
border: '#000000',
text: '#FFFFFF',
hoverBorder: '#333333',
hoverText: '#FFFFFF',
hoverBg: '#333333',
activeBorder: '#000000',
activeText: '#FFFFFF',
activeBg: '#000000'
},
alt: {
bg: '#808080',
text: '#FFFFFF',
hoverBg: '#666666',
hoverText: '#FFFFFF'
}
},
customBlock: {
info: {
bg: '#F5F5F5',
border: '#000000',
text: '#000000',
textDeep: '#000000'
},
tip: {
bg: '#F5F5F5',
border: '#333333',
text: '#1a1a1a',
textDeep: '#000000'
},
warning: {
bg: '#F5F5F5',
border: '#666666',
text: '#333333',
textDeep: '#1a1a1a'
},
danger: {
bg: '#F5F5F5',
border: '#000000',
text: '#000000',
textDeep: '#000000'
}
},
selection: {
bg: '#CCCCCC'
},
home: {
heroNameColor: '#000000',
heroNameBackground: '#FFFFFF',
heroImageBackground: 'linear-gradient(135deg, #E0E0E0 0%, #FFFFFF 100%)',
heroImageFilter: 'blur(44px)'
}
},
dark: {
brand: {
1: '#FFFFFF',
2: '#E0E0E0',
3: '#CCCCCC',
soft: '#999999'
},
bg: '#000000',
bgAlt: '#0A0A0A',
bgElv: 'rgba(0, 0, 0, 0.95)',
bgMark: '#1A1A1A',
text: {
1: '#FFFFFF',
2: '#CCCCCC',
3: '#808080'
},
button: {
brand: {
bg: '#FFFFFF',
border: '#FFFFFF',
text: '#000000',
hoverBorder: '#CCCCCC',
hoverText: '#000000',
hoverBg: '#CCCCCC',
activeBorder: '#FFFFFF',
activeText: '#000000',
activeBg: '#FFFFFF'
},
alt: {
bg: '#808080',
text: '#000000',
hoverBg: '#999999',
hoverText: '#000000'
}
},
customBlock: {
info: {
bg: '#1A1A1A',
border: '#FFFFFF',
text: '#FFFFFF',
textDeep: '#FFFFFF'
},
tip: {
bg: '#1A1A1A',
border: '#CCCCCC',
text: '#E0E0E0',
textDeep: '#FFFFFF'
},
warning: {
bg: '#1A1A1A',
border: '#999999',
text: '#CCCCCC',
textDeep: '#E0E0E0'
},
danger: {
bg: '#1A1A1A',
border: '#FFFFFF',
text: '#FFFFFF',
textDeep: '#FFFFFF'
}
},
selection: {
bg: '#333333'
},
home: {
heroNameColor: '#FFFFFF',
heroNameBackground: '#000000',
heroImageBackground: 'linear-gradient(135deg, #1A1A1A 0%, #000000 100%)',
heroImageFilter: 'blur(44px)'
}
}
}
}

View file

@ -66,8 +66,8 @@ export class ThemeHandler {
if (!localStorage.getItem(STORAGE_KEY_MODE)) {
this.state.value.currentMode = e.matches ? 'dark' : 'light'
this.applyTheme()
}
else {
}
else {
this.applyTheme()
}
})
@ -95,17 +95,23 @@ export class ThemeHandler {
this.applyDOMClasses(currentMode)
this.applyCSSVariables(modeColors, theme)
if (theme.name === 'monochrome') {
root.classList.add('monochrome')
} else {
root.classList.remove('monochrome')
}
}
private applyDOMClasses(mode: DisplayMode) {
const root = document.documentElement
// Remove all mode classes
root.classList.remove('dark', 'light', 'amoled')
// Add current mode class
root.classList.add(mode)
// Add amoled class if enabled in dark mode
if (mode === 'dark' && this.amoledEnabled.value) {
root.classList.add('amoled')
@ -127,7 +133,7 @@ export class ThemeHandler {
let bgColor = colors.bg
let bgAltColor = colors.bgAlt
let bgElvColor = colors.bgElv
if (this.state.value.currentMode === 'dark' && this.amoledEnabled.value) {
bgColor = '#000000'
bgAltColor = '#000000'
@ -170,20 +176,6 @@ export class ThemeHandler {
root.style.removeProperty('--vp-c-text-3')
}
// Debug: log applied text color variables so we can inspect in console
try {
// eslint-disable-next-line no-console
console.log('[ThemeHandler] applied text vars', {
theme: theme.name,
mode: this.state.value.currentMode,
vp_text_1: root.style.getPropertyValue('--vp-c-text-1'),
vp_text_2: root.style.getPropertyValue('--vp-c-text-2'),
vp_text_3: root.style.getPropertyValue('--vp-c-text-3')
})
} catch (e) {
// ignore
}
// Apply button colors
root.style.setProperty('--vp-button-brand-bg', colors.button.brand.bg)
root.style.setProperty('--vp-button-brand-border', colors.button.brand.border)
@ -284,7 +276,7 @@ export class ThemeHandler {
this.state.value.theme = themeRegistry[themeName]
localStorage.setItem(STORAGE_KEY_THEME, themeName)
this.applyTheme()
// Force re-apply ColorPicker colors if theme doesn't specify brand colors
this.ensureColorPickerColors()
}
@ -297,10 +289,10 @@ export class ThemeHandler {
public toggleMode() {
const currentMode = this.state.value.currentMode
// Toggle between light and dark
const newMode: DisplayMode = currentMode === 'light' ? 'dark' : 'light'
this.setMode(newMode)
}