-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
feat: Add dark mode support and CSS improvements #15753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
- Add CSS custom properties for theming - Implement dark mode with prefers-color-scheme and manual toggle - Add theme toggle button in top-left corner with localStorage persistence - Improve accessibility with focus states and contrast ratios - Enhance responsive design with better breakpoints - Improve code block styling with dark mode syntax highlighting - Add print stylesheet optimizations - Improve mobile navigation styling - Enhance API navigation sidebar responsiveness
|
@vkarpov15 can you approve this please. |
|
@vkarpov15 ??? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds comprehensive dark mode support to the Mongoose documentation with a manual theme toggle, improving accessibility and user experience. The implementation uses CSS custom properties for theming, supports both system preferences and manual selection, and includes responsive design improvements across all device sizes.
Key Changes:
- Dark mode implementation with three-state theme toggle (system/dark/light) using localStorage persistence
- CSS custom properties system for consistent theming across light and dark modes
- Enhanced accessibility with improved focus states, WCAG-compliant contrast ratios, and keyboard navigation support
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
index.pug |
Added theme toggle button, mongoose5.css inclusion, and cache-busting query parameters to homepage |
docs/layout.pug |
Added theme toggle button and theme-toggle.js script to documentation layout with cache-busting |
docs/js/theme-toggle.js |
New file implementing three-state theme toggle with localStorage persistence |
docs/css/style.css |
Added dark mode support, theme toggle button styles, and enhanced code block styling for homepage |
docs/css/mongoose5.css |
Comprehensive theming system with CSS custom properties, dark mode support, responsive improvements, and print styles |
docs/css/github.css |
Added dark mode syntax highlighting colors and improved code block styling with transitions |
docs/css/api.css |
Enhanced API navigation with dark mode support, custom scrollbars, and responsive breakpoints |
docs/api_split.pug |
Added cache-busting query parameter to API CSS |
Comments suppressed due to low confidence (1)
docs/js/theme-toggle.js:29
- Unused variable theme.
const theme = document.documentElement.getAttribute('data-theme');
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| updateThemeIcon(); | ||
| } | ||
|
|
||
| // Update theme icon visibility | ||
| function updateThemeIcon() { | ||
| // CSS handles the icon visibility, but we can ensure proper state | ||
| const theme = document.documentElement.getAttribute('data-theme'); | ||
| const lightIcon = document.getElementById('theme-icon-light'); // Sun icon | ||
| const darkIcon = document.getElementById('theme-icon-dark'); // Moon icon | ||
|
|
||
| if (lightIcon && darkIcon) { | ||
| // In dark mode: show sun icon (to switch to light) | ||
| // In light mode: show moon icon (to switch to dark) | ||
| // CSS handles the actual visibility via opacity | ||
| } | ||
| } |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The updateThemeIcon() function retrieves DOM elements but doesn't do anything with them. The comment states "CSS handles the icon visibility," making this function's logic unnecessary. The function body (lines 29-37) can be simplified or removed since CSS already manages icon visibility based on the data-theme attribute.
Consider either removing this function entirely (since CSS handles visibility) or implementing meaningful JavaScript-based icon state management if needed.
| updateThemeIcon(); | |
| } | |
| // Update theme icon visibility | |
| function updateThemeIcon() { | |
| // CSS handles the icon visibility, but we can ensure proper state | |
| const theme = document.documentElement.getAttribute('data-theme'); | |
| const lightIcon = document.getElementById('theme-icon-light'); // Sun icon | |
| const darkIcon = document.getElementById('theme-icon-dark'); // Moon icon | |
| if (lightIcon && darkIcon) { | |
| // In dark mode: show sun icon (to switch to light) | |
| // In light mode: show moon icon (to switch to dark) | |
| // CSS handles the actual visibility via opacity | |
| } | |
| } | |
| } |
| color: var(--code-text, #e0e0e0); | ||
| background-color: var(--code-bg, #2d2d2d); | ||
| } | ||
| } |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This media query for dark mode (lines 188-197) only applies when prefers-color-scheme: dark, but it doesn't account for the manual [data-theme="dark"] override. This creates an inconsistency where manually selected dark mode might not style code blocks correctly.
Consider adding a corresponding body[data-theme="dark"] selector or using a CSS custom property approach to ensure consistency between system and manual dark mode.
| } | |
| } | |
| /* Manual dark mode for homepage code blocks */ | |
| body[data-theme="dark"] pre { | |
| background: var(--code-bg, #2d2d2d); | |
| border-color: var(--border-color, #444); | |
| } | |
| body[data-theme="dark"] code { | |
| color: var(--code-text, #e0e0e0); | |
| background-color: var(--code-bg, #2d2d2d); | |
| } |
| color: #808080; | ||
| } | ||
| } | ||
|
|
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to other files, the dark mode syntax highlighting styles are only applied via @media (prefers-color-scheme: dark) and don't account for manual [data-theme="dark"] selection. Users who manually select dark mode may not see the intended syntax highlighting colors.
Consider adding a [data-theme="dark"] selector alongside the media query to ensure consistency.
| /* Manual dark mode support for syntax highlighting */ | |
| [data-theme="dark"] { | |
| /* Copy of dark mode syntax highlighting styles */ | |
| .hljs { | |
| background: #22272e; | |
| color: #c9d1d9; | |
| } | |
| .hljs-comment, | |
| .hljs-quote { | |
| color: #8b949e; | |
| font-style: italic; | |
| } | |
| .hljs-keyword, | |
| .hljs-selector-tag, | |
| .hljs-literal, | |
| .hljs-section, | |
| .hljs-link { | |
| color: #ff7b72; | |
| } | |
| .hljs-function .hljs-keyword { | |
| color: #d2a8ff; | |
| } | |
| .hljs-string, | |
| .hljs-title, | |
| .hljs-name, | |
| .hljs-type, | |
| .hljs-attribute, | |
| .hljs-symbol, | |
| .hljs-bullet, | |
| .hljs-addition { | |
| color: #a5d6ff; | |
| } | |
| .hljs-meta, | |
| .hljs-subst, | |
| .hljs-regexp, | |
| .hljs-number, | |
| .hljs-built_in, | |
| .hljs-builtin-name, | |
| .hljs-selector-attr, | |
| .hljs-selector-pseudo, | |
| .hljs-template-tag, | |
| .hljs-template-variable, | |
| .hljs-variable, | |
| .hljs-class .hljs-title { | |
| color: #d2a8ff; | |
| } | |
| .hljs-emphasis { | |
| font-style: italic; | |
| } | |
| .hljs-strong { | |
| font-weight: bold; | |
| } | |
| .hljs-deletion { | |
| background: #5a1d1d; | |
| color: #f48771; | |
| } | |
| .hljs-addition { | |
| background: #1e3a1e; | |
| color: #b5cea8; | |
| } | |
| .diff .hljs-change { | |
| background: #2d4d2d; | |
| color: #4ec9b0; | |
| } | |
| .hljs-chunk { | |
| color: #808080; | |
| } | |
| } |
| .pure-menu-link:hover, | ||
| .pure-menu-link.selected { | ||
| background-color: var(--menu-hover); | ||
| } | ||
|
|
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The selector .pure-menu-link:hover, .pure-menu-link.selected is split across two lines (198-199), which is fine, but line 199 appears to duplicate functionality with the .pure-menu-link.selected rule at line 209-211. While not technically wrong, having separate rules for the same selector could lead to confusion.
Consider consolidating these rules or adding a comment explaining why they're separate if there's a specific cascade reason.
| .pure-menu-link:hover, | |
| .pure-menu-link.selected { | |
| background-color: var(--menu-hover); | |
| } | |
| .pure-menu-link:hover { | |
| background-color: var(--menu-hover); | |
| } |
| link(href="docs/css/mongoose5.css?v=" + Date.now(), rel="stylesheet") | ||
| link(href="docs/css/style.css?v=" + Date.now(), rel="stylesheet") | ||
| link(href="docs/css/github.css?v=" + Date.now(), rel="stylesheet") |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Date.now() for cache-busting creates a new URL on every page render, which defeats browser caching entirely. This forces clients to re-download CSS files on every page load, negating the benefits of HTTP caching.
Consider using a build-time constant (e.g., package version, git commit hash, or build timestamp) instead of Date.now() to ensure cache-busting only occurs when files actually change.
| link(href="docs/css/mongoose5.css?v=" + Date.now(), rel="stylesheet") | |
| link(href="docs/css/style.css?v=" + Date.now(), rel="stylesheet") | |
| link(href="docs/css/github.css?v=" + Date.now(), rel="stylesheet") | |
| link(href="docs/css/mongoose5.css?v=" + package.version, rel="stylesheet") | |
| link(href="docs/css/style.css?v=" + package.version, rel="stylesheet") | |
| link(href="docs/css/github.css?v=" + package.version, rel="stylesheet") |
| block layout | ||
| #layout | ||
| #theme-toggle | ||
| button#theme-toggle-btn(aria-label="Toggle dark mode" title="Toggle dark/light theme") |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The button's aria-label says "Toggle dark mode" but the button actually cycles through three states (system/dark/light), not just dark/light. This can confuse screen reader users who expect a simple toggle but get different behavior.
Consider updating to aria-label="Cycle theme preferences" or aria-label="Switch theme (system/dark/light)" to better reflect the three-state functionality.
| button#theme-toggle-btn(aria-label="Toggle dark mode" title="Toggle dark/light theme") | |
| button#theme-toggle-btn(aria-label="Switch theme (system/dark/light)" title="Switch theme (system/dark/light)") |
| function toggleTheme() { | ||
| const currentTheme = document.documentElement.getAttribute('data-theme'); | ||
| if (currentTheme === 'dark') { | ||
| applyTheme('light'); | ||
| } else if (currentTheme === 'light') { | ||
| applyTheme(null); // Reset to system preference | ||
| } else { | ||
| // Currently using system preference, switch to dark | ||
| applyTheme('dark'); | ||
| } | ||
| } |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The three-state toggle behavior (dark → light → system → dark) isn't communicated to screen reader users. When the button is clicked, assistive technology users won't know which state is now active.
Consider updating the button's aria-label dynamically to reflect the current state, e.g., "Theme: Dark mode" or "Theme: System preference", or add aria-live="polite" announcements when the theme changes.
| link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/mongoose5.css?v=${Date.now()}`) | ||
| link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/github.css?v=${Date.now()}`) |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Date.now() for cache-busting creates a new URL on every page render, which defeats browser caching entirely. This forces clients to re-download CSS files on every page load, negating the benefits of HTTP caching.
Consider using a build-time constant (e.g., package version, git commit hash, or build timestamp) instead of Date.now() to ensure cache-busting only occurs when files actually change.
| link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/mongoose5.css?v=${Date.now()}`) | |
| link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/github.css?v=${Date.now()}`) | |
| link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/mongoose5.css?v=${package.version}`) | |
| link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/github.css?v=${package.version}`) |
|
|
||
| append style | ||
| link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/api.css`) | ||
| link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/api.css?v=${Date.now()}`) |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Date.now() for cache-busting creates a new URL on every page render, which defeats browser caching entirely. This forces clients to re-download CSS files on every page load, negating the benefits of HTTP caching.
Consider using a build-time constant (e.g., package version, git commit hash, or build timestamp) instead of Date.now() to ensure cache-busting only occurs when files actually change.
| link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/api.css?v=${Date.now()}`) | |
| link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/api.css?v=${versions.version}`) |
Summary
This PR adds comprehensive CSS improvements to the Mongoose documentation, including dark mode support, accessibility enhancements, and responsive design improvements. The changes improve the user experience across all devices and provide users with manual control over their preferred theme.
Motivation
The Mongoose documentation currently only supports light mode and lacks some modern accessibility features. This PR addresses:
Changes Made
prefers-color-schememedia queryExamples
Before:
After:
Files Changed
docs/css/mongoose5.css- Main documentation styles with dark mode and theme toggledocs/css/api.css- API page styles with responsive improvementsdocs/css/github.css- Syntax highlighting with dark mode supportdocs/css/style.css- Homepage styles with dark modedocs/js/theme-toggle.js- Theme toggle functionality (new file)docs/layout.pug- Added theme toggle button to documentation pagesindex.pug- Added theme toggle button and mongoose5.css to homepagedocs/api_split.pug- Added cache-busting query parametersTesting
index.pug)layout.pug)api_split.pug)Notes
npm run docs:clean)