Add a Settings area with 4 color themes (Aurora, Light, Ocean, Sunset)
Requested directly: "lets add some themeing into it now, perhaps under the configuration, have white/black, and some more colors." There was no existing app-wide Settings/Configuration surface - every prior setting lived in its own panel-specific modal (Fetch Data Settings, subtitle provider settings) - so this adds the app's first one: a palette-icon button in the sidebar footer opens a new Settings modal with a 2x2 grid of theme swatches. Four themes: Aurora (the existing dark teal/green look, unchanged, stays the default), Light (a clean white/black theme - the literal "white/black" ask), Ocean (a cool blue-toned dark variant), and Sunset (a warm amber-toned dark variant) - the "some more colors" part. Picking one applies instantly via a `data-theme` attribute on <html> and persists through new get_theme/save_theme commands (added to settings.rs/lib.rs alongside delivery 25's movie-naming- scheme fix), applied on every future launch by a boot-time effect in App.tsx so it takes effect even if Settings is never reopened. theme.css's variable set was expanded to cover every place a color was previously hardcoded outside the existing --dock/--surface/etc. variables, so the whole app actually re-themes instead of leaving dark boxes behind on the Light theme: button resting/hover/active shades, the Load-files popup background, the primary button's hover tint, the header's gradient stops, and five levels of white-tint row/button hover highlights (RenamePanel.css/Header.css) all moved to new variables (--btn-bg*, --popup-bg, --accent-hover, --header- grad-a/b, --tint-02/03/05/06/16) with theme-specific values - the light theme in particular needed dark tints instead of white ones for hover states to stay visible on a white background. Verified with a new Playwright script covering: default theme on a fresh install, the Settings modal listing all 4 themes with the right one marked selected, clicking a theme applying it immediately (actual computed background color and CSS variable checked, not just the data-theme attribute) and saving it, and a previously-saved theme applying on boot before Settings is ever opened. Screenshots taken of all 4 themes across the main view and the Naming Scheme editor (whose buttons/popups were part of the hardcoded-color cleanup) to confirm visually. All prior verification suites (47 checks across naming-scheme/match-fetch/hash-files/movie-scheme), `cargo test --workspace` (162 tests), and `npm run build` still pass clean.
This commit is contained in:
+17
-1
@@ -1,4 +1,5 @@
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import Sidebar, { PANELS } from "./components/Sidebar";
|
||||
import Header from "./components/Header";
|
||||
import RenamePanel from "./components/RenamePanel";
|
||||
@@ -8,11 +9,26 @@ import SfvPanel from "./components/SfvPanel";
|
||||
import FilterPanel from "./components/FilterPanel";
|
||||
import ListPanel from "./components/ListPanel";
|
||||
import PanelStub from "./components/PanelStub";
|
||||
import { applyTheme, DEFAULT_THEME, type ThemeId } from "./components/SettingsModal";
|
||||
|
||||
const THEME_IDS: ThemeId[] = ["aurora", "light", "ocean", "sunset"];
|
||||
|
||||
export default function App() {
|
||||
const [selected, setSelected] = useState(PANELS[0].id);
|
||||
const current = PANELS.find((p) => p.id === selected) ?? PANELS[0];
|
||||
|
||||
// Applies the last-saved theme as soon as the app boots, regardless of whether the
|
||||
// Settings modal (SettingsModal.tsx, opened from the sidebar) ever gets opened this
|
||||
// session - without this, a saved theme would only ever take effect once the user
|
||||
// happened to open Settings again after restarting the app.
|
||||
useEffect(() => {
|
||||
invoke<string | null>("get_theme")
|
||||
.then((saved) => {
|
||||
applyTheme(saved && (THEME_IDS as string[]).includes(saved) ? (saved as ThemeId) : DEFAULT_THEME);
|
||||
})
|
||||
.catch(() => applyTheme(DEFAULT_THEME));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="app-shell">
|
||||
<Sidebar selected={selected} onSelect={setSelected} />
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(180deg, #111e26 0%, var(--surface-alt) 62%, #0a161c 100%);
|
||||
background: linear-gradient(180deg, var(--header-grad-a) 0%, var(--surface-alt) 62%, var(--header-grad-b) 100%);
|
||||
border-bottom: 1px solid var(--dock-line);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -161,3 +161,18 @@ export function HashIcon() {
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
// Used for the app-wide Settings entry (theme picker) in the sidebar footer -
|
||||
// deliberately a palette rather than reusing GearIcon, which already means something
|
||||
// different (the per-file Naming Scheme editor's trigger button in the Rename panel).
|
||||
export function PaletteIcon() {
|
||||
return (
|
||||
<svg {...{ ...base, width: 16, height: 16 }}>
|
||||
<path d="M12 3.5c-4.7 0-8.5 3.8-8.5 8.5s3.8 8.5 8.5 8.5c1 0 1.7-.8 1.7-1.7 0-.45-.17-.86-.46-1.16-.29-.31-.46-.72-.46-1.17 0-.94.76-1.7 1.7-1.7h2c2.6 0 4.7-2.1 4.7-4.7 0-4.15-4.1-7.55-9.19-7.55Z" />
|
||||
<circle cx="7.7" cy="11" r="1.15" fill="currentColor" stroke="none" />
|
||||
<circle cx="10.2" cy="7.3" r="1.15" fill="currentColor" stroke="none" />
|
||||
<circle cx="14.4" cy="7.6" r="1.15" fill="currentColor" stroke="none" />
|
||||
<circle cx="16.6" cy="11.2" r="1.15" fill="currentColor" stroke="none" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
}
|
||||
|
||||
.list-row:hover {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
background: var(--tint-03);
|
||||
}
|
||||
|
||||
.list-row.selected {
|
||||
@@ -88,7 +88,7 @@
|
||||
letter-spacing: 0.03em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted-text);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
background: var(--tint-05);
|
||||
border-radius: 999px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
@@ -114,17 +114,17 @@
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--surface-deep);
|
||||
background: #172a31;
|
||||
background: var(--btn-bg);
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.list-icon-button:hover {
|
||||
background: #203941;
|
||||
background: var(--btn-bg-hover);
|
||||
}
|
||||
|
||||
.list-icon-button:active {
|
||||
background: #28515a;
|
||||
background: var(--btn-bg-active);
|
||||
}
|
||||
|
||||
.list-icon-button:disabled {
|
||||
@@ -147,7 +147,7 @@
|
||||
flex-direction: column;
|
||||
min-width: 150px;
|
||||
padding: 4px;
|
||||
background: #16262d;
|
||||
background: var(--popup-bg);
|
||||
border: 1px solid var(--surface-deep);
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
|
||||
@@ -197,7 +197,7 @@
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--surface-deep);
|
||||
background: #172a31;
|
||||
background: var(--btn-bg);
|
||||
color: var(--text);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
@@ -206,7 +206,7 @@
|
||||
}
|
||||
|
||||
.action-button:hover {
|
||||
background: #203941;
|
||||
background: var(--btn-bg-hover);
|
||||
}
|
||||
|
||||
.action-button.primary {
|
||||
@@ -217,7 +217,7 @@
|
||||
}
|
||||
|
||||
.action-button.primary:hover {
|
||||
background: #70e3bb;
|
||||
background: var(--accent-hover);
|
||||
}
|
||||
|
||||
.format-editor {
|
||||
@@ -264,7 +264,7 @@
|
||||
|
||||
.format-hint code,
|
||||
.format-editor label code {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
background: var(--tint-06);
|
||||
border-radius: 4px;
|
||||
padding: 1px 5px;
|
||||
font-family: ui-monospace, "SF Mono", monospace;
|
||||
@@ -307,7 +307,7 @@
|
||||
}
|
||||
|
||||
.format-field-chip {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
background: var(--tint-06);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 2px 6px;
|
||||
@@ -319,7 +319,7 @@
|
||||
}
|
||||
|
||||
.format-field-chip:hover {
|
||||
background: rgba(255, 255, 255, 0.16);
|
||||
background: var(--tint-16);
|
||||
}
|
||||
|
||||
.format-field-chip:active {
|
||||
@@ -389,7 +389,7 @@
|
||||
}
|
||||
|
||||
.modal-plan-row:hover {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
background: var(--tint-03);
|
||||
}
|
||||
|
||||
.modal-plan-old {
|
||||
@@ -431,7 +431,7 @@
|
||||
}
|
||||
|
||||
.modal-plan-remove:hover {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
background: var(--tint-06);
|
||||
color: #ff8a8a;
|
||||
}
|
||||
|
||||
@@ -558,7 +558,7 @@
|
||||
.history-batch {
|
||||
padding: 8px;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
background: var(--tint-02);
|
||||
}
|
||||
|
||||
.history-batch-header {
|
||||
@@ -583,7 +583,7 @@
|
||||
font-size: 10.5px;
|
||||
font-weight: 700;
|
||||
color: var(--muted-text);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
background: var(--tint-05);
|
||||
border-radius: 999px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
@@ -612,7 +612,7 @@
|
||||
}
|
||||
|
||||
.preset-row:hover {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
background: var(--tint-03);
|
||||
}
|
||||
|
||||
.preset-slot-badge {
|
||||
@@ -623,7 +623,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
background: var(--tint-06);
|
||||
color: var(--aurora-green);
|
||||
font-size: 11.5px;
|
||||
font-weight: 700;
|
||||
@@ -646,7 +646,7 @@
|
||||
}
|
||||
|
||||
.preset-expression:hover {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
background: var(--tint-06);
|
||||
}
|
||||
|
||||
.preset-expression:disabled {
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
.theme-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 10px;
|
||||
margin: 4px 0 4px;
|
||||
}
|
||||
|
||||
.theme-card {
|
||||
all: unset;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--surface-deep);
|
||||
background: var(--surface);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.theme-card:hover {
|
||||
border-color: var(--dock-line);
|
||||
}
|
||||
|
||||
.theme-card.selected {
|
||||
border-color: var(--aurora-green);
|
||||
box-shadow: 0 0 0 1px var(--aurora-green);
|
||||
}
|
||||
|
||||
.theme-card:disabled {
|
||||
opacity: 0.75;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.theme-swatch {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 28px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--surface-deep);
|
||||
}
|
||||
|
||||
.theme-swatch-chip {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.theme-card-name {
|
||||
font-size: 12.5px;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.theme-card-check {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 10px;
|
||||
color: var(--aurora-green);
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// App-wide Settings: currently just the color theme, opened from the gear-adjacent
|
||||
// palette icon in the sidebar footer (see Sidebar.tsx). Everything else the app
|
||||
// persists lives in its own panel-specific settings modal (Fetch Data Settings in
|
||||
// RenamePanel/EpisodesPanel, subtitle provider settings in SubtitlesPanel) - this is
|
||||
// the one truly app-wide setting so far, hence its own top-level entry point rather
|
||||
// than living inside one of those panels.
|
||||
import { useEffect, useState } from "react";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import "./SettingsModal.css";
|
||||
|
||||
export type ThemeId = "aurora" | "light" | "ocean" | "sunset";
|
||||
|
||||
export const DEFAULT_THEME: ThemeId = "aurora";
|
||||
|
||||
interface ThemeDef {
|
||||
id: ThemeId;
|
||||
name: string;
|
||||
description: string;
|
||||
// Literal swatch colors (background, primary accent, secondary accent) matching
|
||||
// theme.css's own values for this theme - these can't be CSS variables, since the
|
||||
// whole point is to preview a theme that isn't the currently-active one.
|
||||
swatch: [string, string, string];
|
||||
}
|
||||
|
||||
const THEMES: ThemeDef[] = [
|
||||
{ id: "aurora", name: "Aurora", description: "The original dark teal & green look.", swatch: ["#08252b", "#55d7a9", "#52c7db"] },
|
||||
{ id: "light", name: "Light", description: "Clean white background, black text.", swatch: ["#ffffff", "#1f9d74", "#157e9c"] },
|
||||
{ id: "ocean", name: "Ocean", description: "A cool blue-toned dark theme.", swatch: ["#071c2e", "#4fd0e8", "#5aa9ff"] },
|
||||
{ id: "sunset", name: "Sunset", description: "A warm amber-toned dark theme.", swatch: ["#2b1408", "#f0955a", "#f0b66b"] },
|
||||
];
|
||||
|
||||
function isThemeId(value: string): value is ThemeId {
|
||||
return THEMES.some((t) => t.id === value);
|
||||
}
|
||||
|
||||
/// Applies a theme id to the document immediately, so switching feels instant instead
|
||||
/// of waiting on a round trip through Rust. Shared by App.tsx's boot-time load and
|
||||
/// this modal's click handler, so both go through the exact same logic.
|
||||
export function applyTheme(theme: ThemeId) {
|
||||
document.documentElement.dataset.theme = theme;
|
||||
}
|
||||
|
||||
export default function SettingsModal({ open, onClose }: { open: boolean; onClose: () => void }) {
|
||||
const [current, setCurrent] = useState<ThemeId>(DEFAULT_THEME);
|
||||
const [saving, setSaving] = useState<ThemeId | null>(null);
|
||||
|
||||
// Keep this modal's own idea of "the active theme" in sync with whatever's really
|
||||
// applied - reads the live `data-theme` attribute rather than re-fetching from disk,
|
||||
// since App.tsx's boot-time effect (or a previous open of this same modal) already
|
||||
// applied it there.
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
const applied = document.documentElement.dataset.theme;
|
||||
setCurrent(applied && isThemeId(applied) ? applied : DEFAULT_THEME);
|
||||
}, [open]);
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
const pick = async (theme: ThemeId) => {
|
||||
if (theme === current) return;
|
||||
setSaving(theme);
|
||||
applyTheme(theme);
|
||||
setCurrent(theme);
|
||||
try {
|
||||
await invoke("save_theme", { theme });
|
||||
} catch {
|
||||
// The theme still applied for this session even if saving it failed - not
|
||||
// worth blocking or rolling back the visual change over a disk-write hiccup.
|
||||
} finally {
|
||||
setSaving(null);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="modal-overlay" onClick={onClose}>
|
||||
<div className="modal-card modal-card-compact" onClick={(e) => e.stopPropagation()}>
|
||||
<h2 className="modal-title">Settings</h2>
|
||||
<span className="modal-field-label">Theme</span>
|
||||
<p className="modal-subtitle">Pick a color theme for the whole app. Applies immediately and remembers your choice.</p>
|
||||
<div className="theme-grid">
|
||||
{THEMES.map((theme) => (
|
||||
<button
|
||||
key={theme.id}
|
||||
type="button"
|
||||
className={`theme-card${current === theme.id ? " selected" : ""}`}
|
||||
onClick={() => void pick(theme.id)}
|
||||
disabled={saving !== null}
|
||||
title={theme.description}
|
||||
>
|
||||
<span className="theme-swatch">
|
||||
{theme.swatch.map((color, i) => (
|
||||
<span key={i} className="theme-swatch-chip" style={{ background: color }} />
|
||||
))}
|
||||
</span>
|
||||
<span className="theme-card-name">{theme.name}</span>
|
||||
{current === theme.id && <span className="theme-card-check">✓</span>}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="modal-actions">
|
||||
<button className="action-button primary" onClick={onClose}>
|
||||
Done
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -72,6 +72,25 @@
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.sidebar-settings-button {
|
||||
all: unset;
|
||||
box-sizing: border-box;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
color: var(--muted-text);
|
||||
cursor: pointer;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.sidebar-settings-button:hover {
|
||||
color: var(--text);
|
||||
background: var(--tint-06);
|
||||
}
|
||||
|
||||
.sidebar-wordmark {
|
||||
font-weight: 700;
|
||||
font-size: 13px;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { EpisodesIcon, FilterIcon, ListIcon, RenameIcon, SfvIcon, SubtitlesIcon } from "./Icons";
|
||||
import { useState } from "react";
|
||||
import { EpisodesIcon, FilterIcon, ListIcon, PaletteIcon, RenameIcon, SfvIcon, SubtitlesIcon } from "./Icons";
|
||||
import SettingsModal from "./SettingsModal";
|
||||
|
||||
export interface PanelDef {
|
||||
id: string;
|
||||
@@ -25,6 +27,8 @@ export default function Sidebar({
|
||||
selected: string;
|
||||
onSelect: (id: string) => void;
|
||||
}) {
|
||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<nav className="sidebar">
|
||||
<ul className="sidebar-list">
|
||||
@@ -47,9 +51,18 @@ export default function Sidebar({
|
||||
</ul>
|
||||
|
||||
<div className="sidebar-footer">
|
||||
<button
|
||||
className="sidebar-settings-button"
|
||||
title="Settings (theme)"
|
||||
onClick={() => setSettingsOpen(true)}
|
||||
>
|
||||
<PaletteIcon />
|
||||
</button>
|
||||
<span className="sidebar-wordmark">Aurora Curator</span>
|
||||
<span className="sidebar-version">v{APP_VERSION}</span>
|
||||
</div>
|
||||
|
||||
<SettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} />
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
+134
-4
@@ -1,7 +1,13 @@
|
||||
/* Aurora Curator's UI theme — ported 1:1 (hex values) from the original FB-Mod fork's
|
||||
AuroraTheme.java / HeaderPanel.java / MainFrame.java so the rewrite looks like a
|
||||
continuation of that design rather than a random restyle. (The app takes its name,
|
||||
"Aurora Curator", from this same Aurora theme.) */
|
||||
/* Aurora Curator's UI theme. The "aurora" theme below is ported 1:1 (hex values) from
|
||||
the original FB-Mod fork's AuroraTheme.java / HeaderPanel.java / MainFrame.java so
|
||||
the rewrite looks like a continuation of that design rather than a random restyle
|
||||
(the app takes its name, "Aurora Curator", from this same Aurora theme) - it stays
|
||||
the default. The other three theme blocks below (light/ocean/sunset) are Aurora
|
||||
Curator's own additions, picked via Settings (gear icon, sidebar footer) and applied
|
||||
as a `data-theme` attribute on <html>; every visible color in the app is meant to
|
||||
flow through one of these custom properties so switching theme is just switching
|
||||
which block of them is active - see the file's own module-doc-style notes on the
|
||||
less obvious variables below. */
|
||||
:root {
|
||||
--dock: #08252b;
|
||||
--dock-deep: #051115;
|
||||
@@ -19,10 +25,134 @@
|
||||
--sunset: #f0b66b;
|
||||
--list-selection: #1e4d54;
|
||||
--dock-selection: #1d4850;
|
||||
/* A button's resting/hover/active background - was hardcoded (#172a31/#203941/
|
||||
#28515a) in a handful of spots in RenamePanel.css; pulled out to variables here so
|
||||
every theme can supply its own shade instead of leaving a dark box behind on a
|
||||
light theme. */
|
||||
--btn-bg: #172a31;
|
||||
--btn-bg-hover: #203941;
|
||||
--btn-bg-active: #28515a;
|
||||
/* A small floating popup's background (the Load-files split-button menu). */
|
||||
--popup-bg: #16262d;
|
||||
/* The primary action button's hover shade - a lightened version of --aurora-green. */
|
||||
--accent-hover: #70e3bb;
|
||||
/* The header bar's top-to-bottom gradient stops (its middle stop is --surface-alt). */
|
||||
--header-grad-a: #111e26;
|
||||
--header-grad-b: #0a161c;
|
||||
/* Subtle highlight tints for row/button hover states, each a light-on-dark overlay
|
||||
for this theme - previously hardcoded as literal rgba(255,255,255,X) across
|
||||
RenamePanel.css, which is exactly backwards on a light theme (a white tint on an
|
||||
already-light surface is invisible). Named by their alpha so the light theme below
|
||||
can supply the mirror-image dark tints at matching intensities. */
|
||||
--tint-02: rgba(255, 255, 255, 0.02);
|
||||
--tint-03: rgba(255, 255, 255, 0.03);
|
||||
--tint-05: rgba(255, 255, 255, 0.05);
|
||||
--tint-06: rgba(255, 255, 255, 0.06);
|
||||
--tint-16: rgba(255, 255, 255, 0.16);
|
||||
--sidebar-width: 158px;
|
||||
--header-height: 68px;
|
||||
}
|
||||
|
||||
/* Light - a clean white/black theme, the most literal reading of "white/black" from
|
||||
the theming request. --dock-deep doubles as "the text color that sits well on top
|
||||
of --aurora-green" (see RenamePanel.css's .action-button.primary) - here that's
|
||||
white, since this theme's --aurora-green is deliberately darkened for contrast on a
|
||||
white page, the opposite of the dark themes' light-green-on-dark-text pairing. */
|
||||
:root[data-theme="light"] {
|
||||
--dock: #eef2f3;
|
||||
--dock-deep: #ffffff;
|
||||
--dock-mist: #dde7e9;
|
||||
--dock-line: #c7d3d5;
|
||||
--surface: #ffffff;
|
||||
--surface-alt: #f5f7f8;
|
||||
--surface-deep: #dfe6e8;
|
||||
--card: #f7f9fa;
|
||||
--text: #15191b;
|
||||
--muted-text: #5c6b6e;
|
||||
--aurora-green: #1f9d74;
|
||||
--aurora-cyan: #157e9c;
|
||||
--aurora-lilac: #7a68d9;
|
||||
--sunset: #c97a1f;
|
||||
--list-selection: #d7ece7;
|
||||
--dock-selection: #dbeee9;
|
||||
--btn-bg: #eef2f3;
|
||||
--btn-bg-hover: #e2e9eb;
|
||||
--btn-bg-active: #d2dcdd;
|
||||
--popup-bg: #ffffff;
|
||||
--accent-hover: #29b98b;
|
||||
--header-grad-a: #ffffff;
|
||||
--header-grad-b: #eef2f3;
|
||||
--tint-02: rgba(0, 0, 0, 0.02);
|
||||
--tint-03: rgba(0, 0, 0, 0.035);
|
||||
--tint-05: rgba(0, 0, 0, 0.05);
|
||||
--tint-06: rgba(0, 0, 0, 0.07);
|
||||
--tint-16: rgba(0, 0, 0, 0.14);
|
||||
}
|
||||
|
||||
/* Ocean - a cool blue-toned dark variant. */
|
||||
:root[data-theme="ocean"] {
|
||||
--dock: #071c2e;
|
||||
--dock-deep: #030f1c;
|
||||
--dock-mist: #0f3350;
|
||||
--dock-line: #1c4a68;
|
||||
--surface: #071620;
|
||||
--surface-alt: #0c1e2b;
|
||||
--surface-deep: #1a3548;
|
||||
--card: #0f232f;
|
||||
--text: #e7f2f8;
|
||||
--muted-text: #93aebe;
|
||||
--aurora-green: #4fd0e8;
|
||||
--aurora-cyan: #5aa9ff;
|
||||
--aurora-lilac: #8ea0ff;
|
||||
--sunset: #ffb46b;
|
||||
--list-selection: #1a3f57;
|
||||
--dock-selection: #193a52;
|
||||
--btn-bg: #12293a;
|
||||
--btn-bg-hover: #1a3a4f;
|
||||
--btn-bg-active: #234a63;
|
||||
--popup-bg: #102432;
|
||||
--accent-hover: #7fe0f2;
|
||||
--header-grad-a: #0c1f2e;
|
||||
--header-grad-b: #061420;
|
||||
--tint-02: rgba(255, 255, 255, 0.02);
|
||||
--tint-03: rgba(255, 255, 255, 0.03);
|
||||
--tint-05: rgba(255, 255, 255, 0.05);
|
||||
--tint-06: rgba(255, 255, 255, 0.06);
|
||||
--tint-16: rgba(255, 255, 255, 0.16);
|
||||
}
|
||||
|
||||
/* Sunset - a warm amber/coral-toned dark variant. */
|
||||
:root[data-theme="sunset"] {
|
||||
--dock: #2b1408;
|
||||
--dock-deep: #150a04;
|
||||
--dock-mist: #3d2011;
|
||||
--dock-line: #5c3319;
|
||||
--surface: #1a0f08;
|
||||
--surface-alt: #23140c;
|
||||
--surface-deep: #40261a;
|
||||
--card: #241610;
|
||||
--text: #f7ece3;
|
||||
--muted-text: #c2a190;
|
||||
--aurora-green: #f0955a;
|
||||
--aurora-cyan: #f0b66b;
|
||||
--aurora-lilac: #e0866f;
|
||||
--sunset: #ffd08a;
|
||||
--list-selection: #4a2c17;
|
||||
--dock-selection: #452a16;
|
||||
--btn-bg: #2c1a10;
|
||||
--btn-bg-hover: #3c2416;
|
||||
--btn-bg-active: #4f301d;
|
||||
--popup-bg: #24160e;
|
||||
--accent-hover: #f5b083;
|
||||
--header-grad-a: #24140b;
|
||||
--header-grad-b: #140b05;
|
||||
--tint-02: rgba(255, 255, 255, 0.02);
|
||||
--tint-03: rgba(255, 255, 255, 0.03);
|
||||
--tint-05: rgba(255, 255, 255, 0.05);
|
||||
--tint-06: rgba(255, 255, 255, 0.06);
|
||||
--tint-16: rgba(255, 255, 255, 0.16);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user