From 7bb3024dc92bfc4970a6472a2b035a66946ac0c5 Mon Sep 17 00:00:00 2001 From: EthanHealy01 Date: Wed, 27 May 2026 11:37:49 +0100 Subject: [PATCH] feat: add midnight theme and fix theme locations Adds midnight dark theme, fixes broken theme variable locations, adds clean-unused-theme-vars script, and updates RainbowThemeProvider and related theme constants. --- .gitignore | 7 +- .taskfiles/frontend.yml | 15 + .../public/locales/en-GB/translation.toml | 1 + .../editor/scripts/clean-unused-theme-vars.js | 217 +++++++ .../fileEditor/FileEditorThumbnail.module.css | 2 +- .../shared/RainbowThemeProvider.tsx | 17 +- .../config/configSections/GeneralSection.tsx | 14 +- .../src/core/components/tools/ToolPanel.css | 5 + .../viewer/nonpdf/MarkdownRenderer.tsx | 214 ++++++- .../components/viewer/nonpdf/TextViewer.tsx | 4 +- frontend/editor/src/core/constants/theme.ts | 2 +- .../editor/src/core/hooks/useRainbowTheme.ts | 10 +- frontend/editor/src/core/styles/theme.css | 533 +++++++++++------- .../editor/src/core/theme/mantineTheme.ts | 14 + .../components/agents/AgentsPanel.css | 54 +- .../src/assets/material-symbols-icons.d.ts | 205 ++++++- 16 files changed, 1019 insertions(+), 295 deletions(-) create mode 100644 frontend/editor/scripts/clean-unused-theme-vars.js diff --git a/.gitignore b/.gitignore index bb19e3113c..dc0b636ddb 100644 --- a/.gitignore +++ b/.gitignore @@ -55,10 +55,6 @@ app/core/src/main/resources/static/pdfjs/ app/core/src/main/resources/static/vendor/ # Note: Keep backend-managed files like fonts/, css/, js/, pdfjs/, etc. -# Tauri build artifacts -frontend/src-tauri/target/ -frontend/editor/src-tauri/target/ - # Gradle .gradle .gradle-home @@ -162,6 +158,8 @@ common/build proprietary/build stirling-pdf/build frontend/src-tauri/provisioner/target +frontend/src-tauri/target +frontend/src-tauri/runtime/ # Byte-compiled / optimized / DLL files __pycache__/ @@ -178,7 +176,6 @@ venv.bak/ # Env files (secrets / local overrides). Subproject .gitignore files whitelist any committed defaults. .env* -!.env.saas.example # VS Code /.vscode/**/* diff --git a/.taskfiles/frontend.yml b/.taskfiles/frontend.yml index 8c3fbc6179..c4fd57e3ec 100644 --- a/.taskfiles/frontend.yml +++ b/.taskfiles/frontend.yml @@ -257,6 +257,7 @@ tasks: - task: lint - task: format:check - task: test + - task: theme:check-unused-vars check:all: desc: "Full CI quality gate" @@ -298,3 +299,17 @@ tasks: deps: [install] cmds: - node editor/scripts/generate-licenses.js + + theme:clean-unused-vars: + desc: "Remove unused CSS variables from theme.css" + deps: [install] + vars: + REMOVE: '{{.REMOVE | default "false"}}' + cmds: + - node editor/scripts/clean-unused-theme-vars.js{{if eq .REMOVE "true"}} --remove{{end}} {{.CLI_ARGS}} + + theme:check-unused-vars: + desc: "Fail if theme.css contains unused CSS variables" + deps: [install] + cmds: + - node editor/scripts/clean-unused-theme-vars.js --check diff --git a/frontend/editor/public/locales/en-GB/translation.toml b/frontend/editor/public/locales/en-GB/translation.toml index 7236d05905..d66305b6d6 100644 --- a/frontend/editor/public/locales/en-GB/translation.toml +++ b/frontend/editor/public/locales/en-GB/translation.toml @@ -6905,6 +6905,7 @@ theme = "Theme" themeDark = "Dark" themeDescription = "Switch between light and dark mode" themeLight = "Light" +themeMidnight = "Midnight" title = "General" user = "User" diff --git a/frontend/editor/scripts/clean-unused-theme-vars.js b/frontend/editor/scripts/clean-unused-theme-vars.js new file mode 100644 index 0000000000..0b1cb1a6e2 --- /dev/null +++ b/frontend/editor/scripts/clean-unused-theme-vars.js @@ -0,0 +1,217 @@ +#!/usr/bin/env node + +/** + * Finds and optionally removes unused CSS custom properties from theme.css. + * + * Usage: + * node scripts/clean-unused-theme-vars.js # dry run: report only + * node scripts/clean-unused-theme-vars.js --check # CI mode: exit 1 if any unused + * node scripts/clean-unused-theme-vars.js --remove # remove unused declarations + * node scripts/clean-unused-theme-vars.js --verbose # show all usage counts + */ + +const fs = require("fs"); +const path = require("path"); + +const REMOVE = process.argv.includes("--remove"); +const CHECK = process.argv.includes("--check"); +const VERBOSE = + process.argv.includes("--verbose") || process.argv.includes("-v"); + +const EDITOR_ROOT = path.join(__dirname, ".."); +const THEME_CSS_PATH = path.join(EDITOR_ROOT, "src/core/styles/theme.css"); + +const SCAN_EXTENSIONS = new Set([ + ".ts", + ".tsx", + ".css", + ".js", + ".jsx", + ".mts", + ".mjs", +]); + +const SKIP_DIRS = new Set([ + "node_modules", + "dist", + ".git", + "target", + "coverage", + ".turbo", +]); + +// ─── Parse declarations ─────────────────────────────────────────────────────── + +function parseDeclarations(content) { + const lines = content.split("\n"); + // Map from varName -> array of 0-based line indices where it is declared + const declarations = new Map(); + + for (let i = 0; i < lines.length; i++) { + const match = lines[i].match(/^\s*(--[\w-]+)\s*:/); + if (match) { + const name = match[1]; + if (!declarations.has(name)) declarations.set(name, []); + declarations.get(name).push(i); + } + } + + return declarations; +} + +// ─── Scan for usages ───────────────────────────────────────────────────────── + +const VAR_USAGE_RE = /var\((--[\w-]+)/g; + +function collectUsagesInFile(filePath, used) { + let content; + try { + content = fs.readFileSync(filePath, "utf8"); + } catch { + return; + } + + VAR_USAGE_RE.lastIndex = 0; + let match; + while ((match = VAR_USAGE_RE.exec(content)) !== null) { + used.add(match[1]); + } +} + +function scanDir(dir, used) { + let entries; + try { + entries = fs.readdirSync(dir, { withFileTypes: true }); + } catch { + return; + } + + for (const entry of entries) { + if (entry.name.startsWith(".") || SKIP_DIRS.has(entry.name)) continue; + + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + scanDir(fullPath, used); + } else if (SCAN_EXTENSIONS.has(path.extname(entry.name))) { + collectUsagesInFile(fullPath, used); + } + } +} + +// ─── Remove unused declarations ─────────────────────────────────────────────── + +function removeDeclarations(content, unusedNames) { + const lines = content.split("\n"); + const filtered = []; + let skipping = false; + + for (const line of lines) { + if (skipping) { + // Still consuming a multi-line value — stop when we hit the terminating semicolon + if (line.includes(";")) skipping = false; + continue; + } + + const match = line.match(/^\s*(--[\w-]+)\s*:/); + if (match && unusedNames.has(match[1])) { + // If the value doesn't end on this line, skip subsequent lines too + if (!line.includes(";")) skipping = true; + continue; + } + + filtered.push(line); + } + + // Collapse runs of 3+ blank lines down to 2 (avoids gaps from removed blocks) + const collapsed = []; + let blankRun = 0; + for (const line of filtered) { + if (line.trim() === "") { + blankRun++; + if (blankRun <= 2) collapsed.push(line); + } else { + blankRun = 0; + collapsed.push(line); + } + } + + return collapsed.join("\n"); +} + +// ─── Main ───────────────────────────────────────────────────────────────────── + +function main() { + if (!fs.existsSync(THEME_CSS_PATH)) { + console.error("theme.css not found at:", THEME_CSS_PATH); + process.exit(1); + } + + const themeCss = fs.readFileSync(THEME_CSS_PATH, "utf8"); + const declarations = parseDeclarations(themeCss); + + console.log(`Found ${declarations.size} declared CSS variables in theme.css`); + console.log("Scanning source files for usages..."); + + const used = new Set(); + scanDir(EDITOR_ROOT, used); + + const unused = new Set(); + for (const name of declarations.keys()) { + if (!used.has(name)) unused.add(name); + } + + if (VERBOSE) { + const allNames = [...declarations.keys()].sort(); + for (const name of allNames) { + const status = used.has(name) ? "used " : "UNUSED"; + console.log(` ${status} ${name}`); + } + console.log(); + } + + if (unused.size === 0) { + console.log("No unused CSS variables found."); + return; + } + + const sortedUnused = [...unused].sort(); + console.log(`\nUnused variables (${unused.size}):`); + for (const name of sortedUnused) { + const lineNums = declarations + .get(name) + .map((i) => i + 1) + .join(", "); + console.log( + ` ${name} (line${declarations.get(name).length > 1 ? "s" : ""} ${lineNums})`, + ); + } + + if (CHECK) { + console.error( + "\ntheme.css has unused CSS variables. Run the following to fix:", + ); + console.error("\n task frontend:theme:clean-unused-vars REMOVE=true\n"); + process.exit(1); + } + + if (!REMOVE) { + console.log( + "\nDry run — no changes written. Re-run with --remove to delete unused declarations.", + ); + return; + } + + const updated = removeDeclarations(themeCss, unused); + fs.writeFileSync(THEME_CSS_PATH, updated, "utf8"); + + // Count declarations removed + const declsRemoved = [...unused].reduce( + (sum, name) => sum + declarations.get(name).length, + 0, + ); + console.log( + `\nRemoved ${declsRemoved} declaration${declsRemoved !== 1 ? "s" : ""} (${unused.size} unique variable${unused.size !== 1 ? "s" : ""}) from theme.css`, + ); +} + +main(); diff --git a/frontend/editor/src/core/components/fileEditor/FileEditorThumbnail.module.css b/frontend/editor/src/core/components/fileEditor/FileEditorThumbnail.module.css index fcd0335238..de2f6e6828 100644 --- a/frontend/editor/src/core/components/fileEditor/FileEditorThumbnail.module.css +++ b/frontend/editor/src/core/components/fileEditor/FileEditorThumbnail.module.css @@ -75,7 +75,7 @@ box-shadow: var(--shadow-md); overflow: hidden; position: relative; - background: var(--bg-surface); + background: white; transition: box-shadow 0.15s ease, transform 0.2s ease; diff --git a/frontend/editor/src/core/components/shared/RainbowThemeProvider.tsx b/frontend/editor/src/core/components/shared/RainbowThemeProvider.tsx index 25ddffaa72..1c81ca2963 100644 --- a/frontend/editor/src/core/components/shared/RainbowThemeProvider.tsx +++ b/frontend/editor/src/core/components/shared/RainbowThemeProvider.tsx @@ -1,4 +1,4 @@ -import { createContext, useContext, ReactNode } from "react"; +import { createContext, useContext, ReactNode, useEffect } from "react"; import { MantineProvider } from "@mantine/core"; import { useRainbowTheme } from "@app/hooks/useRainbowTheme"; import { mantineTheme } from "@app/theme/mantineTheme"; @@ -36,9 +36,20 @@ interface RainbowThemeProviderProps { export function RainbowThemeProvider({ children }: RainbowThemeProviderProps) { const rainbowTheme = useRainbowTheme(); - // Determine the Mantine color scheme + // Determine the Mantine color scheme (midnight and rainbow both use Mantine dark) const mantineColorScheme = - rainbowTheme.themeMode === "rainbow" ? "dark" : rainbowTheme.themeMode; + rainbowTheme.themeMode === "rainbow" || + rainbowTheme.themeMode === "midnight" + ? "dark" + : rainbowTheme.themeMode; + + // Apply data-color-scheme attribute to html element for CSS midnight overrides + useEffect(() => { + document.documentElement.setAttribute( + "data-color-scheme", + rainbowTheme.themeMode, + ); + }, [rainbowTheme.themeMode]); return ( diff --git a/frontend/editor/src/core/components/shared/config/configSections/GeneralSection.tsx b/frontend/editor/src/core/components/shared/config/configSections/GeneralSection.tsx index f1bfdbdca2..4a34ac20b5 100644 --- a/frontend/editor/src/core/components/shared/config/configSections/GeneralSection.tsx +++ b/frontend/editor/src/core/components/shared/config/configSections/GeneralSection.tsx @@ -49,7 +49,7 @@ const GeneralSection: React.FC = ({ const { t } = useTranslation(); const { preferences, updatePreference } = usePreferences(); const { config } = useAppConfig(); - const { toggleTheme, themeMode } = useRainbowThemeContext(); + const { themeMode } = useRainbowThemeContext(); const [fileLimitInput, setFileLimitInput] = useState( preferences.autoUnzipFileLimit, ); @@ -380,10 +380,10 @@ const GeneralSection: React.FC = ({ { - if ((themeMode === "dark") !== (val === "dark")) toggleTheme(); - }} + value={themeMode === "rainbow" ? "dark" : (themeMode as string)} + onChange={(val) => + updatePreference("theme", val as "light" | "dark" | "midnight") + } data={[ { label: t("settings.general.themeLight", "Light"), @@ -393,6 +393,10 @@ const GeneralSection: React.FC = ({ label: t("settings.general.themeDark", "Dark"), value: "dark", }, + { + label: t("settings.general.themeMidnight", "Midnight"), + value: "midnight", + }, ]} /> diff --git a/frontend/editor/src/core/components/tools/ToolPanel.css b/frontend/editor/src/core/components/tools/ToolPanel.css index 592c837715..4d871cd3e3 100644 --- a/frontend/editor/src/core/components/tools/ToolPanel.css +++ b/frontend/editor/src/core/components/tools/ToolPanel.css @@ -295,6 +295,11 @@ flex-shrink: 0; } +[data-mantine-color-scheme="dark"] .tool-panel__active-tool-pill { + background: transparent; + border-color: var(--border-subtle); +} + [data-mantine-color-scheme="dark"] .tool-panel__active-tool-pill-icon { background: color-mix( in srgb, diff --git a/frontend/editor/src/core/components/viewer/nonpdf/MarkdownRenderer.tsx b/frontend/editor/src/core/components/viewer/nonpdf/MarkdownRenderer.tsx index 5856326096..28e566f54b 100644 --- a/frontend/editor/src/core/components/viewer/nonpdf/MarkdownRenderer.tsx +++ b/frontend/editor/src/core/components/viewer/nonpdf/MarkdownRenderer.tsx @@ -17,17 +17,13 @@ function CopyButton({ text }: { text: string }) { position: "absolute", top: 8, right: 8, - background: copied - ? "var(--mantine-color-green-0)" - : "var(--mantine-color-gray-0)", - border: "1px solid var(--mantine-color-gray-3)", + background: copied ? "var(--color-green-100)" : "var(--bg-muted)", + border: "1px solid var(--border-default)", borderRadius: 3, cursor: "pointer", fontSize: "0.7em", padding: "2px 8px", - color: copied - ? "var(--mantine-color-green-7)" - : "var(--mantine-color-gray-7)", + color: copied ? "var(--color-green-700)" : "var(--text-secondary)", }} > {copied ? "✓ Copied" : "Copy"} @@ -36,6 +32,183 @@ function CopyButton({ text }: { text: string }) { } const components: Components = { + h1: ({ children }) => ( +

