From be4f660f042e5bc42f2a5945b8fb5913a000322d Mon Sep 17 00:00:00 2001 From: Alok Singh Date: Tue, 16 Dec 2025 00:31:58 -0800 Subject: [PATCH 1/2] feat: add dark mode support via prefers-color-scheme Add automatic dark mode support that respects operating system preferences using the `@media (prefers-color-scheme: dark)` CSS media query. Changes: - verso-vars.css: Add new CSS custom properties for backgrounds, borders, links, shadows, and message colors with dark mode variants - code.css: Update API docs styling to use CSS variables - search-box.css/search-highlight.css: Update search UI to use CSS variables - Style.lean: Update manual page styling to use CSS variables The color scheme is harmonized with lean-lang.org: - Light: #ffffff background, #333 text, #386ee0 links - Dark: #1e1e1e background, #eee text, #3b94ff links Closes #641 --- src/verso-html/code.css | 55 +++++---- src/verso-manual/VersoManual/Html.lean | 2 + src/verso-manual/VersoManual/Html/Style.lean | 78 +++++++++--- src/verso/Verso/Code/Highlighted.lean | 80 ++++++------ static-web/search/search-box.css | 22 ++-- static-web/search/search-highlight.css | 16 +-- static-web/theme-toggle.js | 123 +++++++++++++++++++ static-web/verso-vars.css | 108 +++++++++++++++- 8 files changed, 379 insertions(+), 105 deletions(-) create mode 100644 static-web/theme-toggle.js diff --git a/src/verso-html/code.css b/src/verso-html/code.css index 625d4e55..ae3b022a 100644 --- a/src/verso-html/code.css +++ b/src/verso-html/code.css @@ -15,7 +15,8 @@ body { font-family: var(--verso-text-font-family); line-height: 1.6; - color: #333; + color: var(--verso-text-color, #333); + background-color: var(--verso-background-color, #fff); height: 100vh; overflow: hidden; } @@ -29,8 +30,8 @@ body { /* Sidebar */ .sidebar { width: 300px; - background: #f8f9fa; - border-right: 1px solid #e9ecef; + background: var(--verso-surface-color, #f8f9fa); + border-right: 1px solid var(--verso-border-color, #e9ecef); overflow-y: auto; flex-shrink: 0; } @@ -73,11 +74,11 @@ body { } .module-tree summary:hover { - background-color: #e9ecef; + background-color: var(--verso-border-color, #e9ecef); } .module-tree summary a { - color: #0066cc; + color: var(--verso-link-color, #0066cc); text-decoration: none; } @@ -86,12 +87,12 @@ body { } .module-tree summary.current { - background-color: #0066cc; - color: white; + background-color: var(--verso-link-color, #0066cc); + color: var(--verso-background-color, white); } .module-tree summary.current a { - color: white; + color: var(--verso-background-color, white); } .module-tree summary::before { @@ -100,7 +101,7 @@ body { left: -0.75rem; transition: transform 0.2s ease; font-size: 0.75rem; - color: #6c757d; + color: var(--verso-text-color-light, #6c757d); } .module-tree details[open] > summary::before { @@ -114,7 +115,7 @@ body { } .module-tree .leaf a { - color: #0066cc; + color: var(--verso-link-color, #0066cc); text-decoration: none; } @@ -123,12 +124,12 @@ body { } .module-tree .current { - background-color: #0066cc; - color: white; + background-color: var(--verso-link-color, #0066cc); + color: var(--verso-background-color, white); } .module-tree .current a { - color: white; + color: var(--verso-background-color, white); } /* Main content area */ @@ -141,8 +142,8 @@ body { /* Title bar */ .title-bar { - background: #fff; - border-bottom: 1px solid #e9ecef; + background: var(--verso-background-color, #fff); + border-bottom: 1px solid var(--verso-border-color, #e9ecef); padding: 1rem 1.5rem; flex-shrink: 0; position: relative; @@ -165,12 +166,12 @@ body { .breadcrumbs li:not(:last-child)::after { content: "·"; margin: 0; - color: #6c757d; + color: var(--verso-text-color-light, #6c757d); font-weight: bold; } .breadcrumbs a { - color: #0066cc; + color: var(--verso-link-color, #0066cc); text-decoration: none; padding: 0.25rem 0.5rem; border-radius: 0.25rem; @@ -178,13 +179,13 @@ body { } .breadcrumbs a:hover { - background-color: #e3f2fd; + background-color: var(--verso-selected-color, #e3f2fd); text-decoration: underline; } .breadcrumbs .current { font-weight: 600; - color: #495057; + color: var(--verso-text-color, #495057); padding: 0.25rem 0.5rem; border-radius: 0.25rem; } @@ -194,8 +195,8 @@ body { flex: 1; overflow-y: auto; padding: 2rem; - background: #ffffff; - color: #24292e; + background: var(--verso-background-color, #ffffff); + color: var(--verso-text-color, #24292e); font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace; font-size: 1rem; } @@ -206,7 +207,7 @@ body { margin-left: calc(var(--indent, 0) * 1ch); padding: 0.25rem 0.5rem; max-width: 40em; - border: 1px solid #ddd; + border: 1px solid var(--verso-border-color-light, #ddd); border-radius: 1rem; width: max-content; } @@ -297,19 +298,19 @@ pre, top: 1rem; left: 1rem; z-index: 1001; - background: #fff; - border: 1px solid #dee2e6; + background: var(--verso-background-color, #fff); + border: 1px solid var(--verso-border-color, #dee2e6); border-radius: 0.375rem; padding: 0.5rem; cursor: pointer; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + box-shadow: 0 2px 4px var(--verso-shadow-color, rgba(0, 0, 0, 0.1)); } .hamburger span { display: block; width: 20px; height: 2px; - background: #333; + background: var(--verso-text-color, #333); margin: 4px 0; transition: 0.3s; } @@ -327,7 +328,7 @@ pre, height: 100vh; z-index: 1000; transition: left 0.3s ease; - box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1); + box-shadow: 2px 0 10px var(--verso-shadow-color, rgba(0, 0, 0, 0.1)); } .menu-toggle:checked + .hamburger + .layout .sidebar { diff --git a/src/verso-manual/VersoManual/Html.lean b/src/verso-manual/VersoManual/Html.lean index 68be6e59..da79fba0 100644 --- a/src/verso-manual/VersoManual/Html.lean +++ b/src/verso-manual/VersoManual/Html.lean @@ -444,6 +444,7 @@ public def page + {{extraJsFiles.map fun f => ({{}})}} {{extraStylesheets.map (fun url => {{ }})}} {{extraCss.toArray.map ({{}})}} @@ -465,6 +466,7 @@ public def page

{{bookTitle}}

+