theme
This commit is contained in:
@@ -195,6 +195,12 @@ const Sidebar = ({
|
|||||||
neutralHue,
|
neutralHue,
|
||||||
setNeutralHue,
|
setNeutralHue,
|
||||||
resetNeutralHue,
|
resetNeutralHue,
|
||||||
|
neutralChroma,
|
||||||
|
setNeutralChroma,
|
||||||
|
resetNeutralChroma,
|
||||||
|
neutralContrast,
|
||||||
|
setNeutralContrast,
|
||||||
|
resetNeutralContrast,
|
||||||
themeMode,
|
themeMode,
|
||||||
cycleThemeMode,
|
cycleThemeMode,
|
||||||
themeModes,
|
themeModes,
|
||||||
@@ -204,6 +210,8 @@ const Sidebar = ({
|
|||||||
setCollapsed(true);
|
setCollapsed(true);
|
||||||
}, [setCollapsed]);
|
}, [setCollapsed]);
|
||||||
const neutralHueInputId = useId();
|
const neutralHueInputId = useId();
|
||||||
|
const neutralChromaInputId = useId();
|
||||||
|
const neutralContrastInputId = useId();
|
||||||
const sortedCorrespondents = useMemo(() => {
|
const sortedCorrespondents = useMemo(() => {
|
||||||
if (!Array.isArray(correspondents)) {
|
if (!Array.isArray(correspondents)) {
|
||||||
return [];
|
return [];
|
||||||
@@ -281,9 +289,11 @@ const Sidebar = ({
|
|||||||
[onUploadFiles, selectedFolder],
|
[onUploadFiles, selectedFolder],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleNeutralHueReset = useCallback(() => {
|
const handleThemeAdjustmentsReset = useCallback(() => {
|
||||||
resetNeutralHue();
|
resetNeutralHue();
|
||||||
}, [resetNeutralHue]);
|
resetNeutralChroma();
|
||||||
|
resetNeutralContrast();
|
||||||
|
}, [resetNeutralHue, resetNeutralChroma, resetNeutralContrast]);
|
||||||
|
|
||||||
const handleNeutralHueChange = useCallback(
|
const handleNeutralHueChange = useCallback(
|
||||||
(value) => {
|
(value) => {
|
||||||
@@ -300,6 +310,44 @@ const Sidebar = ({
|
|||||||
[resetNeutralHue, setNeutralHue],
|
[resetNeutralHue, setNeutralHue],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleNeutralChromaChange = useCallback(
|
||||||
|
(value) => {
|
||||||
|
if (value === '') {
|
||||||
|
resetNeutralChroma();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const parsed = Number(value);
|
||||||
|
if (Number.isNaN(parsed)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setNeutralChroma(parsed);
|
||||||
|
},
|
||||||
|
[resetNeutralChroma, setNeutralChroma],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleNeutralContrastChange = useCallback(
|
||||||
|
(value) => {
|
||||||
|
if (value === '') {
|
||||||
|
resetNeutralContrast();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const parsed = Number(value);
|
||||||
|
if (Number.isNaN(parsed)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setNeutralContrast(parsed);
|
||||||
|
},
|
||||||
|
[resetNeutralContrast, setNeutralContrast],
|
||||||
|
);
|
||||||
|
|
||||||
|
const formatSliderValue = useCallback((value) => {
|
||||||
|
const parsed = Number(value);
|
||||||
|
if (Number.isNaN(parsed)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return parsed.toFixed(2);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const themeModeList = themeModes && themeModes.length ? themeModes : THEME_MODES;
|
const themeModeList = themeModes && themeModes.length ? themeModes : THEME_MODES;
|
||||||
const themeModeIndex = themeModeList.indexOf(themeMode);
|
const themeModeIndex = themeModeList.indexOf(themeMode);
|
||||||
const safeThemeModeIndex = themeModeIndex === -1 ? 0 : themeModeIndex;
|
const safeThemeModeIndex = themeModeIndex === -1 ? 0 : themeModeIndex;
|
||||||
@@ -336,9 +384,9 @@ const Sidebar = ({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="icon-button"
|
className="icon-button"
|
||||||
onClick={handleNeutralHueReset}
|
onClick={handleThemeAdjustmentsReset}
|
||||||
aria-label="Reset neutral hue"
|
aria-label="Reset theme adjustments"
|
||||||
title="Reset neutral hue"
|
title="Reset theme adjustments"
|
||||||
>
|
>
|
||||||
<RestoreIcon size={16} />
|
<RestoreIcon size={16} />
|
||||||
</button>
|
</button>
|
||||||
@@ -354,9 +402,38 @@ const Sidebar = ({
|
|||||||
step="1"
|
step="1"
|
||||||
value={neutralHue}
|
value={neutralHue}
|
||||||
onChange={(event) => handleNeutralHueChange(event.target.value)}
|
onChange={(event) => handleNeutralHueChange(event.target.value)}
|
||||||
|
onDoubleClick={resetNeutralHue}
|
||||||
/>
|
/>
|
||||||
<span className="menu__slider-value">{neutralHue}°</span>
|
<span className="menu__slider-value">{neutralHue}°</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label className="menu__slider" htmlFor={neutralChromaInputId}>
|
||||||
|
<span className="menu__slider-label">Chroma</span>
|
||||||
|
<input
|
||||||
|
id={neutralChromaInputId}
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="1"
|
||||||
|
step="0.01"
|
||||||
|
value={neutralChroma}
|
||||||
|
onChange={(event) => handleNeutralChromaChange(event.target.value)}
|
||||||
|
onDoubleClick={resetNeutralChroma}
|
||||||
|
/>
|
||||||
|
<span className="menu__slider-value">{formatSliderValue(neutralChroma)}</span>
|
||||||
|
</label>
|
||||||
|
<label className="menu__slider" htmlFor={neutralContrastInputId}>
|
||||||
|
<span className="menu__slider-label">Contrast</span>
|
||||||
|
<input
|
||||||
|
id={neutralContrastInputId}
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="1"
|
||||||
|
step="0.01"
|
||||||
|
value={neutralContrast}
|
||||||
|
onChange={(event) => handleNeutralContrastChange(event.target.value)}
|
||||||
|
onDoubleClick={resetNeutralContrast}
|
||||||
|
/>
|
||||||
|
<span className="menu__slider-value">{formatSliderValue(neutralContrast)}</span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|||||||
@@ -12,19 +12,29 @@ const SIDEBAR_COLLAPSE_STORAGE_KEY = 'papercrate_sidebar_collapsed';
|
|||||||
const SidebarContext = createContext(null);
|
const SidebarContext = createContext(null);
|
||||||
|
|
||||||
const THEME_STORAGE_KEY = 'papercrate_theme_settings';
|
const THEME_STORAGE_KEY = 'papercrate_theme_settings';
|
||||||
const DEFAULT_NEUTRAL_HUE = 180;
|
const DEFAULT_NEUTRAL_HUE = 145;
|
||||||
|
const DEFAULT_NEUTRAL_CHROMA = 0.15;
|
||||||
|
const DEFAULT_NEUTRAL_CONTRAST = 0.364;
|
||||||
const DEFAULT_THEME_MODE = 'system';
|
const DEFAULT_THEME_MODE = 'system';
|
||||||
const THEME_MODES = ['system', 'light', 'dark'];
|
const THEME_MODES = ['system', 'light', 'dark'];
|
||||||
|
|
||||||
const loadInitialThemeSettings = () => {
|
const loadInitialThemeSettings = () => {
|
||||||
const defaults = { neutralHue: DEFAULT_NEUTRAL_HUE, mode: DEFAULT_THEME_MODE };
|
const defaults = {
|
||||||
|
neutralHue: DEFAULT_NEUTRAL_HUE,
|
||||||
|
neutralChroma: DEFAULT_NEUTRAL_CHROMA,
|
||||||
|
neutralContrast: DEFAULT_NEUTRAL_CONTRAST,
|
||||||
|
mode: DEFAULT_THEME_MODE,
|
||||||
|
};
|
||||||
|
|
||||||
if (typeof window === 'undefined') {
|
if (typeof window === 'undefined') {
|
||||||
if (typeof document !== 'undefined') {
|
if (typeof document !== 'undefined') {
|
||||||
const current = document.documentElement.style.getPropertyValue('--neutral-hue');
|
const root = document.documentElement;
|
||||||
|
const current = root.style.getPropertyValue('--neutral-hue');
|
||||||
const parsed = Number.parseInt(current, 10);
|
const parsed = Number.parseInt(current, 10);
|
||||||
return {
|
return {
|
||||||
neutralHue: Number.isNaN(parsed) ? defaults.neutralHue : parsed,
|
neutralHue: Number.isNaN(parsed) ? defaults.neutralHue : parsed,
|
||||||
|
neutralChroma: defaults.neutralChroma,
|
||||||
|
neutralContrast: defaults.neutralContrast,
|
||||||
mode: defaults.mode,
|
mode: defaults.mode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -32,13 +42,36 @@ const loadInitialThemeSettings = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
|
const readNumberVar = (name, fallback) => {
|
||||||
|
const inlineValue = root.style.getPropertyValue(name);
|
||||||
|
const inlineParsed = Number.parseFloat(inlineValue);
|
||||||
|
if (!Number.isNaN(inlineParsed)) {
|
||||||
|
return inlineParsed;
|
||||||
|
}
|
||||||
|
if (typeof window !== 'undefined' && window.getComputedStyle) {
|
||||||
|
const computedValue = window.getComputedStyle(root).getPropertyValue(name);
|
||||||
|
const computedParsed = Number.parseFloat(computedValue);
|
||||||
|
if (!Number.isNaN(computedParsed)) {
|
||||||
|
return computedParsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
};
|
||||||
|
|
||||||
const loadFromRoot = () => {
|
const loadFromRoot = () => {
|
||||||
const current = root.style.getPropertyValue('--neutral-hue');
|
const current = root.style.getPropertyValue('--neutral-hue');
|
||||||
const parsed = Number.parseInt(current, 10);
|
const parsed = Number.parseInt(current, 10);
|
||||||
return Number.isNaN(parsed) ? defaults.neutralHue : parsed;
|
return {
|
||||||
|
neutralHue: Number.isNaN(parsed) ? defaults.neutralHue : parsed,
|
||||||
|
neutralChroma: readNumberVar('--neutral-chroma', defaults.neutralChroma),
|
||||||
|
neutralContrast: readNumberVar('--neutral-contrast', defaults.neutralContrast),
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
let neutralHueValue = loadFromRoot();
|
const rootValues = loadFromRoot();
|
||||||
|
let neutralHueValue = rootValues.neutralHue;
|
||||||
|
let neutralChromaValue = rootValues.neutralChroma;
|
||||||
|
let neutralContrastValue = rootValues.neutralContrast;
|
||||||
let modeValue = defaults.mode;
|
let modeValue = defaults.mode;
|
||||||
|
|
||||||
const composite = window.localStorage.getItem(THEME_STORAGE_KEY);
|
const composite = window.localStorage.getItem(THEME_STORAGE_KEY);
|
||||||
@@ -49,6 +82,14 @@ const loadInitialThemeSettings = () => {
|
|||||||
if (!Number.isNaN(storedHue)) {
|
if (!Number.isNaN(storedHue)) {
|
||||||
neutralHueValue = storedHue;
|
neutralHueValue = storedHue;
|
||||||
}
|
}
|
||||||
|
const storedChroma = Number.parseFloat(parsed?.neutralChroma);
|
||||||
|
if (!Number.isNaN(storedChroma)) {
|
||||||
|
neutralChromaValue = Math.min(Math.max(storedChroma, 0), 1);
|
||||||
|
}
|
||||||
|
const storedContrast = Number.parseFloat(parsed?.neutralContrast);
|
||||||
|
if (!Number.isNaN(storedContrast)) {
|
||||||
|
neutralContrastValue = Math.min(Math.max(storedContrast, 0), 1);
|
||||||
|
}
|
||||||
const storedMode = parsed?.mode;
|
const storedMode = parsed?.mode;
|
||||||
if (THEME_MODES.includes(storedMode)) {
|
if (THEME_MODES.includes(storedMode)) {
|
||||||
modeValue = storedMode;
|
modeValue = storedMode;
|
||||||
@@ -70,7 +111,12 @@ const loadInitialThemeSettings = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { neutralHue: neutralHueValue, mode: modeValue };
|
return {
|
||||||
|
neutralHue: neutralHueValue,
|
||||||
|
neutralChroma: neutralChromaValue,
|
||||||
|
neutralContrast: neutralContrastValue,
|
||||||
|
mode: modeValue,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadInitialCollapsedState = (defaultValue) => {
|
const loadInitialCollapsedState = (defaultValue) => {
|
||||||
@@ -95,6 +141,8 @@ export const SidebarProvider = ({ initialCollapsed = false, children }) => {
|
|||||||
const [collapsed, setCollapsedState] = useState(() => loadInitialCollapsedState(initialCollapsed));
|
const [collapsed, setCollapsedState] = useState(() => loadInitialCollapsedState(initialCollapsed));
|
||||||
const initialTheme = useMemo(() => loadInitialThemeSettings(), []);
|
const initialTheme = useMemo(() => loadInitialThemeSettings(), []);
|
||||||
const [neutralHue, setNeutralHueState] = useState(initialTheme.neutralHue);
|
const [neutralHue, setNeutralHueState] = useState(initialTheme.neutralHue);
|
||||||
|
const [neutralChroma, setNeutralChromaState] = useState(initialTheme.neutralChroma);
|
||||||
|
const [neutralContrast, setNeutralContrastState] = useState(initialTheme.neutralContrast);
|
||||||
const [themeMode, setThemeModeState] = useState(initialTheme.mode);
|
const [themeMode, setThemeModeState] = useState(initialTheme.mode);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -104,6 +152,20 @@ export const SidebarProvider = ({ initialCollapsed = false, children }) => {
|
|||||||
document.documentElement.style.setProperty('--neutral-hue', `${neutralHue}deg`);
|
document.documentElement.style.setProperty('--neutral-hue', `${neutralHue}deg`);
|
||||||
}, [neutralHue]);
|
}, [neutralHue]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof document === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
document.documentElement.style.setProperty('--neutral-chroma', String(neutralChroma));
|
||||||
|
}, [neutralChroma]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof document === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
document.documentElement.style.setProperty('--neutral-contrast', String(neutralContrast));
|
||||||
|
}, [neutralContrast]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof document === 'undefined') {
|
if (typeof document === 'undefined') {
|
||||||
return;
|
return;
|
||||||
@@ -121,14 +183,19 @@ export const SidebarProvider = ({ initialCollapsed = false, children }) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const payload = JSON.stringify({ neutralHue, mode: themeMode });
|
const payload = JSON.stringify({
|
||||||
|
neutralHue,
|
||||||
|
neutralChroma,
|
||||||
|
neutralContrast,
|
||||||
|
mode: themeMode,
|
||||||
|
});
|
||||||
window.localStorage.setItem(THEME_STORAGE_KEY, payload);
|
window.localStorage.setItem(THEME_STORAGE_KEY, payload);
|
||||||
window.localStorage.removeItem('papercrate_neutral_hue');
|
window.localStorage.removeItem('papercrate_neutral_hue');
|
||||||
window.localStorage.removeItem('papercrate_theme_mode');
|
window.localStorage.removeItem('papercrate_theme_mode');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('[theme] failed to persist theme settings', error);
|
console.warn('[theme] failed to persist theme settings', error);
|
||||||
}
|
}
|
||||||
}, [neutralHue, themeMode]);
|
}, [neutralHue, neutralChroma, neutralContrast, themeMode]);
|
||||||
|
|
||||||
const setNeutralHue = useCallback((value) => {
|
const setNeutralHue = useCallback((value) => {
|
||||||
setNeutralHueState((prev) => {
|
setNeutralHueState((prev) => {
|
||||||
@@ -144,6 +211,42 @@ export const SidebarProvider = ({ initialCollapsed = false, children }) => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const setNeutralChroma = useCallback((value) => {
|
||||||
|
setNeutralChromaState((prev) => {
|
||||||
|
if (value === '' || value === null || typeof value === 'undefined') {
|
||||||
|
return DEFAULT_NEUTRAL_CHROMA;
|
||||||
|
}
|
||||||
|
const parsed = Number(value);
|
||||||
|
if (Number.isNaN(parsed)) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
const clamped = Math.min(Math.max(parsed, 0), 1);
|
||||||
|
return Math.round(clamped * 1000) / 1000;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const resetNeutralChroma = useCallback(() => {
|
||||||
|
setNeutralChromaState(DEFAULT_NEUTRAL_CHROMA);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const setNeutralContrast = useCallback((value) => {
|
||||||
|
setNeutralContrastState((prev) => {
|
||||||
|
if (value === '' || value === null || typeof value === 'undefined') {
|
||||||
|
return DEFAULT_NEUTRAL_CONTRAST;
|
||||||
|
}
|
||||||
|
const parsed = Number(value);
|
||||||
|
if (Number.isNaN(parsed)) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
const clamped = Math.min(Math.max(parsed, 0), 1);
|
||||||
|
return Math.round(clamped * 1000) / 1000;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const resetNeutralContrast = useCallback(() => {
|
||||||
|
setNeutralContrastState(DEFAULT_NEUTRAL_CONTRAST);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const resetNeutralHue = useCallback(() => {
|
const resetNeutralHue = useCallback(() => {
|
||||||
setNeutralHueState(DEFAULT_NEUTRAL_HUE);
|
setNeutralHueState(DEFAULT_NEUTRAL_HUE);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -186,19 +289,33 @@ export const SidebarProvider = ({ initialCollapsed = false, children }) => {
|
|||||||
setCollapsed,
|
setCollapsed,
|
||||||
neutralHue,
|
neutralHue,
|
||||||
setNeutralHue,
|
setNeutralHue,
|
||||||
|
neutralChroma,
|
||||||
|
setNeutralChroma,
|
||||||
|
neutralContrast,
|
||||||
|
setNeutralContrast,
|
||||||
resetNeutralHue,
|
resetNeutralHue,
|
||||||
|
resetNeutralChroma,
|
||||||
|
resetNeutralContrast,
|
||||||
themeMode,
|
themeMode,
|
||||||
setThemeMode,
|
setThemeMode,
|
||||||
cycleThemeMode,
|
cycleThemeMode,
|
||||||
themeModes: THEME_MODES,
|
themeModes: THEME_MODES,
|
||||||
defaultNeutralHue: DEFAULT_NEUTRAL_HUE,
|
defaultNeutralHue: DEFAULT_NEUTRAL_HUE,
|
||||||
|
defaultNeutralChroma: DEFAULT_NEUTRAL_CHROMA,
|
||||||
|
defaultNeutralContrast: DEFAULT_NEUTRAL_CONTRAST,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
collapsed,
|
collapsed,
|
||||||
setCollapsed,
|
setCollapsed,
|
||||||
neutralHue,
|
neutralHue,
|
||||||
setNeutralHue,
|
setNeutralHue,
|
||||||
|
neutralChroma,
|
||||||
|
setNeutralChroma,
|
||||||
|
neutralContrast,
|
||||||
|
setNeutralContrast,
|
||||||
resetNeutralHue,
|
resetNeutralHue,
|
||||||
|
resetNeutralChroma,
|
||||||
|
resetNeutralContrast,
|
||||||
themeMode,
|
themeMode,
|
||||||
setThemeMode,
|
setThemeMode,
|
||||||
cycleThemeMode,
|
cycleThemeMode,
|
||||||
|
|||||||
@@ -1,26 +1,32 @@
|
|||||||
:root {
|
:root {
|
||||||
color-scheme: light dark;
|
color-scheme: light dark;
|
||||||
|
|
||||||
--neutral-hue: 180deg;
|
--neutral-hue: 145deg;
|
||||||
--foreground-hue-offset: 10deg;
|
--surface-hue-shift: 6deg;
|
||||||
--accent-hue-offset: -20deg;
|
--foreground-hue-offset: 20deg;
|
||||||
--dark-hue-offset: 30deg;
|
--accent-hue-offset: 0deg;
|
||||||
--dark-foreground-hue-offset: 10deg;
|
--dark-hue-offset: 40deg;
|
||||||
--surface-hue-shift: -4deg;
|
--dark-foreground-hue-offset: 20deg;
|
||||||
|
--neutral-chroma: 0.15;
|
||||||
|
--neutral-contrast: 0.5;
|
||||||
|
--neutral-contrast-amount: calc(0.85 + var(--neutral-contrast) * 0.55);
|
||||||
|
--neutral-contrast-baseline: 1.125;
|
||||||
|
--neutral-contrast-delta: calc(var(--neutral-contrast-amount) - var(--neutral-contrast-baseline));
|
||||||
|
--neutral-chroma-scale: calc(clamp(0.0001, var(--neutral-chroma), 1) / 0.1);
|
||||||
|
|
||||||
/* --- Neutrals --- */
|
/* --- Neutrals --- */
|
||||||
--bg: oklch(0.97 0 calc(var(--neutral-hue) + var(--surface-hue-shift)));
|
--bg: oklch(calc(0.97 + var(--neutral-contrast-delta) * 0.12) calc(var(--neutral-chroma) * 0.001) calc(var(--neutral-hue) + var(--surface-hue-shift)));
|
||||||
--surface: oklch(0.985 0 calc(var(--neutral-hue) + var(--surface-hue-shift)));
|
--surface: oklch(calc(0.985 + var(--neutral-contrast-delta) * 0.1) calc(var(--neutral-chroma) * 0.001) calc(var(--neutral-hue) + var(--surface-hue-shift)));
|
||||||
--surface-subtle: oklch(0.96 0 calc(var(--neutral-hue) + var(--surface-hue-shift)));
|
--surface-subtle: oklch(calc(0.96 + var(--neutral-contrast-delta) * 0.16) calc(var(--neutral-chroma) * 0.002) calc(var(--neutral-hue) + var(--surface-hue-shift)));
|
||||||
--fg: oklch(0.32 0 calc(var(--neutral-hue) + var(--foreground-hue-offset)));
|
--fg: oklch(calc(0.32 - var(--neutral-contrast-delta) * 0.18) calc(var(--neutral-chroma) * 0.003) calc(var(--neutral-hue) + var(--foreground-hue-offset)));
|
||||||
--muted: oklch(0.54 0 calc(var(--neutral-hue) + var(--foreground-hue-offset)));
|
--muted: oklch(calc(0.54 - var(--neutral-contrast-delta) * 0.05) calc(var(--neutral-chroma) * 0.005) calc(var(--neutral-hue) + var(--foreground-hue-offset)));
|
||||||
--muted-subtle: color-mix(in oklch, var(--muted) 55%, var(--border));
|
--muted-subtle: color-mix(in oklch, var(--muted) 55%, var(--border));
|
||||||
--sidebar-fg: oklch(0.56 0 calc(var(--neutral-hue) + var(--foreground-hue-offset)));
|
--sidebar-fg: oklch(calc(0.56 + var(--neutral-contrast-delta) * 0.18) calc(var(--neutral-chroma) * 0.003) calc(var(--neutral-hue) + var(--foreground-hue-offset)));
|
||||||
--border: oklch(0.92 0 calc(var(--neutral-hue) + var(--foreground-hue-offset)));
|
--border: oklch(calc(0.92 + var(--neutral-contrast-delta) * 0.15) calc(var(--neutral-chroma) * 0.0015) calc(var(--neutral-hue) + var(--foreground-hue-offset)));
|
||||||
|
|
||||||
/* --- Accent (primary) --- */
|
/* --- Accent (primary) --- */
|
||||||
--accent: oklch(0.61 0.16 calc(var(--neutral-hue) + var(--foreground-hue-offset) + var(--accent-hue-offset)));
|
--accent: oklch(0.61 calc(0.16 * var(--neutral-chroma-scale)) calc(var(--neutral-hue) + var(--foreground-hue-offset) + var(--accent-hue-offset)));
|
||||||
--accent-hover: oklch(0.70 0.12 calc(var(--neutral-hue) + var(--foreground-hue-offset) + var(--accent-hue-offset)));
|
--accent-hover: oklch(0.70 calc(0.12 * var(--neutral-chroma-scale)) calc(var(--neutral-hue) + var(--foreground-hue-offset) + var(--accent-hue-offset)));
|
||||||
--on-accent: oklch(1 0 0);
|
--on-accent: oklch(1 0 0);
|
||||||
|
|
||||||
--folder-icon-back: color-mix(in oklch, var(--accent) 78%, black 8%);
|
--folder-icon-back: color-mix(in oklch, var(--accent) 78%, black 8%);
|
||||||
@@ -107,18 +113,17 @@
|
|||||||
|
|
||||||
--dark-neutral-hue: calc(var(--neutral-hue) + var(--dark-hue-offset));
|
--dark-neutral-hue: calc(var(--neutral-hue) + var(--dark-hue-offset));
|
||||||
--dark-foreground-hue: calc(var(--neutral-hue) + var(--dark-foreground-hue-offset));
|
--dark-foreground-hue: calc(var(--neutral-hue) + var(--dark-foreground-hue-offset));
|
||||||
|
--bg: oklch(calc(0.18 - var(--neutral-contrast-delta) * 0.015) calc(var(--neutral-chroma) * 0.1) calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
||||||
--bg: oklch(0.15 0.01 calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
--surface: oklch(calc(0.22 - var(--neutral-contrast-delta) * 0.012) calc(var(--neutral-chroma) * 0.12) calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
||||||
--surface: oklch(0.19 0.012 calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
--surface-subtle: oklch(calc(0.26 - var(--neutral-contrast-delta) * 0.01) calc(var(--neutral-chroma) * 0.12) calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
||||||
--surface-subtle: oklch(0.23 0.012 calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
--fg: oklch(calc(0.9 + var(--neutral-contrast-delta) * 0.02) calc(var(--neutral-chroma) * 0.04) var(--dark-foreground-hue));
|
||||||
--fg: oklch(0.89 0.015 var(--dark-foreground-hue));
|
--muted: oklch(calc(0.72 + var(--neutral-contrast-delta) * 0.01) calc(var(--neutral-chroma) * 0.06) var(--dark-foreground-hue));
|
||||||
--muted: oklch(0.72 0.02 var(--dark-foreground-hue));
|
|
||||||
--muted-subtle: color-mix(in oklch, var(--muted) 45%, var(--border));
|
--muted-subtle: color-mix(in oklch, var(--muted) 45%, var(--border));
|
||||||
--sidebar-fg: oklch(0.78 0.02 var(--dark-foreground-hue));
|
--sidebar-fg: oklch(calc(0.78 + var(--neutral-contrast-delta) * 0.01) calc(var(--neutral-chroma) * 0.06) var(--dark-foreground-hue));
|
||||||
--border: oklch(0.33 0.01 var(--dark-foreground-hue));
|
--border: oklch(calc(0.33 - var(--neutral-contrast-delta) * 0.01) calc(var(--neutral-chroma) * 0.03) var(--dark-foreground-hue));
|
||||||
|
|
||||||
--accent: oklch(0.75 0.16 calc(var(--dark-foreground-hue) + var(--accent-hue-offset)));
|
--accent: oklch(0.75 calc(0.16 * var(--neutral-chroma-scale)) calc(var(--dark-foreground-hue) + var(--accent-hue-offset)));
|
||||||
--accent-hover: oklch(0.82 0.13 calc(var(--dark-foreground-hue) + var(--accent-hue-offset)));
|
--accent-hover: oklch(0.82 calc(0.13 * var(--neutral-chroma-scale)) calc(var(--dark-foreground-hue) + var(--accent-hue-offset)));
|
||||||
--on-accent: oklch(0.15 0.015 var(--dark-foreground-hue));
|
--on-accent: oklch(0.15 0.015 var(--dark-foreground-hue));
|
||||||
|
|
||||||
--folder-icon-back: color-mix(in oklch, var(--accent) 72%, black 12%);
|
--folder-icon-back: color-mix(in oklch, var(--accent) 72%, black 12%);
|
||||||
@@ -185,18 +190,17 @@
|
|||||||
|
|
||||||
--dark-neutral-hue: calc(var(--neutral-hue) + var(--dark-hue-offset));
|
--dark-neutral-hue: calc(var(--neutral-hue) + var(--dark-hue-offset));
|
||||||
--dark-foreground-hue: calc(var(--neutral-hue) + var(--dark-foreground-hue-offset));
|
--dark-foreground-hue: calc(var(--neutral-hue) + var(--dark-foreground-hue-offset));
|
||||||
|
--bg: oklch(calc(0.5 - 0.35 * var(--neutral-contrast-amount)) calc(var(--neutral-chroma) * 0.1) calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
||||||
--bg: oklch(0.15 0 calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
--surface: oklch(calc(0.5 - 0.31 * var(--neutral-contrast-amount)) calc(var(--neutral-chroma) * 0.12) calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
||||||
--surface: oklch(0.19 0 calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
--surface-subtle: oklch(calc(0.5 - 0.27 * var(--neutral-contrast-amount)) calc(var(--neutral-chroma) * 0.12) calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
||||||
--surface-subtle: oklch(0.23 0 calc(var(--dark-neutral-hue) + var(--surface-hue-shift)));
|
--fg: oklch(calc(0.5 + 0.39 * var(--neutral-contrast-amount)) calc(var(--neutral-chroma) * 0.04) var(--dark-foreground-hue));
|
||||||
--fg: oklch(0.89 0 var(--dark-foreground-hue));
|
--muted: oklch(calc(0.5 + 0.22 * var(--neutral-contrast-amount)) calc(var(--neutral-chroma) * 0.06) var(--dark-foreground-hue));
|
||||||
--muted: oklch(0.72 0 var(--dark-foreground-hue));
|
|
||||||
--muted-subtle: color-mix(in oklch, var(--muted) 45%, var(--border));
|
--muted-subtle: color-mix(in oklch, var(--muted) 45%, var(--border));
|
||||||
--sidebar-fg: oklch(0.78 0 var(--dark-foreground-hue));
|
--sidebar-fg: oklch(calc(0.5 + 0.28 * var(--neutral-contrast-amount)) calc(var(--neutral-chroma) * 0.06) var(--dark-foreground-hue));
|
||||||
--border: oklch(0.33 0 var(--dark-foreground-hue));
|
--border: oklch(calc(0.5 - 0.17 * var(--neutral-contrast-amount)) calc(var(--neutral-chroma) * 0.03) var(--dark-foreground-hue));
|
||||||
|
|
||||||
--accent: oklch(0.75 0.16 calc(var(--dark-foreground-hue) + var(--accent-hue-offset)));
|
--accent: oklch(0.75 calc(0.16 * var(--neutral-chroma-scale)) calc(var(--dark-foreground-hue) + var(--accent-hue-offset)));
|
||||||
--accent-hover: oklch(0.82 0.13 calc(var(--dark-foreground-hue) + var(--accent-hue-offset)));
|
--accent-hover: oklch(0.82 calc(0.13 * var(--neutral-chroma-scale)) calc(var(--dark-foreground-hue) + var(--accent-hue-offset)));
|
||||||
--on-accent: oklch(0.15 0.015 var(--dark-foreground-hue));
|
--on-accent: oklch(0.15 0.015 var(--dark-foreground-hue));
|
||||||
|
|
||||||
--folder-icon-back: color-mix(in oklch, var(--accent) 72%, black 12%);
|
--folder-icon-back: color-mix(in oklch, var(--accent) 72%, black 12%);
|
||||||
|
|||||||
Reference in New Issue
Block a user