+ {children} +

+ ), + h2: ({ children }) => ( +

+ {children} +

+ ), + h3: ({ children }) => ( +

+ {children} +

+ ), + h4: ({ children }) => ( +

+ {children} +

+ ), + h5: ({ children }) => ( +
+ {children} +
+ ), + h6: ({ children }) => ( +
+ {children} +
+ ), + p: ({ children }) => ( +

+ {children} +

+ ), + a: ({ children, href }) => ( + + {children} + + ), + strong: ({ children }) => ( + + {children} + + ), + em: ({ children }) => ( + {children} + ), + blockquote: ({ children }) => ( +
+ {children} +
+ ), + hr: () => ( +
+ ), + ul: ({ children }) => ( +
    + {children} +
+ ), + ol: ({ children }) => ( +
    + {children} +
+ ), + li: ({ children }) => ( +
  • + {children} +
  • + ), + code: ({ children, className }) => { + const isBlock = className?.startsWith("language-"); + if (isBlock) return {children}; + return ( + + {children} + + ); + }, pre: ({ children }) => { const codeText = React.isValidElement(children) ? String((children.props as { children?: unknown }).children ?? "") @@ -44,12 +217,15 @@ const components: Components = {
               {children}
    @@ -65,18 +241,33 @@ const components: Components = {
               borderCollapse: "collapse",
               width: "100%",
               fontSize: "0.85em",
    +          color: "var(--text-primary)",
             }}
           >
             {children}
           
         
    ), + thead: ({ children }) => ( + {children} + ), + tbody: ({ children }) => {children}, + tr: ({ children }) => ( + + {children} + + ), th: ({ children, style }) => ( ( diff --git a/frontend/editor/src/core/components/viewer/nonpdf/TextViewer.tsx b/frontend/editor/src/core/components/viewer/nonpdf/TextViewer.tsx index 869d09f9e7..17e3bff665 100644 --- a/frontend/editor/src/core/components/viewer/nonpdf/TextViewer.tsx +++ b/frontend/editor/src/core/components/viewer/nonpdf/TextViewer.tsx @@ -92,8 +92,10 @@ export function TextViewer({ file, isMarkdown }: TextViewerProps) { maxWidth: 800, margin: "0 auto", padding: "20px 28px", - background: "#ffffff", + background: "var(--bg-surface)", + color: "var(--text-primary)", borderRadius: 6, + border: "1px solid var(--border-subtle)", }} > {renderedMarkdown} diff --git a/frontend/editor/src/core/constants/theme.ts b/frontend/editor/src/core/constants/theme.ts index 2de5b145cb..7721e1a85d 100644 --- a/frontend/editor/src/core/constants/theme.ts +++ b/frontend/editor/src/core/constants/theme.ts @@ -1,6 +1,6 @@ // Theme constants and utilities -export type ThemeMode = "light" | "dark" | "rainbow"; +export type ThemeMode = "light" | "dark" | "midnight" | "rainbow"; // Detect OS theme preference export function getSystemTheme(): "light" | "dark" { diff --git a/frontend/editor/src/core/hooks/useRainbowTheme.ts b/frontend/editor/src/core/hooks/useRainbowTheme.ts index 1241f234d1..1649373953 100644 --- a/frontend/editor/src/core/hooks/useRainbowTheme.ts +++ b/frontend/editor/src/core/hooks/useRainbowTheme.ts @@ -175,9 +175,13 @@ export function useRainbowTheme(): RainbowThemeHook { return; } - // Normal theme switching - const nextTheme = themeMode === "light" ? "dark" : "light"; - updatePreference("theme", nextTheme); + // Normal theme switching: light → dark → midnight → light + const cycle: Record = { + light: "dark", + dark: "midnight", + midnight: "light", + }; + updatePreference("theme", cycle[themeMode] ?? "light"); }, [themeMode, updatePreference]); const activateRainbow = useCallback(() => { diff --git a/frontend/editor/src/core/styles/theme.css b/frontend/editor/src/core/styles/theme.css index 9980e5ea97..624a723252 100644 --- a/frontend/editor/src/core/styles/theme.css +++ b/frontend/editor/src/core/styles/theme.css @@ -14,12 +14,6 @@ --spdf-compare-inline-added-bg: rgba(52, 199, 89, 0.25); /* File Manager active file colors */ - --file-active-bg: rgba( - 59, - 130, - 246, - 0.1 - ); /* Transparent blue for active file background */ --file-active-badge-bg: rgba( 34, 197, @@ -43,9 +37,7 @@ --fullscreen-anim-duration-out: 0.22s; /* Z-index constants (added in this PR) */ - --z-over-fullscreen-surface: 1400; --z-fullscreen-surface: 1200; - --z-fullscreen-favorite-star: 2; --z-fullscreen-icon-svg: 1; --z-toolpicker-star: 1; @@ -162,10 +154,8 @@ --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1); /* Font weights */ - --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; - --font-weight-bold: 700; /* Light theme semantic colors */ --bg-surface: #ffffff; @@ -192,22 +182,9 @@ /* Icon colors for light mode */ --icon-user-bg: #9ca3af; --icon-user-color: #ffffff; - --icon-notifications-bg: #9ca3af; - --icon-notifications-color: #ffffff; --icon-tools-bg: #1e88e5; --icon-tools-color: #ffffff; - --icon-read-bg: #4caf50; - --icon-read-color: #ffffff; - --icon-sign-bg: #3ba99c; - --icon-sign-color: #ffffff; - --icon-automate-bg: #a576e3; - --icon-automate-color: #ffffff; - --icon-files-bg: #d3e7f7; --icon-files-color: #0a8bff; - --icon-activity-bg: #d3e7f7; - --icon-activity-color: #0a8bff; - --icon-config-bg: #9ca3af; - --icon-config-color: #ffffff; /* Colors for tooltips */ --tooltip-title-bg: #dbefff; @@ -224,7 +201,6 @@ --tools-text-and-icon-color: var(--text-primary); /* Tool picker sticky header variables (light mode) */ - --tool-header-bg: #dbefff; --tool-header-border: #bee2ff; --tool-header-text: #1e88e5; --tool-header-badge-bg: #c0ddff; @@ -235,7 +211,6 @@ --tool-subcategory-rule-color: #e5e7eb; /* doubly lighter rule line */ --accent-interactive: #4a90e2; --text-instruction: #4a90e2; - --text-brand: var(--color-gray-700); --text-brand-accent: #dc2626; /* PDF text selection colors */ @@ -251,16 +226,13 @@ --tool-panel-search-border-bottom: #eff1f4; /* container */ - --landing-paper-bg: var(--bg-surface); --landing-inner-paper-bg: #eef8ff; --landing-inner-paper-border: #cdeaff; --landing-button-bg: var(--bg-surface); --landing-button-color: var(--icon-tools-bg); --landing-button-border: #e0f2f7; - --landing-button-hover-bg: rgb(251, 251, 251); /* drop state */ - --landing-drop-paper-bg: #e3f2fd; --landing-drop-inner-paper-bg: #bbdefb; --landing-drop-inner-paper-border: #90caf9; @@ -268,36 +240,15 @@ --landing-hero-gradient: linear-gradient(135deg, #4c8bf5 0%, #3a7be8 100%); --landing-stack-w: 224px; --landing-stack-h: 176px; - --landing-stack-glow-bg: radial-gradient( - circle, - rgba(74, 144, 226, 0.18) 0%, - transparent 70% - ); /* landing doc stack shadows */ --landing-doc-shadow-back-idle: 0 4px 20px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.04); - --landing-doc-shadow-back-hover: - 0 12px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.08); --landing-doc-shadow-front-idle: 0 8px 30px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.02); - --landing-doc-shadow-front-hover: - 0 18px 48px rgba(0, 0, 0, 0.18), 0 8px 20px rgba(0, 0, 0, 0.1), - 0 0 0 1px rgba(0, 0, 0, 0.04); /* landing action button shadows */ - --landing-action-transition: - transform 0.28s cubic-bezier(0.4, 0, 0.2, 1), - box-shadow 0.32s cubic-bezier(0.4, 0, 0.2, 1); - --landing-action-shadow-idle: - 0 6px 18px rgba(0, 0, 0, 0), 0 2px 6px rgba(0, 0, 0, 0); - --landing-action-shadow-hover: - 0 6px 18px rgba(0, 0, 0, 0.14), 0 2px 6px rgba(0, 0, 0, 0.08); - --landing-action-primary-shadow-idle: - 0 10px 26px rgba(58, 123, 232, 0), 0 4px 12px rgba(0, 0, 0, 0); - --landing-action-primary-shadow-hover: - 0 10px 26px rgba(58, 123, 232, 0.42), 0 4px 12px rgba(0, 0, 0, 0.1); /* selected file header colors */ --header-selected-bg: #1e88e5; /* light mode selected header matches dark */ @@ -306,18 +257,10 @@ --accordion-item-bg: #e8eaed; /* accordion item background - more distinguishable */ /* shadows */ - --drop-shadow-color: rgba(0, 0, 0, 0.08); - --drop-shadow-color-strong: rgba(0, 0, 0, 0.04); - --drop-shadow-filter: drop-shadow(0 0.2rem 0.4rem rgba(0, 0, 0, 0.08)) - drop-shadow(0 0.6rem 0.6rem rgba(0, 0, 0, 0.06)) - drop-shadow(0 1.2rem 1rem rgba(0, 0, 0, 0.04)); /* Light mode card hover and selection */ - --header-hover-bg: #3b4b6e; /* same family as selected, a touch muted for hover */ --card-selected-border: #3fafff; /* slightly more blue than dark mode header */ - --checkbox-border: #2f83bf; --checkbox-checked-bg: #3fafff; - --checkbox-tick: #ffffff; --information-text-bg: #eaeaea; --information-text-color: #5e5e5e; @@ -348,15 +291,9 @@ --api-keys-button-color: #333333; /* PDF Report Colors (always light) */ - --pdf-light-header-bg: 239 246 255; - --pdf-light-accent: 59 130 246; - --pdf-light-text-primary: 30 41 59; --pdf-light-text-muted: 100 116 139; --pdf-light-box-bg: 248 250 252; --pdf-light-box-border: 226 232 240; - --pdf-light-warning: 234 179 8; - --pdf-light-danger: 248 113 113; - --pdf-light-success: 34 197 94; --pdf-light-neutral: 148 163 184; --pdf-light-status-valid-bg: 209 250 229; --pdf-light-status-valid-text: 6 95 70; @@ -366,8 +303,6 @@ --pdf-light-status-invalid-text: 153 27 27; --pdf-light-status-neutral-bg: 229 231 235; --pdf-light-status-neutral-text: 55 65 81; - --pdf-light-report-container-bg: 249 250 251; - --pdf-light-simulated-page-bg: 255 255 255; --pdf-light-simulated-page-text: 15 23 42; /* Code token colors (light mode) */ @@ -376,11 +311,6 @@ --code-num-color: #4338ca; /* indigo-700 */ --code-com-color: #6b7280; /* gray-500 */ /* Compare tool specific colors - only for colors that don't have existing theme pairs */ - --compare-upload-dropzone-bg: rgba(241, 245, 249, 0.45); - --compare-upload-dropzone-border: rgba(148, 163, 184, 0.6); - --compare-upload-icon-bg: rgba(148, 163, 184, 0.2); - --compare-upload-icon-color: rgba(17, 24, 39, 0.75); - --compare-upload-divider: rgba(148, 163, 184, 0.5); /* Compare page label chip (light mode): slightly lighter than surrounding rows */ --compare-page-label-bg: var(--bg-muted); @@ -420,12 +350,12 @@ } [data-mantine-color-scheme="dark"] { - /* Dark theme gray scale (inverted) */ - --gray-50: 17 24 39; - --gray-100: 31 35 41; - --gray-200: 42 47 54; - --gray-300: 55 65 81; - --gray-400: 75 85 99; + /* Dark theme gray scale — very dark, near-black */ + --gray-50: 7 10 14; + --gray-100: 10 13 18; + --gray-200: 15 19 24; + --gray-300: 22 28 36; + --gray-400: 36 44 58; --gray-500: 107 114 128; --gray-600: 156 163 175; --gray-700: 209 213 219; @@ -433,9 +363,9 @@ --gray-900: 243 244 246; /* Dark semantic colors for Tailwind */ - --surface: 31 35 41; - --background: 42 47 54; - --border: 55 65 81; + --surface: 15 19 24; + --background: 10 13 18; + --border: 22 28 36; /* Dark theme Mantine colors */ --color-red-50: #2d1b1b; @@ -449,11 +379,11 @@ --color-red-800: #991b1b; --color-red-900: #7f1d1d; - --color-gray-50: #111827; - --color-gray-100: #1f2329; - --color-gray-200: #2a2f36; - --color-gray-300: #374151; - --color-gray-400: #4b5563; + --color-gray-50: #070a0e; + --color-gray-100: #0a0d12; + --color-gray-200: #0f1318; + --color-gray-300: #161c24; + --color-gray-400: #242c3a; --color-gray-500: #6b7280; --color-gray-600: #9ca3af; --color-gray-700: #d1d5db; @@ -461,20 +391,20 @@ --color-gray-900: #f3f4f6; /* Category colors - same as light mode for consistency */ - --category-color-removal: #ef4444; /* Red for removal tools */ - --category-color-security: #f59e0b; /* Orange for security tools */ - --category-color-formatting: #8b5cf6; /* Purple for formatting tools */ - --category-color-extraction: #06b6d4; /* Cyan for extraction tools */ - --category-color-signing: #10b981; /* Green for signing tools */ - --category-color-general: #3b82f6; /* Blue for general tools */ - --category-color-verification: #f97316; /* Orange for verification tools */ - --category-color-automation: #ec4899; /* Pink for automation tools */ - --category-color-developer: #6b7280; /* Gray for developer tools */ - --category-color-default: #6b7280; /* Default gray */ + --category-color-removal: #ef4444; + --category-color-security: #f59e0b; + --category-color-formatting: #8b5cf6; + --category-color-extraction: #06b6d4; + --category-color-signing: #10b981; + --category-color-general: #3b82f6; + --category-color-verification: #f97316; + --category-color-automation: #ec4899; + --category-color-developer: #6b7280; + --category-color-default: #6b7280; /* Special section colors - same as light mode for consistency */ - --special-color-favorites: #ffc107; /* Yellow/gold for favorites */ - --special-color-recommended: #1bb1d4; /* Cyan for recommended */ + --special-color-favorites: #ffc107; + --special-color-recommended: #1bb1d4; /* Success (green) - dark */ --color-green-50: #052e16; @@ -501,53 +431,39 @@ --color-yellow-900: #fef9c3; /* Dark theme semantic colors */ - --bg-surface: #2a2f36; - --bg-raised: #1f2329; - --bg-muted: #1f2329; - --bg-background: #2a2f36; - --bg-toolbar: #1f2329; - --bg-file-manager: #1f2329; - --bg-file-list: #2a2f36; + --bg-surface: #0f1318; + --bg-raised: #0a0d12; + --bg-muted: #0a0d12; + --bg-background: #0a0d12; + --bg-toolbar: #0a0d12; + --bg-file-manager: #0a0d12; + --bg-file-list: #0f1318; --btn-open-file: #0a8bff; - --text-primary: #f9fafb; - --text-secondary: #d1d5db; - --text-muted: #9ca3af; - /* Always-dark text (for use on light backgrounds like alerts) - does not change in dark mode */ + --text-primary: #f0f2f5; + --text-secondary: #c5ccd6; + --text-muted: #8b96a3; --text-always-dark: #1f2937; --text-always-dark-muted: #6b7280; - --border-subtle: #2a2f36; - --border-default: #3a4047; - --border-strong: #4b5563; - --hover-bg: #374151; - --active-bg: #4b5563; + --border-subtle: #0f1318; + --border-default: #161c24; + --border-strong: #242c3a; + --hover-bg: #13181f; + --active-bg: #1a2030; --automation-entry-hover-bg: var(--color-gray-200); /* Icon colors for dark mode */ - --icon-user-bg: #2a2f36; - --icon-user-color: #6e7581; - --icon-notifications-bg: #2a2f36; - --icon-notifications-color: #6e7581; - --icon-tools-bg: #4b525a; - --icon-tools-color: #eaeaea; - --icon-read-bg: #4b525a; - --icon-read-color: #eaeaea; - --icon-sign-bg: #4b525a; - --icon-sign-color: #eaeaea; - --icon-automate-bg: #4b525a; - --icon-automate-color: #eaeaea; - --icon-files-bg: #4b525a; - --icon-files-color: #eaeaea; - --icon-activity-bg: #4b525a; - --icon-activity-color: #eaeaea; - --icon-config-bg: #4b525a; - --icon-config-color: #eaeaea; + --icon-user-bg: #0f1318; + --icon-user-color: #5a6475; + --icon-tools-bg: #161c24; + --icon-tools-color: #d8dce4; + --icon-files-color: #d8dce4; /* Inactive icon colors for dark mode */ - --icon-inactive-bg: #2a2f36; - --icon-inactive-color: #6e7581; + --icon-inactive-bg: #0f1318; + --icon-inactive-color: #5a6475; /* Dark mode tooltip colors */ - --tooltip-title-bg: #4b525a; + --tooltip-title-bg: #161c24; --tooltip-title-color: #fff; --tooltip-header-bg: var(--bg-raised); --tooltip-header-color: var(--text-primary); @@ -555,7 +471,6 @@ --accent-interactive: #ffffff; --text-instruction: #ffffff; - --text-brand: var(--color-gray-800); --text-brand-accent: #ef4444; /* Compare badge text colors (dark mode): lighter for readability */ @@ -563,62 +478,41 @@ --spdf-compare-added-badge-fg: var(--color-green-500); /* container */ - --landing-paper-bg: #171a1f; --landing-inner-paper-bg: var(--bg-raised); - --landing-inner-paper-border: #2d3237; + --landing-inner-paper-border: #161c24; /* landing dark overrides */ - --landing-stack-glow-bg: radial-gradient( - circle, - rgba(30, 136, 229, 0.22) 0%, - transparent 70% - ); --landing-doc-shadow-back-idle: - 0 4px 20px rgba(0, 0, 0, 0.35), 0 1px 3px rgba(0, 0, 0, 0.25); - --landing-doc-shadow-back-hover: - 0 14px 44px rgba(0, 0, 0, 0.55), 0 6px 16px rgba(0, 0, 0, 0.35); + 0 4px 20px rgba(0, 0, 0, 0.6), 0 1px 3px rgba(0, 0, 0, 0.4); --landing-doc-shadow-front-idle: - 0 8px 30px rgba(0, 0, 0, 0.45), 0 4px 12px rgba(0, 0, 0, 0.3), + 0 8px 30px rgba(0, 0, 0, 0.7), 0 4px 12px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.04); - --landing-doc-shadow-front-hover: - 0 20px 52px rgba(0, 0, 0, 0.6), 0 10px 24px rgba(0, 0, 0, 0.4), - 0 0 0 1px rgba(255, 255, 255, 0.06); --landing-button-color: #ffffff; - --landing-button-hover-bg: var(--bg-raised); /* selected file header colors for dark */ --header-selected-bg: #1e88e5; --header-selected-fg: #ffffff; - /* file card background (dark) */ - --file-card-bg: #1f2329; - --accordion-item-bg: #373d45; /* accordion item background - more distinguishable */ - - /* shadows */ - --drop-shadow-color: rgba(255, 255, 255, 0.08); - --drop-shadow-color-strong: rgba(255, 255, 255, 0.04); - --drop-shadow-filter: drop-shadow(0 0.2rem 0.4rem rgba(200, 200, 200, 0.08)) - drop-shadow(0 0.6rem 0.6rem rgba(200, 200, 200, 0.06)) - drop-shadow(0 1.2rem 1rem rgba(200, 200, 200, 0.04)); + --file-card-bg: #0a0d12; + --accordion-item-bg: #13181f; /* Adjust shadows for dark mode */ - --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3); - --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4); - --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4); - --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.4); - --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.4); + --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.5); + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.6); + --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.6); + --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.6); + --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.6); --tools-text-and-icon-color: var(--text-primary); /* Tool picker sticky header variables (dark mode) */ - --tool-header-bg: #2a2f36; - --tool-header-border: #3a4047; - --tool-header-text: #d0d6dc; - --tool-header-badge-bg: #4b525a; - --tool-header-badge-text: #ffffff; + --tool-header-border: #161c24; + --tool-header-text: #c5ccd6; + --tool-header-badge-bg: #161c24; + --tool-header-badge-text: #f0f2f5; /* Subcategory title styling (dark mode) */ - --tool-subcategory-text-color: #9ca3af; /* lighter text in dark mode as well */ - --tool-subcategory-rule-color: #3a4047; /* doubly lighter (relative) line in dark */ + --tool-subcategory-text-color: #8b96a3; + --tool-subcategory-rule-color: #161c24; /* PDF text selection colors (dark mode) */ --pdf-selection-bg: rgba(96, 165, 250, 0.25); @@ -626,74 +520,67 @@ /* Placeholder text colors (dark mode) */ --search-text-and-icon-color: #ffffff !important; - --input-bg: #4b525a; + --input-bg: #161c24; /* Tool panel search bar background colors (dark mode) */ - --tool-panel-search-bg: #1f2329; - --tool-panel-search-border-bottom: #4b525a; + --tool-panel-search-bg: #0a0d12; + --tool-panel-search-border-bottom: #242c3a; - --information-text-bg: #292e34; - --information-text-color: #ececec; + --information-text-bg: #0a0d12; + --information-text-color: #d8dce4; /* Bulk selection panel specific colors (dark mode) */ - --bulk-panel-bg: var(--bg-raised); /* dark background for parent container */ - --bulk-card-bg: var(--bg-raised); /* dark background for cards */ - --bulk-card-border: var( - --border-default - ); /* default border for cards and buttons */ - --bulk-card-hover-border: var(--border-strong); /* stronger border on hover */ - --unsupported-bar-bg: #1f2329; - --unsupported-bar-border: #4b525a; + --bulk-panel-bg: var(--bg-raised); + --bulk-card-bg: var(--bg-raised); + --bulk-card-border: var(--border-default); + --bulk-card-hover-border: var(--border-strong); + --unsupported-bar-bg: #0a0d12; + --unsupported-bar-border: #242c3a; /* Config Modal colors (dark mode) */ - --modal-nav-bg: #1f2329; - --modal-nav-section-title: #9ca3af; - --modal-nav-item: #d0d6dc; + --modal-nav-bg: #0a0d12; + --modal-nav-section-title: #8b96a3; + --modal-nav-item: #c5ccd6; --modal-nav-item-active: #0a8bff; --modal-nav-item-active-bg: rgba(10, 139, 255, 0.15); - --modal-content-bg: #2a2f36; + --modal-content-bg: #0f1318; --modal-header-border: rgba(255, 255, 255, 0.08); /* Onboarding (dark mode) */ - --onboarding-title: #f9fafb; - --onboarding-body: #d1d5db; + --onboarding-title: #f0f2f5; + --onboarding-body: #c5ccd6; --onboarding-primary-button-bg: #ffffff; - --onboarding-primary-button-text: #0b1220; + --onboarding-primary-button-text: #0a0d12; --onboarding-secondary-button-bg: transparent; - --onboarding-secondary-button-text: #e5e7eb; - --onboarding-secondary-button-border: #3a4047; - --onboarding-step-active: #e5e7eb; - --onboarding-step-inactive: #4b5563; + --onboarding-secondary-button-text: #d8dce4; + --onboarding-secondary-button-border: #161c24; + --onboarding-step-active: #d8dce4; + --onboarding-step-inactive: #242c3a; + /* API Keys section colors (dark mode) */ - --api-keys-card-bg: #2a2f36; - --api-keys-card-border: #3a4047; + --api-keys-card-bg: #0f1318; + --api-keys-card-border: #161c24; --api-keys-card-shadow: none; - --api-keys-input-bg: #1f2329; - --api-keys-input-border: #3a4047; - --api-keys-button-bg: #3a4047; - --api-keys-button-color: #d0d6dc; + --api-keys-input-bg: #0a0d12; + --api-keys-input-border: #161c24; + --api-keys-button-bg: #161c24; + --api-keys-button-color: #c5ccd6; /* Code token colors (dark mode - Cursor-like) */ - --code-kw-color: #c792ea; /* purple */ - --code-str-color: #c3e88d; /* green */ - --code-num-color: #f78c6c; /* orange */ - --code-com-color: #697098; /* muted gray-blue */ - /* Compare tool specific colors (dark mode) - only for colors that don't have existing theme pairs */ - --compare-upload-dropzone-bg: rgba(31, 35, 41, 0.45); - --compare-upload-dropzone-border: rgba(75, 85, 99, 0.6); - --compare-upload-icon-bg: rgba(75, 85, 99, 0.2); - --compare-upload-icon-color: rgba(243, 244, 246, 0.75); - --compare-upload-divider: rgba(75, 85, 99, 0.5); + --code-kw-color: #c792ea; + --code-str-color: #c3e88d; + --code-num-color: #f78c6c; + --code-com-color: #697098; - /* Compare page label chip (dark mode): slightly darker than surrounding rows */ - --compare-page-label-bg: #1f2329; + /* Compare page label chip (dark mode) */ + --compare-page-label-bg: #0a0d12; --compare-page-label-fg: var(--text-secondary); /* Status indicator dot ring shadow (dark) */ --status-dot-ring: 0 0 0 2px rgba(255, 255, 255, 0.18); /* Input element styling (dark) */ - --input-bg: #4b525a; + --input-bg: #161c24; /* Select/dropdown placeholder state (dark) */ --select-placeholder-bg: var(--mantine-color-dark-5); @@ -709,6 +596,195 @@ --dropdown-group-label: var(--mantine-color-dark-2); } +/* ── Midnight theme — blue-tinted dark workbench ── */ +/* Applied on top of dark mode: html has both data-mantine-color-scheme="dark" + and data-color-scheme="midnight" */ +[data-color-scheme="midnight"] { + --gray-50: 21 26 38; + --gray-100: 30 36 52; + --gray-200: 45 50 72; + --gray-300: 58 65 90; + --gray-400: 75 85 99; + --gray-500: 107 114 128; + --gray-600: 156 163 175; + --gray-700: 209 213 219; + --gray-800: 229 231 235; + --gray-900: 243 244 246; + + --surface: 30 36 52; + --background: 21 26 38; + --border: 58 65 90; + + --color-gray-50: #151a24; + --color-gray-100: #1a2030; + --color-gray-200: #1e2435; + --color-gray-300: #252836; + --color-gray-400: #2d3340; + --color-gray-500: #6b7280; + --color-gray-600: #9ca3af; + --color-gray-700: #d1d5db; + --color-gray-800: #e5e7eb; + --color-gray-900: #f3f4f6; + + --category-color-general: #4b77e6; + + --bg-surface: #1e2435; + --bg-raised: #1a2030; + --bg-muted: #1a2030; + --bg-background: #151a24; + --bg-toolbar: #1e2435; + --bg-file-manager: #1a2030; + --bg-file-list: #1e2435; + --btn-open-file: #4b77e6; + --text-primary: #f1f5f9; + --text-secondary: #cbd5e1; + --text-muted: #94a3b8; + --text-always-dark: #1f2937; + --text-always-dark-muted: #6b7280; + --border-subtle: #2d3340; + --border-default: #3a4152; + --border-strong: #4a5568; + --hover-bg: #252836; + --active-bg: #2d3340; + --automation-entry-hover-bg: var(--color-gray-200); + + --icon-user-bg: #1e2435; + --icon-user-color: #6b7280; + --icon-tools-bg: #2d3340; + --icon-tools-color: #cbd5e1; + --icon-files-color: #4b77e6; + --icon-inactive-bg: #1e2435; + --icon-inactive-color: #6b7280; + + --tooltip-title-bg: #252836; + --tooltip-title-color: #f1f5f9; + --tooltip-header-bg: #1a2030; + --tooltip-header-color: #f1f5f9; + --tooltip-border: var(--border-default); + + --accent-interactive: #4b77e6; + --text-instruction: #4b77e6; + --text-brand-accent: #60a5fa; + + --spdf-compare-removed-badge-fg: var(--color-red-500); + --spdf-compare-added-badge-fg: var(--color-green-500); + + --landing-inner-paper-bg: #1a2030; + --landing-inner-paper-border: #3a4152; + --landing-button-bg: #252836; + --landing-button-color: #f1f5f9; + --landing-button-border: #3a4152; + --landing-drop-inner-paper-bg: #1e2435; + --landing-drop-inner-paper-border: #3a4152; + + --landing-doc-shadow-back-idle: + 0 4px 20px rgba(0, 0, 0, 0.45), 0 1px 3px rgba(0, 0, 0, 0.3); + --landing-doc-shadow-front-idle: + 0 8px 30px rgba(0, 0, 0, 0.55), 0 4px 12px rgba(0, 0, 0, 0.4), + 0 0 0 1px rgba(75, 119, 230, 0.08); + + --header-selected-bg: #4b77e6; + --header-selected-fg: #ffffff; + --file-card-bg: #1a2030; + --accordion-item-bg: #252836; + + --card-selected-border: #4b77e6; + --checkbox-checked-bg: #4b77e6; + + --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4); + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5); + --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.5); + --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.5); + --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.5); + + --tools-text-and-icon-color: #cbd5e1; + + --tool-header-border: #3a4152; + --tool-header-text: #cbd5e1; + --tool-header-badge-bg: #252836; + --tool-header-badge-text: #f1f5f9; + + --tool-subcategory-text-color: #94a3b8; + --tool-subcategory-rule-color: #3a4152; + + --pdf-selection-bg: rgba(75, 119, 230, 0.25); + --pdf-selection-ring: rgba(75, 119, 230, 0.28); + + --search-text-and-icon-color: #f1f5f9 !important; + --input-bg: #252836; + + --tool-panel-search-bg: #1a2030; + --tool-panel-search-border-bottom: #3a4152; + + --information-text-bg: #1e2435; + --information-text-color: #cbd5e1; + + --bulk-panel-bg: var(--bg-raised); + --bulk-card-bg: var(--bg-raised); + --bulk-card-border: var(--border-default); + --bulk-card-hover-border: var(--border-strong); + --unsupported-bar-bg: #1a2030; + --unsupported-bar-border: #3a4152; + + --modal-nav-bg: #1a2030; + --modal-nav-section-title: #94a3b8; + --modal-nav-item: #cbd5e1; + --modal-nav-item-active: #4b77e6; + --modal-nav-item-active-bg: rgba(75, 119, 230, 0.18); + --modal-content-bg: #1e2435; + --modal-header-border: rgba(255, 255, 255, 0.08); + + --onboarding-title: #f1f5f9; + --onboarding-body: #cbd5e1; + --onboarding-primary-button-bg: #4b77e6; + --onboarding-primary-button-text: #ffffff; + --onboarding-secondary-button-bg: transparent; + --onboarding-secondary-button-text: #cbd5e1; + --onboarding-secondary-button-border: #3a4152; + --onboarding-step-active: #cbd5e1; + --onboarding-step-inactive: #3a4152; + + --api-keys-card-bg: #1e2435; + --api-keys-card-border: #3a4152; + --api-keys-card-shadow: none; + --api-keys-input-bg: #1a2030; + --api-keys-input-border: #3a4152; + --api-keys-button-bg: #252836; + --api-keys-button-color: #cbd5e1; + + --code-kw-color: #7aa2f7; + --code-str-color: #9ece6a; + --code-num-color: #ff9e64; + --code-com-color: #565f89; + + --compare-page-label-bg: #1a2030; + --compare-page-label-fg: var(--text-secondary); + + --status-dot-ring: 0 0 0 2px rgba(75, 119, 230, 0.25); + + --select-placeholder-bg: var(--mantine-color-dark-5); + --select-placeholder-text: var(--mantine-color-dark-2); + + --dropdown-trigger-bg: var(--mantine-color-dark-6); + --dropdown-trigger-text: var(--mantine-color-dark-0); + --dropdown-trigger-text-disabled: var(--mantine-color-dark-1); + --dropdown-trigger-icon: var(--mantine-color-dark-2); + --dropdown-panel-bg: var(--mantine-color-dark-7); + --dropdown-panel-border: var(--mantine-color-dark-4); + --dropdown-group-label: var(--mantine-color-dark-2); + + --link-hover-bg: rgba(75, 119, 230, 0.06); + --link-hover-border: rgba(75, 119, 230, 0.2); + --link-hover-shadow: + 0 0 0 0.5px rgba(75, 119, 230, 0.1), 0 1px 3px rgba(75, 119, 230, 0.08); + --link-focus-ring: rgba(75, 119, 230, 0.35); + --link-toolbar-bg: rgba(21, 26, 36, 0.94); + --link-toolbar-border: rgba(255, 255, 255, 0.1); + --link-toolbar-shadow: + 0 12px 40px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.3), + 0 0 0 0.5px rgba(75, 119, 230, 0.08); +} + /* Dropzone drop state styling */ [data-accept] .dropzone-inner { background-color: var(--landing-drop-inner-paper-bg) !important; @@ -717,7 +793,6 @@ /* Plan section card borders - only override in dark mode */ [data-mantine-color-scheme="dark"] .plan-card { - --paper-border-color: rgb(158, 158, 158) !important; } [data-mantine-color-scheme="dark"] .plan-card [data-size="sm"] { @@ -739,6 +814,19 @@ background-color: #1c598e !important; } +[data-color-scheme="midnight"] + .plan-button:not(:disabled):not([data-disabled]) { + background-color: #4b77e6 !important; +} + +/* Override Mantine's internal body/surface colors for midnight */ +[data-color-scheme="midnight"] { + --mantine-color-body: #151a24; + --mantine-color-dark-6: #1e2435; + --mantine-color-dark-7: #151a24; + --mantine-color-dark-9: #0f1318; +} + /* Lighter grey for disabled plan buttons */ .plan-button:disabled, .plan-button[data-disabled] { @@ -787,12 +875,14 @@ border-radius: 8px; } -/* Smooth transitions for theme switching */ +/* Smooth transitions for theme switching - backgrounds and borders only. + Color (text) is intentionally excluded: Mantine applies the color scheme + after the first paint, so a color transition would cause text to visibly + crawl from the wrong colour on every page load. */ * { transition: background-color 0.2s ease, - border-color 0.2s ease, - color 0.2s ease; + border-color 0.2s ease; } /* ── PDF Link Overlay (viewer) ── */ :root { @@ -992,10 +1082,15 @@ --shadow-color: rgba(15, 23, 42, 0.55); } -[data-theme="dark"] { +[data-theme="dark"], +[data-color-scheme="dark"] { --shadow-color: rgba(0, 0, 0, 0.75); } +[data-color-scheme="midnight"] { + --shadow-color: rgba(0, 0, 0, 0.85); +} + /* ---- Wordmark light/dark switching (use instead of JS colorScheme checks) ---- */ .wordmark-dark-only { display: none; diff --git a/frontend/editor/src/core/theme/mantineTheme.ts b/frontend/editor/src/core/theme/mantineTheme.ts index ac36eb515f..f63fe5fd5a 100644 --- a/frontend/editor/src/core/theme/mantineTheme.ts +++ b/frontend/editor/src/core/theme/mantineTheme.ts @@ -53,6 +53,19 @@ const gray: MantineColorsTuple = [ "var(--color-gray-900)", ]; +const dark: MantineColorsTuple = [ + "#c4c9d2", + "#9aa3b0", + "#9ca3af", + "#6b7280", + "#242c3a", + "#161c24", + "#0f1318", + "#0a0d12", + "#070a0e", + "#040507", +]; + export const mantineTheme = createTheme({ // Primary color primaryColor: "primary", @@ -63,6 +76,7 @@ export const mantineTheme = createTheme({ green, yellow, gray, + dark, }, // Spacing system - uses CSS variables diff --git a/frontend/editor/src/proprietary/components/agents/AgentsPanel.css b/frontend/editor/src/proprietary/components/agents/AgentsPanel.css index 7a531012eb..379062a8dc 100644 --- a/frontend/editor/src/proprietary/components/agents/AgentsPanel.css +++ b/frontend/editor/src/proprietary/components/agents/AgentsPanel.css @@ -25,19 +25,9 @@ display: block; width: 100%; padding: 0.75rem; - border: 1px solid - color-mix(in srgb, var(--mantine-color-blue-5) 40%, var(--border-subtle)); + border: 1px solid var(--border-subtle); border-radius: 0.625rem; - background: linear-gradient( - 135deg, - color-mix( - in srgb, - var(--mantine-color-blue-6) 6%, - var(--mantine-color-body) - ) - 0%, - var(--mantine-color-body) 100% - ); + background: var(--mantine-color-body); transition: background 150ms ease-out, border-color 150ms ease-out; @@ -46,19 +36,10 @@ .agent-button:hover { border-color: color-mix( in srgb, - var(--mantine-color-blue-5) 65%, + var(--mantine-color-gray-4) 60%, var(--border-subtle) ); - background: linear-gradient( - 135deg, - color-mix( - in srgb, - var(--mantine-color-blue-6) 12%, - var(--mantine-color-default-hover) - ) - 0%, - var(--mantine-color-default-hover) 100% - ); + background: var(--mantine-color-default-hover); } .agent-button__logo { @@ -156,34 +137,17 @@ } [data-mantine-color-scheme="dark"] .agent-button { + background: transparent; border-color: color-mix( in srgb, - var(--mantine-color-blue-7) 55%, - var(--border-subtle) - ); - background: linear-gradient( - 135deg, - color-mix(in srgb, var(--mantine-color-blue-9) 35%, transparent) 0%, - transparent 100% + var(--mantine-color-dark-4) 60%, + transparent ); } [data-mantine-color-scheme="dark"] .agent-button:hover { - border-color: color-mix( - in srgb, - var(--mantine-color-blue-5) 60%, - var(--border-subtle) - ); - background: linear-gradient( - 135deg, - color-mix( - in srgb, - var(--mantine-color-blue-8) 45%, - rgba(255, 255, 255, 0.04) - ) - 0%, - rgba(255, 255, 255, 0.04) 100% - ); + border-color: var(--mantine-color-dark-3); + background: var(--mantine-color-dark-6); } [data-mantine-color-scheme="dark"] .agent-button__logo { diff --git a/frontend/src/assets/material-symbols-icons.d.ts b/frontend/src/assets/material-symbols-icons.d.ts index 39299de33c..89803d02e7 100644 --- a/frontend/src/assets/material-symbols-icons.d.ts +++ b/frontend/src/assets/material-symbols-icons.d.ts @@ -2,7 +2,210 @@ // This file is automatically generated by scripts/generate-icons.js // Do not edit manually - changes will be overwritten -export type MaterialSymbolIcon = '123-rounded' | 'account-circle' | 'add' | 'add-comment' | 'add-photo-alternate' | 'add-rounded' | 'admin-panel-settings' | 'admin-panel-settings-rounded' | 'analytics' | 'analytics-rounded' | 'api-rounded' | 'approval-outline-rounded' | 'arrow-back' | 'arrow-back-rounded' | 'arrow-forward' | 'article-outline-rounded' | 'assignment-outline-rounded' | 'attachment-rounded' | 'auto-awesome-rounded' | 'automation-outline' | 'backup' | 'bookmark-add-rounded' | 'branding-watermark-outline-rounded' | 'brush' | 'build-outline-rounded' | 'change-history' | 'check' | 'check-circle' | 'check-circle-outline-rounded' | 'check-circle-rounded' | 'chevron-left' | 'chevron-left-rounded' | 'chevron-right-rounded' | 'cleaning-services-outline-rounded' | 'close' | 'close-rounded' | 'cloud-upload' | 'comment' | 'compare-rounded' | 'compress' | 'content-copy' | 'content-copy-rounded' | 'content-cut-rounded' | 'content-paste-rounded' | 'credit-card' | 'crop-free-rounded' | 'crop-rounded' | 'crop-square' | 'crop-square-outline' | 'dashboard-customize-outline-rounded' | 'dashboard-customize-rounded' | 'dashboard-outline-rounded' | 'delete' | 'delete-outline-rounded' | 'delete-rounded' | 'description' | 'desktop-cloud-rounded' | 'download' | 'download-rounded' | 'edit' | 'edit-outline-rounded' | 'edit-rounded' | 'edit-square-outline-rounded' | 'edit-square-rounded' | 'error' | 'error-outline-rounded' | 'error-rounded' | 'expand-more-rounded' | 'explore-rounded' | 'extension-rounded' | 'fact-check-outline-rounded' | 'fact-check-rounded' | 'find-replace' | 'folder-rounded' | 'format-align-center' | 'format-align-left' | 'format-align-right' | 'format-color-fill-rounded' | 'format-underlined' | 'gavel-rounded' | 'gpp-maybe-outline-rounded' | 'group' | 'group-add' | 'group-rounded' | 'groups-rounded' | 'help-rounded' | 'highlight' | 'image-outline-rounded' | 'info' | 'info-outline-rounded' | 'info-rounded' | 'javascript-rounded' | 'key' | 'key-rounded' | 'keyboard-arrow-down' | 'keyboard-arrow-up' | 'keyboard-rounded' | 'language' | 'layers-clear-outline-rounded' | 'layers-outline-rounded' | 'library-add-outline-rounded' | 'link' | 'link-rounded' | 'lock' | 'lock-open' | 'lock-open-right-outline-rounded' | 'lock-outline' | 'login' | 'logout' | 'logout-rounded' | 'looks-one-outline-rounded' | 'mail-rounded' | 'match-word-rounded' | 'material-symbols:pause-rounded' | 'material-symbols:play-arrow-rounded' | 'menu-book-outline-rounded' | 'menu-book-rounded' | 'more-vert' | 'move-down-rounded' | 'opacity' | 'open-in-new-rounded' | 'palette-outline' | 'pan-tool-rounded' | 'password-rounded' | 'pause-rounded' | 'person' | 'person-add' | 'person-add-rounded' | 'person-check' | 'person-off' | 'person-remove' | 'person-rounded' | 'photo-library-outline-rounded' | 'picture-as-pdf-rounded' | 'pin-end' | 'play-arrow-rounded' | 'play-circle' | 'preview-off-rounded' | 'qr-code-rounded' | 'quick-reference-all-outline-rounded' | 'radio-button-unchecked' | 'redo' | 'refresh' | 'refresh-rounded' | 'remove-moderator-outline-rounded' | 'remove-selection-rounded' | 'rocket-launch' | 'rotate-left' | 'rotate-right' | 'rotate-right-rounded' | 'save' | 'save-rounded' | 'scan-delete-outline-rounded' | 'scan-delete-rounded' | 'scanner-outline-rounded' | 'schedule-outline-rounded' | 'search' | 'search-rounded' | 'security' | 'select-all' | 'send-rounded' | 'settings-rounded' | 'shield-lock' | 'shield-rounded' | 'show-chart' | 'signature-rounded' | 'speed' | 'star' | 'star-rounded' | 'sticky-note-2' | 'storage-rounded' | 'strikethrough-s' | 'subdirectory-arrow-right-rounded' | 'swap-horiz' | 'sync-alt-rounded' | 'system-update-alt-rounded' | 'text-fields' | 'text-fields-rounded' | 'thread-unread-rounded' | 'toc-rounded' | 'touch-app-rounded' | 'tune-rounded' | 'undo' | 'unfold-less' | 'unfold-more' | 'upload-file-rounded' | 'upload-rounded' | 'verified-outline-rounded' | 'verified-user-outline' | 'verified-user-rounded' | 'view-carousel-rounded' | 'view-list' | 'visibility' | 'visibility-off-outline-rounded' | 'visibility-rounded' | 'vital-signs-rounded' | 'warning' | 'warning-rounded' | 'workspace-premium-outline-rounded' | 'workspace-premium-rounded' | 'zoom-in' | 'zoom-in-map-rounded' | 'zoom-out'; +export type MaterialSymbolIcon = + | "123-rounded" + | "account-circle" + | "add" + | "add-comment" + | "add-photo-alternate" + | "add-rounded" + | "admin-panel-settings" + | "admin-panel-settings-rounded" + | "analytics" + | "analytics-rounded" + | "api-rounded" + | "approval-outline-rounded" + | "arrow-back" + | "arrow-back-rounded" + | "arrow-forward" + | "article-outline-rounded" + | "assignment-outline-rounded" + | "attachment-rounded" + | "auto-awesome-rounded" + | "automation-outline" + | "backup" + | "bookmark-add-rounded" + | "branding-watermark-outline-rounded" + | "brush" + | "build-outline-rounded" + | "change-history" + | "check" + | "check-circle" + | "check-circle-outline-rounded" + | "check-circle-rounded" + | "chevron-left" + | "chevron-left-rounded" + | "chevron-right-rounded" + | "cleaning-services-outline-rounded" + | "close" + | "close-rounded" + | "cloud-upload" + | "comment" + | "compare-rounded" + | "compress" + | "content-copy" + | "content-copy-rounded" + | "content-cut-rounded" + | "content-paste-rounded" + | "credit-card" + | "crop-free-rounded" + | "crop-rounded" + | "crop-square" + | "crop-square-outline" + | "dashboard-customize-outline-rounded" + | "dashboard-customize-rounded" + | "dashboard-outline-rounded" + | "delete" + | "delete-outline-rounded" + | "delete-rounded" + | "description" + | "desktop-cloud-rounded" + | "download" + | "download-rounded" + | "edit" + | "edit-outline-rounded" + | "edit-rounded" + | "edit-square-outline-rounded" + | "edit-square-rounded" + | "error" + | "error-outline-rounded" + | "error-rounded" + | "expand-more-rounded" + | "explore-rounded" + | "extension-rounded" + | "fact-check-outline-rounded" + | "fact-check-rounded" + | "find-replace" + | "folder-rounded" + | "format-align-center" + | "format-align-left" + | "format-align-right" + | "format-color-fill-rounded" + | "format-underlined" + | "gavel-rounded" + | "gpp-maybe-outline-rounded" + | "group" + | "group-add" + | "group-rounded" + | "groups-rounded" + | "help-rounded" + | "highlight" + | "image-outline-rounded" + | "info" + | "info-outline-rounded" + | "info-rounded" + | "javascript-rounded" + | "key" + | "key-rounded" + | "keyboard-arrow-down" + | "keyboard-arrow-up" + | "keyboard-rounded" + | "language" + | "layers-clear-outline-rounded" + | "layers-outline-rounded" + | "library-add-outline-rounded" + | "link" + | "link-rounded" + | "lock" + | "lock-open" + | "lock-open-right-outline-rounded" + | "lock-outline" + | "login" + | "logout" + | "logout-rounded" + | "looks-one-outline-rounded" + | "mail-rounded" + | "match-word-rounded" + | "material-symbols:pause-rounded" + | "material-symbols:play-arrow-rounded" + | "menu-book-outline-rounded" + | "menu-book-rounded" + | "more-vert" + | "move-down-rounded" + | "opacity" + | "open-in-new-rounded" + | "palette-outline" + | "pan-tool-rounded" + | "password-rounded" + | "pause-rounded" + | "person" + | "person-add" + | "person-add-rounded" + | "person-check" + | "person-off" + | "person-remove" + | "person-rounded" + | "photo-library-outline-rounded" + | "picture-as-pdf-rounded" + | "pin-end" + | "play-arrow-rounded" + | "play-circle" + | "preview-off-rounded" + | "qr-code-rounded" + | "quick-reference-all-outline-rounded" + | "radio-button-unchecked" + | "redo" + | "refresh" + | "refresh-rounded" + | "remove-moderator-outline-rounded" + | "remove-selection-rounded" + | "rocket-launch" + | "rotate-left" + | "rotate-right" + | "rotate-right-rounded" + | "save" + | "save-rounded" + | "scan-delete-outline-rounded" + | "scan-delete-rounded" + | "scanner-outline-rounded" + | "schedule-outline-rounded" + | "search" + | "search-rounded" + | "security" + | "select-all" + | "send-rounded" + | "settings-rounded" + | "shield-lock" + | "shield-rounded" + | "show-chart" + | "signature-rounded" + | "speed" + | "star" + | "star-rounded" + | "sticky-note-2" + | "storage-rounded" + | "strikethrough-s" + | "subdirectory-arrow-right-rounded" + | "swap-horiz" + | "sync-alt-rounded" + | "system-update-alt-rounded" + | "text-fields" + | "text-fields-rounded" + | "thread-unread-rounded" + | "toc-rounded" + | "touch-app-rounded" + | "tune-rounded" + | "undo" + | "unfold-less" + | "unfold-more" + | "upload-file-rounded" + | "upload-rounded" + | "verified-outline-rounded" + | "verified-user-outline" + | "verified-user-rounded" + | "view-carousel-rounded" + | "view-list" + | "visibility" + | "visibility-off-outline-rounded" + | "visibility-rounded" + | "vital-signs-rounded" + | "warning" + | "warning-rounded" + | "workspace-premium-outline-rounded" + | "workspace-premium-rounded" + | "zoom-in" + | "zoom-in-map-rounded" + | "zoom-out"; export interface IconSet { prefix: string;