diff --git a/docs/css/api.css b/docs/css/api.css index a2f30f6c76..3d9b50fe0d 100644 --- a/docs/css/api.css +++ b/docs/css/api.css @@ -12,6 +12,28 @@ height: 100%; padding-bottom: 10px; overflow-y: auto; + background-color: var(--menu-bg, #fafafa); + border-left: 1px solid var(--border-color, #ddd); + scrollbar-width: thin; + scrollbar-color: var(--border-color, #ddd) var(--menu-bg, #fafafa); + transition: background-color 0.3s ease, border-color 0.3s ease; +} + +.api-nav::-webkit-scrollbar { + width: 8px; +} + +.api-nav::-webkit-scrollbar-track { + background: var(--menu-bg, #fafafa); +} + +.api-nav::-webkit-scrollbar-thumb { + background-color: var(--border-color, #ddd); + border-radius: 4px; +} + +.api-nav::-webkit-scrollbar-thumb:hover { + background-color: var(--text-muted, #777); } .api-nav .nav-item-title { @@ -24,7 +46,18 @@ } .api-nav a { - color: #777; + color: var(--text-muted, #777); + transition: color 0.2s ease; +} + +.api-nav a:hover { + color: var(--link-color, #0971B2); +} + +.api-nav a:focus-visible { + outline: 3px solid var(--focus-ring, #0971B2); + outline-offset: 2px; + border-radius: 2px; } .api-nav .nav-item-sub { @@ -54,12 +87,47 @@ margin-top: 3em; } +/* Responsive API navigation */ @media (max-width: 1785px) { .api-nav { display: none; } } +/* Tablet: Show API nav as collapsible sidebar */ +@media (min-width: 1400px) and (max-width: 1785px) { + .api-nav { + display: block; + left: auto; + right: 0; + width: 280px; + z-index: 10; + } +} + +/* Mobile: API nav as bottom sheet or hidden */ +@media (max-width: 1400px) { + .api-nav { + display: none; + } + + /* Optionally show as bottom sheet on mobile */ + .api-nav.mobile-open { + display: block; + position: fixed; + bottom: 0; + left: 0; + right: 0; + top: auto; + height: 50vh; + width: 100%; + border-left: none; + border-top: 1px solid var(--border-color, #ddd); + border-radius: 8px 8px 0 0; + box-shadow: 0 -2px 8px var(--shadow, rgba(0, 0, 0, 0.1)); + } +} + ul { margin-top: -10px; } @@ -166,4 +234,37 @@ hr.separate-api { .deprecated { color: #ff0000; + font-weight: 600; +} + +/* Accessibility improvements */ +.method-type:focus-visible, +.api-nav .nav-item-title:focus-visible { + outline: 3px solid var(--focus-ring, #0971B2); + outline-offset: 2px; + border-radius: 2px; +} + +/* Dark mode support for API page */ +@media (prefers-color-scheme: dark) { + .api-nav { + background-color: var(--menu-bg, #252525); + border-left-color: var(--border-color, #444); + } + + .api-nav a { + color: var(--text-muted, #888); + } + + .api-nav a:hover { + color: var(--link-color, #4a9eff); + } + + .native-ad { + background-color: var(--bg-secondary, #2d2d2d); + } + + .native-ad a { + color: var(--text-primary, #e0e0e0); + } } diff --git a/docs/css/github.css b/docs/css/github.css index f8cec1bdc3..d1d69d6f91 100644 --- a/docs/css/github.css +++ b/docs/css/github.css @@ -1,31 +1,45 @@ code { - background-color: #eee; - padding: 2px 4px; + background-color: var(--code-bg, #eee); + padding: 2px 6px; font-size: 0.9em; - color: #800; + color: var(--link-color, #800); border-radius: 4px; + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + transition: background-color 0.3s ease, color 0.3s ease; } pre code { background-color: transparent; padding: 0; font-size: 1em; - color: #222; + color: var(--code-text, #222); } pre { display: block; - padding: 9.5px; - margin: 10px 0 10px; + padding: 12px 16px; + margin: 16px 0; font-size: 13px; - line-height: 1.42857143; - color: #333; - word-break: break-all; - word-wrap: break-word; - background-color: #f5f5f5; - border: 1px solid #ccc; - border-radius: 4px; - font-family: Menlo,Monaco,Consolas,"Courier New",monospace; + line-height: 1.6; + color: var(--code-text, #333); + word-break: break-word; + overflow-wrap: break-word; + overflow-x: auto; + background-color: var(--code-bg, #f5f5f5); + border: 1px solid var(--border-color, #ccc); + border-radius: 6px; + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + box-shadow: 0 1px 3px var(--shadow, rgba(0, 0, 0, 0.1)); + transition: background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease; +} + +/* Enable absolute positioning for copy button and improve hover effect */ +pre { + position: relative; +} + +pre:hover { + box-shadow: 0 2px 6px var(--shadow, rgba(0, 0, 0, 0.15)); } /* @@ -38,9 +52,10 @@ github.com style (c) Vasily Polovnyov display: block; overflow-x: auto; padding: 0.5em; - color: #333; - background: #f8f8f8; + color: var(--code-text, #333); + background: var(--code-bg, #f8f8f8); -webkit-text-size-adjust: none; + transition: background-color 0.3s ease, color 0.3s ease; } .hljs-comment, @@ -152,3 +167,164 @@ github.com style (c) Vasily Polovnyov .hljs-chunk { color: #aaa; } + +/* Dark mode support for syntax highlighting */ +.code-theme-dark code { + background-color: var(--code-bg, #2d2d2d); + color: var(--link-color, #4a9eff); +} + +.code-theme-dark pre { + background-color: var(--code-bg, #2d2d2d); + border-color: var(--border-color, #444); + color: var(--code-text, #e0e0e0); +} + +.code-theme-dark .hljs { + background: var(--code-bg, #2d2d2d); + color: var(--code-text, #e0e0e0); +} + +.code-theme-dark .hljs-comment, +.code-theme-dark .diff .hljs-header, +.code-theme-dark .hljs-javadoc { + color: #6a9955; +} + +.code-theme-dark .hljs-keyword, +.code-theme-dark .css .rule .hljs-keyword, +.code-theme-dark .hljs-winutils, +.code-theme-dark .nginx .hljs-title, +.code-theme-dark .hljs-subst, +.code-theme-dark .hljs-request, +.code-theme-dark .hljs-status { + color: #569cd6; + font-weight: bold; +} + +.code-theme-dark .hljs-number, +.code-theme-dark .hljs-hexcolor, +.code-theme-dark .ruby .hljs-constant { + color: #b5cea8; +} + +.code-theme-dark .hljs-string, +.code-theme-dark .hljs-tag .hljs-value, +.code-theme-dark .hljs-phpdoc, +.code-theme-dark .hljs-dartdoc, +.code-theme-dark .tex .hljs-formula { + color: #ce9178; +} + +.code-theme-dark .hljs-title, +.code-theme-dark .hljs-id, +.code-theme-dark .scss .hljs-preprocessor { + color: #d7ba7d; + font-weight: bold; +} + +.code-theme-dark .hljs-class .hljs-title, +.code-theme-dark .hljs-type, +.code-theme-dark .vhdl .hljs-literal, +.code-theme-dark .tex .hljs-command { + color: #4ec9b0; + font-weight: bold; +} + +.code-theme-dark .hljs-tag, +.code-theme-dark .hljs-tag .hljs-title, +.code-theme-dark .hljs-rules .hljs-property, +.code-theme-dark .django .hljs-tag .hljs-keyword { + color: #569cd6; + font-weight: normal; +} + +.code-theme-dark .hljs-attribute, +.code-theme-dark .hljs-variable, +.code-theme-dark .lisp .hljs-body { + color: #9cdcfe; +} + +.code-theme-dark .hljs-regexp { + color: #d16969; +} + +.code-theme-dark .hljs-symbol, +.code-theme-dark .ruby .hljs-symbol .hljs-string, +.code-theme-dark .lisp .hljs-keyword, +.code-theme-dark .clojure .hljs-keyword, +.code-theme-dark .scheme .hljs-keyword, +.code-theme-dark .tex .hljs-special, +.code-theme-dark .hljs-prompt { + color: #c586c0; +} + +.code-theme-dark .hljs-built_in { + color: #4fc1ff; +} + +.code-theme-dark .hljs-preprocessor, +.code-theme-dark .hljs-pragma, +.code-theme-dark .hljs-pi, +.code-theme-dark .hljs-doctype, +.code-theme-dark .hljs-shebang, +.code-theme-dark .hljs-cdata { + color: #808080; + font-weight: bold; +} + +.code-theme-dark .hljs-deletion { + background: #5a1d1d; + color: #f48771; +} + +.code-theme-dark .hljs-addition { + background: #1e3a1e; + color: #b5cea8; +} + +.code-theme-dark .diff .hljs-change { + background: #2d4d2d; + color: #4ec9b0; +} + +.code-theme-dark .hljs-chunk { + color: #808080; +} + +/* Accessibility: Ensure sufficient contrast for code */ +code, +pre, +.hljs { + /* WCAG AA compliant contrast ratios */ + min-height: 1.5em; +} + +/* Improve code block readability on small screens */ +@media (max-width: 768px) { + pre { + font-size: 12px; + padding: 10px; + margin: 12px 0; + } + + code { + font-size: 0.85em; + padding: 2px 4px; + } +} + +/* Print styles for code blocks */ +@media print { + pre { + border: 1px solid #ccc; + page-break-inside: avoid; + background: #f5f5f5; + color: #000; + } + + code { + background: #f0f0f0; + color: #000; + } +} diff --git a/docs/css/mongoose5.css b/docs/css/mongoose5.css index 4ae64f50dd..71f26843bf 100644 --- a/docs/css/mongoose5.css +++ b/docs/css/mongoose5.css @@ -1,9 +1,97 @@ +/* CSS Custom Properties for Theming */ +:root { + /* Light mode colors */ + --bg-primary: #ffffff; + --bg-secondary: #eee; + --bg-tertiary: #fafafa; + --text-primary: #000000; + --text-secondary: #333333; + --text-muted: #777777; + --link-color: #0971B2; + --link-hover: #065a8f; + --border-color: #ddd; + --code-bg: #f5f5f5; + --code-text: #333; + --menu-bg: #eee; + --menu-hover: rgba(0, 0, 0, 0.1); + --menu-selected: rgba(0, 0, 0, 0.15); + --shadow: rgba(0, 0, 0, 0.1); + --focus-ring: #0971B2; + --focus-ring-width: 3px; +} + +/* Dark mode colors */ +@media (prefers-color-scheme: dark) { + :root:not([data-theme="light"]) { + --bg-primary: #1a1a1a; + --bg-secondary: #2d2d2d; + --bg-tertiary: #252525; + --text-primary: #e0e0e0; + --text-secondary: #c0c0c0; + --text-muted: #888888; + --link-color: #4a9eff; + --link-hover: #6bb3ff; + --border-color: #444444; + --code-bg: #2d2d2d; + --code-text: #e0e0e0; + --menu-bg: #252525; + --menu-hover: rgba(255,255,255, 0.1); + --menu-selected: rgba(255,255,255, 0.15); + --shadow: rgba(0, 0, 0, 0.3); + --focus-ring: #4a9eff; + } +} + +/* Manual dark mode override */ +[data-theme="dark"] { + --bg-primary: #1a1a1a; + --bg-secondary: #2d2d2d; + --bg-tertiary: #252525; + --text-primary: #e0e0e0; + --text-secondary: #c0c0c0; + --text-muted: #888888; + --link-color: #4a9eff; + --link-hover: #6bb3ff; + --border-color: #444444; + --code-bg: #2d2d2d; + --code-text: #e0e0e0; + --menu-bg: #252525; + --menu-hover: rgba(255,255,255, 0.1); + --menu-selected: rgba(255,255,255, 0.15); + --shadow: rgba(0, 0, 0, 0.3); + --focus-ring: #4a9eff; +} + +/* Light mode override */ +[data-theme="light"] { + --bg-primary: #ffffff; + --bg-secondary: #eee; + --bg-tertiary: #fafafa; + --text-primary: #000000; + --text-secondary: #333333; + --text-muted: #777777; + --link-color: #0971B2; + --link-hover: #065a8f; + --border-color: #ddd; + --code-bg: #f5f5f5; + --code-text: #333; + --menu-bg: #eee; + --menu-hover: rgba(0,0,0, 0.1); + --menu-selected: rgba(0,0,0, 0.15); + --shadow: rgba(0, 0, 0, 0.1); + --focus-ring: #0971B2; +} + html { font-family: 'Open Sans'; + color-scheme: light dark; } body { margin: 0; + background-color: var(--bg-primary); + color: var(--text-primary); + transition: background-color 0.3s ease, color 0.3s ease; } img { @@ -12,7 +100,19 @@ img { a { text-decoration: none; - color: #0971B2; + color: var(--link-color); + transition: color 0.2s ease, opacity 0.2s ease; +} + +a:hover { + color: var(--link-hover); + opacity: 0.9; +} + +a:focus-visible { + outline: var(--focus-ring-width) solid var(--focus-ring); + outline-offset: 2px; + border-radius: 2px; } p { @@ -51,7 +151,16 @@ h1 a, h2 a, h3 a, h4 a { - color: #000; + color: var(--text-primary); +} + +h1 a:focus-visible, +h2 a:focus-visible, +h3 a:focus-visible, +h4 a:focus-visible { + outline: var(--focus-ring-width) solid var(--focus-ring); + outline-offset: 2px; + border-radius: 2px; } #logo { @@ -86,8 +195,19 @@ h4 a { padding-bottom: 0px; } -.pure-menu-link:hover, .pure-menu-link.selected { - background-color: rgba(0,0,0, 0.1); +.pure-menu-link:hover, +.pure-menu-link.selected { + background-color: var(--menu-hover); +} + +.pure-menu-link:focus-visible { + outline: var(--focus-ring-width) solid var(--focus-ring); + outline-offset: -2px; + border-radius: 2px; +} + +.pure-menu-link.selected { + background-color: var(--menu-selected); } li.sub-item { @@ -96,18 +216,18 @@ li.sub-item { } li.version { - border-bottom: 1px solid #ddd; + border-bottom: 1px solid var(--border-color); padding-bottom: 4px; } li.version ul.pure-menu-children { - border: 1px solid #ddd; + border: 1px solid var(--border-color); } #logo-container { padding-top: 0; padding-bottom: 6px; - border-bottom: 1px solid #ddd; + border-bottom: 1px solid var(--border-color); } #logo-container > a { @@ -120,10 +240,29 @@ li.version ul.pure-menu-children { top: 0; left: 0; bottom: 0px; - background-color: #eee; + background-color: var(--menu-bg); width: 250px; - border-right: 1px solid #ddd; + border-right: 1px solid var(--border-color); overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: var(--border-color) var(--menu-bg); +} + +#menu::-webkit-scrollbar { + width: 8px; +} + +#menu::-webkit-scrollbar-track { + background: var(--menu-bg); +} + +#menu::-webkit-scrollbar-thumb { + background-color: var(--border-color); + border-radius: 4px; +} + +#menu::-webkit-scrollbar-thumb:hover { + background-color: var(--text-muted); } .container { @@ -143,11 +282,26 @@ li.version ul.pure-menu-children { } .search input { - border: 1px solid #ddd; + border: 1px solid var(--border-color); padding: 0.25em; width: 170px; border-radius: 3px; flex: 1; + background-color: var(--bg-primary); + color: var(--text-primary); + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.search input:focus { + outline: none; + border-color: var(--focus-ring); + box-shadow: 0 0 0 2px rgba(9, 113, 178, 0.1); +} + +@media (prefers-color-scheme: dark) { + .search input:focus { + box-shadow: 0 0 0 2px rgba(74, 158, 255, 0.2); + } } #search-input-nav { @@ -155,14 +309,29 @@ li.version ul.pure-menu-children { } .search button { - background-color: #777; - color: white; + background-color: var(--text-muted); + color: var(--bg-primary); border: 1px solid transparent; border-radius: 3px; height: 30px; width: 30px; padding: 0px; flex: 0 0 auto; + cursor: pointer; + transition: background-color 0.2s ease, transform 0.1s ease; +} + +.search button:hover { + background-color: var(--text-secondary); +} + +.search button:active { + transform: scale(0.95); +} + +.search button:focus-visible { + outline: var(--focus-ring-width) solid var(--focus-ring); + outline-offset: 2px; } #search-button-nav { @@ -179,11 +348,21 @@ li.version ul.pure-menu-children { position: absolute; top: 0.125em; right: 0px; - background-color: #fafafa; - border: 1px solid #ddd; + background-color: var(--bg-tertiary); + border: 1px solid var(--border-color); padding: 5px; padding-bottom: 0px; border-radius: 3px; + transition: background-color 0.2s ease, border-color 0.2s ease; +} + +.edit-docs-link:hover { + background-color: var(--bg-secondary); +} + +.edit-docs-link:focus-visible { + outline: var(--focus-ring-width) solid var(--focus-ring); + outline-offset: 2px; } .edit-docs-link img { @@ -204,6 +383,14 @@ li.version ul.pure-menu-children { display: none; } +/* Improved responsive breakpoints */ +@media (max-width: 1400px) { + .container { + width: calc(100% - 300px); + max-width: 900px; + } +} + @media (max-width: 1160px) { h2:hover::before, h3:hover::before { position: static; @@ -226,10 +413,12 @@ li.version ul.pure-menu-children { display: none; position: fixed; top: 45px; - border-top: 1px solid #ddd; - border-right: 1px solid #ddd; - border-bottom: 1px solid #ddd; + border-top: 1px solid var(--border-color); + border-right: 1px solid var(--border-color); + border-bottom: 1px solid var(--border-color); left: 0px; + max-height: calc(100vh - 45px); + box-shadow: 2px 0 8px var(--shadow); } pre { @@ -238,13 +427,15 @@ li.version ul.pure-menu-children { } #mobile-menu { - display: block; + display: flex; + align-items: center; height: 45px; - background-color: #eee; - border-bottom: 1px solid #ddd; + background-color: var(--menu-bg); + border-bottom: 1px solid var(--border-color); position: sticky; top: 0; - z-index: 1; + z-index: 100; + box-shadow: 0 2px 4px var(--shadow); } #logo { @@ -259,6 +450,21 @@ li.version ul.pure-menu-children { width: 215px; margin-left: auto; margin-right: auto; + display: flex; + align-items: center; + justify-content: center; + } + + #mobile-logo-container a { + display: flex; + align-items: center; + text-decoration: none; + } + + #mobile-logo-container a:focus-visible { + outline: var(--focus-ring-width) solid var(--focus-ring); + outline-offset: 2px; + border-radius: 2px; } #logo-container { @@ -267,26 +473,44 @@ li.version ul.pure-menu-children { .menu-link { position: absolute; - display: block; + display: flex; + align-items: center; + justify-content: center; top: 0px; left: 0; - background-color: #eee; + background-color: transparent; z-index: 10; - width: 2em; - height: 3px; - padding: 2.1em 1.6em; + width: 45px; + height: 45px; + padding: 0; + border: none; + cursor: pointer; + transition: background-color 0.2s ease; + } + + .menu-link:hover { + background-color: var(--menu-hover); } - .menu-link:hover, - .menu-link:focus { - background: #ddd; + .menu-link:focus-visible { + outline: var(--focus-ring-width) solid var(--focus-ring); + outline-offset: -2px; + background-color: var(--menu-hover); } #menuLink { width: 40px; height: 40px; - padding: 2.5px; - color: rgb(0,0,0); + padding: 8px; + color: var(--text-primary); + display: flex; + align-items: center; + justify-content: center; + } + + #menuLink svg { + width: 100%; + height: 100%; } .active { @@ -371,3 +595,164 @@ li.version ul.pure-menu-children { display: none !important; } } + +/* Print stylesheet improvements */ +@media print { + #menu, + #mobile-menu, + .edit-docs-link, + #jobs, + .cpc-ad, + .api-nav { + display: none !important; + } + + .container { + left: 0 !important; + width: 100% !important; + padding: 0 !important; + margin: 0 !important; + } + + body { + background: white; + color: black; + } + + a { + color: #000; + text-decoration: underline; + } + + a[href^="http"]:after { + content: " (" attr(href) ")"; + font-size: 0.8em; + color: #666; + } + + pre { + border: 1px solid #ccc; + page-break-inside: avoid; + } + + h1, h2, h3, h4, h5, h6 { + page-break-after: avoid; + } + + img { + max-width: 100% !important; + page-break-inside: avoid; + } +} + +/* Tablet breakpoint */ +@media (min-width: 768px) and (max-width: 1160px) { + .container { + padding-left: 30px; + padding-right: 30px; + } +} + +/* Small mobile devices */ +@media (max-width: 480px) { + .container { + padding-left: 15px; + padding-right: 15px; + } + + #content { + margin: 5px; + } + + #mobile-logo-container { + width: 180px; + } + + .logo-text { + font-size: 16pt; + } +} + +/* Theme Toggle Button */ +#theme-toggle { + position: fixed; + top: 20px; + right: 20px; + z-index: 1000; + background-color: var(--bg-secondary); + border: 1px solid var(--border-color); + border-radius: 50%; + box-shadow: 0 2px 8px var(--shadow); + transition: background-color 0.3s ease, border-color 0.3s ease; +} + +#theme-toggle-btn { + width: 44px; + height: 44px; + padding: 0; + margin: 0; + border: none; + background: transparent; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + color: var(--text-primary); + transition: background-color 0.2s ease, transform 0.1s ease; +} + +#theme-toggle-btn:hover { + background-color: var(--menu-hover); +} + +#theme-toggle-btn:active { + transform: scale(0.95); +} + +#theme-toggle-btn:focus-visible { + outline: var(--focus-ring-width) solid var(--focus-ring); + outline-offset: 2px; +} + +#theme-icon-light, +#theme-icon-dark { + position: absolute; + transition: opacity 0.3s ease, transform 0.3s ease; + width: 20px; + height: 20px; +} + +/* Default: show moon icon (for light/system mode) */ +#theme-icon-dark { + opacity: 1; + transform: rotate(0deg); +} + +#theme-icon-light { + opacity: 0; + transform: rotate(90deg); + pointer-events: none; +} + +/* In dark mode: show sun icon, hide moon icon */ +[data-theme="dark"] #theme-icon-light { + opacity: 1; + transform: rotate(0deg); + pointer-events: auto; +} + +[data-theme="dark"] #theme-icon-dark { + opacity: 0; + transform: rotate(90deg); + pointer-events: none; +} + +/* On mobile, adjust position */ +@media (max-width: 1160px) { + #theme-toggle { + top: auto; + bottom: 15px; + right: 15px; + } +} diff --git a/docs/css/style.css b/docs/css/style.css index 32edaaea47..ae06f764ea 100644 --- a/docs/css/style.css +++ b/docs/css/style.css @@ -1,10 +1,123 @@ body { font-family: 'Open Sans', Helvetica, Arial, FreeSans; - color: #333; + color: var(--text-secondary, #333); -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: 100%; padding: 0; margin: 0; + background-color: var(--bg-primary, #ffffff); + transition: background-color 0.3s ease, color 0.3s ease; +} + +/* Dark mode support for homepage */ +@media (prefers-color-scheme: dark) { + body:not([data-theme="light"]) { + background-color: var(--bg-primary, #1a1a1a); + color: var(--text-secondary, #c0c0c0); + } +} + +/* Manual theme overrides */ +[data-theme="dark"] { + background-color: var(--bg-primary, #1a1a1a); + color: var(--text-secondary, #c0c0c0); +} + +[data-theme="light"] { + background-color: var(--bg-primary, #ffffff); + color: var(--text-secondary, #333); +} + +/* Theme Toggle Button for Homepage */ +#theme-toggle { + position: fixed; + bottom: 20px; + right: 20px; + z-index: 1000; + background-color: rgba(255, 255, 255, 0.9); + border: 1px solid #ddd; + border-radius: 50%; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + transition: background-color 0.3s ease, border-color 0.3s ease; +} + +[data-theme="dark"] #theme-toggle { + background-color: rgba(26, 26, 26, 0.9); + border-color: #444; +} + +#theme-toggle-btn { + width: 44px; + height: 44px; + padding: 0; + margin: 0; + border: none; + background: transparent; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + color: #333; + transition: background-color 0.2s ease, transform 0.1s ease; +} + +body[data-theme="dark"] #theme-toggle-btn { + color: #e0e0e0; +} + +#theme-toggle-btn:hover { + background-color: rgba(0, 0, 0, 0.1); +} + +body[data-theme="dark"] #theme-toggle-btn:hover { + background-color: rgba(255, 255, 255, 0.1); +} + +#theme-toggle-btn:active { + transform: scale(0.95); +} + +#theme-toggle-btn:focus-visible { + outline: 3px solid #0971B2; + outline-offset: 2px; +} + +body[data-theme="dark"] #theme-toggle-btn:focus-visible { + outline-color: #4a9eff; +} + +#theme-icon-light, +#theme-icon-dark { + position: absolute; + transition: opacity 0.3s ease, transform 0.3s ease; + width: 20px; + height: 20px; +} + +/* Default: show moon icon (for light/system mode) */ +#theme-icon-dark { + opacity: 1; + transform: rotate(0deg); +} + +#theme-icon-light { + opacity: 0; + transform: rotate(90deg); + pointer-events: none; +} + +/* In dark mode: show sun icon, hide moon icon */ +[data-theme="dark"] #theme-icon-light { + opacity: 1; + transform: rotate(0deg); + pointer-events: auto; +} + +[data-theme="dark"] #theme-icon-dark { + opacity: 0; + transform: rotate(90deg); + pointer-events: none; } /* location.hash */ @@ -21,14 +134,20 @@ body { } a { - color: #800; + color: var(--link-color, #800); -webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow; -webkit-transition-duration: 0.15s; -webkit-transition-timing-function: ease-out; + transition: opacity 0.15s ease-out, color 0.15s ease-out; } a:hover { opacity: 0.8; } +a:focus-visible { + outline: 3px solid var(--focus-ring, #0971B2); + outline-offset: 2px; + border-radius: 2px; +} #wrap { width: 600px; margin: 0 auto; @@ -43,20 +162,36 @@ h1 { } pre { - background: #eee; - padding: 5px; - border-radius: 3px; + background: var(--code-bg, #eee); + padding: 12px 16px; + border-radius: 6px; overflow-x: auto; + border: 1px solid var(--border-color, #ddd); + transition: background-color 0.3s ease, border-color 0.3s ease; } code { - color: #333; + color: var(--code-text, #333); font-size: 11px; font-family: Consolas, "Liberation Mono", Courier, monospace; + background-color: var(--code-bg, #eee); + padding: 2px 6px; + border-radius: 4px; } pre code { border: 0 none; padding: 1.2em; overflow-x: auto; + background-color: transparent; +} + +/* Dark mode for homepage code blocks */ +[data-theme="dark"] pre { + background: var(--code-bg, #2d2d2d); + border-color: var(--border-color, #444); +} +[data-theme="dark"] code { + color: var(--code-text, #e0e0e0); + background-color: var(--code-bg, #2d2d2d); } #header { text-align: center; @@ -83,6 +218,7 @@ h2 a { font-size: 146px; font-weight: 100; text-indent: -23px; + color: #800; } .load #header .mongoose { letter-spacing: -14px; @@ -94,6 +230,10 @@ h2 a { text-align: center; margin: 7px 0; } +[data-theme="dark"] .tagline { + color: #f8f8f8; + text-shadow: 1px 1px #222; +} .blurb { text-align: center; font-style: oblique; @@ -116,7 +256,6 @@ h2 a { #links li { display: inline-block; margin: 0 15px; - background-color: #FEFEFE; } #links a { background: #444; diff --git a/docs/js/theme-toggle.js b/docs/js/theme-toggle.js new file mode 100644 index 0000000000..1fb347e045 --- /dev/null +++ b/docs/js/theme-toggle.js @@ -0,0 +1,36 @@ +(function() { + 'use strict'; + + const STORAGE_KEY = 'mongoose-theme'; + const CODE_THEME_CLASS = 'code-theme-dark'; + const supportsMatchMedia = typeof window !== 'undefined' && typeof window.matchMedia === 'function'; + const prefersDarkQuery = supportsMatchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null; + + function toggleTheme() { + const currentTheme = document.documentElement.getAttribute('data-theme'); + if (currentTheme === 'dark') { + applyTheme('light'); + } else { + applyTheme('dark'); + } + } + + function applyTheme(theme, skipSetStorage) { + document.documentElement.setAttribute('data-theme', theme); + if (!skipSetStorage) { + try { + localStorage.setItem(STORAGE_KEY, theme); + } catch (e) { + // Silently fail - theme will still work for current session + } + } + const isDark = theme === 'dark'; + document.documentElement.classList.toggle(CODE_THEME_CLASS, isDark); + document.body.classList.toggle(CODE_THEME_CLASS, isDark); + } + + const theme = localStorage.getItem(STORAGE_KEY) || (prefersDarkQuery?.matches ? 'dark' : 'light'); + applyTheme(theme, true); + const toggleBtn = document.getElementById('theme-toggle-btn'); + toggleBtn.addEventListener('click', toggleTheme); +})(); diff --git a/docs/layout.pug b/docs/layout.pug index 34fd4081db..b9a39c233f 100644 --- a/docs/layout.pug +++ b/docs/layout.pug @@ -10,8 +10,8 @@ html(lang='en') link(rel="stylesheet", href="https://unpkg.com/purecss@1.0.1/build/pure-min.css", integrity="sha384-oAOxQR6DkCoMliIh8yFnu25d7Eq/PHS21PClpwjOTeU2jRSq11vu66rf90/cZr47", crossorigin="anonymous") link(rel="stylesheet", href="https://fonts.googleapis.com/css?family=Open+Sans") - link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/github.css`) - link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/mongoose5.css`) + 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/carbonads.css`) link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/copy-code.css`) @@ -23,6 +23,10 @@ html(lang='en') body block layout #layout + #theme-toggle + button#theme-toggle-btn(aria-label="Toggle dark mode" title="Toggle dark/light theme") + + #mobile-menu a#menuLink.menu-link(href='#menu') @@ -174,5 +178,6 @@ html(lang='en') script(type="text/javascript" src=`${versions.versionedPath}/docs/js/navbar-search.js`) script(type="text/javascript" src=`${versions.versionedPath}/docs/js/mobile-navbar-toggle.js`) + script(type="text/javascript" src=`${versions.versionedPath}/docs/js/theme-toggle.js`) script(type="text/javascript" src=`${versions.versionedPath}/docs/js/copy-code.js`) diff --git a/index.pug b/index.pug index 14cba69a0f..b0fd5bffcf 100644 --- a/index.pug +++ b/index.pug @@ -5,6 +5,7 @@ html(lang='en') meta(name="viewport", content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no") title Mongoose ODM v#{package.version} link(href="//fonts.googleapis.com/css?family=Anonymous+Pro:400,700|Droid+Sans+Mono|Open+Sans:400,700|Linden+Hill|Quattrocento:400,700|News+Cycle:400,700|Antic+Slab|Cabin+Condensed:400,700", rel="stylesheet", type="text/css") + link(href="docs/css/mongoose5.css", rel="stylesheet") link(href="docs/css/style.css", rel="stylesheet") link(href="docs/css/github.css", rel="stylesheet") link(href="docs/css/carbonads.css", rel="stylesheet") @@ -45,6 +46,10 @@ html(lang='en') } body + #theme-toggle + button#theme-toggle-btn(aria-label="Toggle dark mode" title="Toggle dark/light theme") + + a(class="github-fork-ribbon" href="https://github.com/Automattic/mongoose" data-ribbon="Fork me on GitHub" title="Fork me on GitHub" target="_blank"). Fork me on GitHub #wrap.homepage @@ -153,5 +158,6 @@ html(lang='en') Sponsor [Mongoose on OpenCollective](https://opencollective.com/mongoose) to get your company's logo above! p#footer Licensed under MIT. + script(src="docs/js/theme-toggle.js") script. document.body.className = 'load';