Copilot commented on code in PR #147: URL: https://github.com/apache/datafusion-site/pull/147#discussion_r2768783432
########## _typos.toml: ########## @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Configuration for typos spell checker +# https://github.com/crate-ci/typos + +# Custom dictionary for technical terms +[default.extend-words] +# Add any false positives here if needed Review Comment: There is a trailing space at the end of this comment line. Remove the trailing space to maintain clean code formatting. ```suggestion # Add any false positives here if needed ``` ########## .github/workflows/typo-check.yml: ########## @@ -0,0 +1,36 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: Typo Check + +on: + push: + branches: + - main + pull_request: + +jobs: + typos: + name: Spell Check with Typos + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 Review Comment: The version v5.0.0 of actions/checkout should be verified. As of January 2025, the latest major version was v4. If v5 has been released since then, this is correct. However, for consistency with other workflows in this repository (publish-site.yml and stage-site.yml), consider using the same version notation style. The other workflows use @v4 instead of pinned hashes. If pinned hashes are preferred for security, consider updating the other workflows as well for consistency. ########## content/theme/templates/menu.html: ########## @@ -15,6 +15,10 @@ <a class="nav-link" href="/blog/feed.xml">RSS</a> </li> </ul> + <button id="theme-toggle" class="theme-toggle" aria-label="Toggle dark mode" title="Toggle dark mode"> + <span class="icon-sun">☀️</span> + <span class="icon-moon">🌙</span> Review Comment: Using emoji characters (☀️ and 🌙) for the toggle icons may cause inconsistent rendering across different browsers and operating systems. Consider using SVG icons or icon fonts (like the FontAwesome already included in the project) for more consistent cross-platform appearance and better control over styling. Additionally, the emoji may be announced by screen readers, which could be confusing since the button already has an aria-label. ```suggestion <i class="icon-sun fa-regular fa-sun" aria-hidden="true"></i> <i class="icon-moon fa-regular fa-moon" aria-hidden="true"></i> ``` ########## content/css/darkmode.css: ########## @@ -0,0 +1,673 @@ +/* Dark Mode Styles for Apache DataFusion Blog */ + +/* Root variables for light mode (default) */ +:root { + --bg-primary: #ffffff; + --bg-secondary: #f8f9fa; + --bg-tertiary: #e9ecef; + --text-primary: #212529; + --text-secondary: #6c757d; + --text-muted: #868e96; + --border-color: #dee2e6; + --callout-bg: #f8f9fa; + --code-bg: #f8f9fa; + --link-color: #0d6efd; + --link-hover: #0a58ca; + --toc-border: #eee; + --shadow: rgba(0, 0, 0, 0.1); + --accent-color: #0d6efd; +} + +/* Dark mode variables - Modern, high contrast palette */ +[data-theme="dark"] { + --bg-primary: #0d1117; + --bg-secondary: #161b22; + --bg-tertiary: #1c2128; + --text-primary: #e6edf3; + --text-secondary: #8b949e; + --text-muted: #6e7681; + --border-color: #30363d; + --callout-bg: #161b22; + --code-bg: #0d1117; + --link-color: #58a6ff; + --link-hover: #79c0ff; + --toc-border: #30363d; + --shadow: rgba(0, 0, 0, 0.5); + --accent-color: #58a6ff; +} + +/* Apply dark mode styles */ +[data-theme="dark"] body { + background-color: var(--bg-primary); + color: var(--text-primary); +} + +/* Main content areas */ +[data-theme="dark"] .bg-white { + background-color: var(--bg-primary) !important; +} + +[data-theme="dark"] .bg-light { + background-color: var(--bg-secondary) !important; +} + +[data-theme="dark"] #contents { + background-color: var(--bg-primary); + color: var(--text-primary); +} + +[data-theme="dark"] #contents > .bg-white { + background-color: var(--bg-secondary) !important; + border: 1px solid var(--border-color); +} + +/* Callout boxes - prominent styling */ +[data-theme="dark"] .callout { + background-color: var(--bg-tertiary); + border: 1px solid var(--border-color); + border-left: 4px solid var(--accent-color); + padding: 1.5rem; + margin: 1rem 0; + border-radius: 8px; + box-shadow: 0 2px 8px var(--shadow); +} + +[data-theme="dark"] .post { + background-color: transparent; +} + +[data-theme="dark"] .post header { + border-bottom: 1px solid var(--border-color); + padding-bottom: 1rem; + margin-bottom: 1rem; +} + +/* Table of Contents */ +[data-theme="dark"] .toc { + background-color: var(--bg-tertiary); + border: 1px solid var(--border-color); + color: var(--text-primary); + border-radius: 8px; +} + +[data-theme="dark"] .toc a { + color: var(--text-secondary); +} + +[data-theme="dark"] .toc a:hover { + color: var(--link-color); +} + +/* Links */ +[data-theme="dark"] a { + color: var(--link-color); + text-decoration: none; +} + +[data-theme="dark"] a:hover { + color: var(--link-hover); + text-decoration: underline; +} + +/* Code blocks and inline code */ +[data-theme="dark"] code { + background-color: var(--bg-tertiary); + color: #ff7b72; + padding: 0.2em 0.4em; + border-radius: 4px; + font-size: 0.9em; +} + +[data-theme="dark"] pre { + background-color: var(--code-bg); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 1rem; + overflow-x: auto; +} + +[data-theme="dark"] pre code { + background-color: transparent; + color: var(--text-primary); + padding: 0; +} + +/* Tables */ +[data-theme="dark"] .table { + color: var(--text-primary); + border-color: var(--border-color); +} + +[data-theme="dark"] .table-striped > tbody > tr:nth-of-type(odd) > * { + background-color: var(--bg-tertiary); + color: var(--text-primary); +} + +[data-theme="dark"] .table > :not(caption) > * > * { + background-color: transparent; + border-bottom-color: var(--border-color); + color: var(--text-primary); +} + +[data-theme="dark"] .table > thead { + border-bottom: 2px solid var(--border-color); +} + +/* Blockquotes */ +[data-theme="dark"] blockquote { + border-left: 4px solid var(--accent-color); + padding-left: 1rem; + margin-left: 0; + color: var(--text-secondary); + background-color: var(--bg-tertiary); + padding: 1rem; + border-radius: 4px; +} + +/* Horizontal rules */ +[data-theme="dark"] hr { + border-color: var(--border-color); + opacity: 0.5; +} + +/* Buttons - comprehensive styling */ +[data-theme="dark"] button, +[data-theme="dark"] .button, +[data-theme="dark"] a.button { + background-color: var(--accent-color); + color: #ffffff; + border: 1px solid var(--accent-color); + padding: 0.5rem 1.25rem; + border-radius: 6px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + text-decoration: none; + display: inline-block; +} + +[data-theme="dark"] button:hover, +[data-theme="dark"] .button:hover, +[data-theme="dark"] a.button:hover { + background-color: var(--link-hover); + border-color: var(--link-hover); + color: #ffffff; + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(88, 166, 255, 0.3); + text-decoration: none; +} + +[data-theme="dark"] button:active, +[data-theme="dark"] .button:active, +[data-theme="dark"] a.button:active { + transform: translateY(0); +} + +/* Comment buttons specific styling */ +[data-theme="dark"] #giscus-load, +[data-theme="dark"] #giscus-revoke { + background-color: var(--bg-tertiary); + color: var(--text-primary); + border: 1px solid var(--border-color); +} + +[data-theme="dark"] #giscus-load:hover, +[data-theme="dark"] #giscus-revoke:hover { + background-color: var(--accent-color); + border-color: var(--accent-color); + color: #ffffff; +} + +/* Cards and list items */ +[data-theme="dark"] .card { + background-color: var(--bg-tertiary); + border: 1px solid var(--border-color); + color: var(--text-primary); +} + +[data-theme="dark"] .list-group-item { + background-color: var(--bg-tertiary); + border: 1px solid var(--border-color); + color: var(--text-primary); +} + +[data-theme="dark"] .list-group-item:hover { + background-color: var(--bg-secondary); +} + +/* Post titles and article content */ +[data-theme="dark"] .post header .title h1 a { + color: var(--text-primary); + font-weight: 600; +} + +[data-theme="dark"] .post header .title h1 a:hover { + color: var(--link-hover); + text-decoration: none; +} + +[data-theme="dark"] .post header p { + color: var(--text-secondary); +} + +[data-theme="dark"] article { + color: var(--text-primary); +} + +/* Headings */ +[data-theme="dark"] h1, +[data-theme="dark"] h2, +[data-theme="dark"] h3, +[data-theme="dark"] h4, +[data-theme="dark"] h5, +[data-theme="dark"] h6 { + color: var(--text-primary); + font-weight: 600; +} + +[data-theme="dark"] h1 { + border-bottom: 2px solid var(--border-color); + padding-bottom: 0.5rem; +} + +[data-theme="dark"] p { + color: var(--text-primary); +} + +/* Lists */ +[data-theme="dark"] ul, +[data-theme="dark"] ol { + color: var(--text-primary); +} + +[data-theme="dark"] li { + color: var(--text-primary); +} + +/* Stats and tags */ +[data-theme="dark"] .stats li { + color: var(--text-secondary); +} + +[data-theme="dark"] .stats li a { + color: var(--text-secondary); + background-color: var(--bg-tertiary); + padding: 0.25rem 0.75rem; + border-radius: 12px; + border: 1px solid var(--border-color); +} + +[data-theme="dark"] .stats li a:hover { + color: var(--link-hover); + border-color: var(--accent-color); + text-decoration: none; +} + +/* Navbar - ensure it looks good in dark mode */ +[data-theme="dark"] .navbar-dark { + background-color: #0d1117 !important; + border-bottom: 1px solid var(--border-color); +} + +[data-theme="dark"] .navbar-brand { + color: var(--text-primary) !important; +} + +[data-theme="dark"] .nav-link { + color: var(--text-secondary) !important; +} + +[data-theme="dark"] .nav-link:hover { + color: var(--link-color) !important; +} + +/* Footer adjustments */ +[data-theme="dark"] footer, +[data-theme="dark"] .row.g-0 { + color: var(--text-secondary); +} + +[data-theme="dark"] footer a { + color: var(--link-color); +} + +/* Image adjustments for dark mode */ +[data-theme="dark"] img:not([src*="logo"]) { + opacity: 0.9; + border-radius: 4px; +} + +[data-theme="dark"] img:not([src*="logo"]):hover { + opacity: 1; +} + +/* Forms and inputs */ +[data-theme="dark"] input, +[data-theme="dark"] textarea, +[data-theme="dark"] select { + background-color: var(--bg-tertiary); + border-color: var(--border-color); + color: var(--text-primary); +} + +[data-theme="dark"] input:focus, +[data-theme="dark"] textarea:focus, +[data-theme="dark"] select:focus { + background-color: var(--bg-secondary); + border-color: var(--accent-color); + outline: none; + box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.1); +} + +/* Kbd styling */ +[data-theme="dark"] kbd { + background-color: var(--bg-tertiary); + border: 1px solid var(--border-color); + color: var(--text-primary); +} + +/* Figure caption */ +[data-theme="dark"] figcaption { + color: var(--text-secondary); +} + +/* Mark/highlight */ +[data-theme="dark"] mark { + background-color: #ffc10726; + color: var(--text-primary); +} + +/* Scrollbar styling for dark mode */ +[data-theme="dark"] ::-webkit-scrollbar { + width: 12px; + height: 12px; +} + +[data-theme="dark"] ::-webkit-scrollbar-track { + background: var(--bg-secondary); +} + +[data-theme="dark"] ::-webkit-scrollbar-thumb { + background: var(--border-color); + border-radius: 6px; +} + +[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { + background: var(--text-muted); +} Review Comment: Add a blank line before this comment for better readability and consistency with the rest of the CSS file structure. ```suggestion } ``` ########## content/js/darkmode.js: ########## @@ -0,0 +1,93 @@ +/** + * Dark Mode Toggle Functionality for Apache DataFusion Blog + */ + +(function() { + 'use strict'; + + // Constants + const THEME_KEY = 'datafusion-theme'; + const THEME_DARK = 'dark'; + const THEME_LIGHT = 'light'; + + /** + * Get the current theme from localStorage or system preference + */ + function getStoredTheme() { + return localStorage.getItem(THEME_KEY); + } + + /** + * Get the preferred theme based on system settings + */ + function getPreferredTheme() { + const storedTheme = getStoredTheme(); + if (storedTheme) { + return storedTheme; + } + // Check system preference + return window.matchMedia('(prefers-color-scheme: dark)').matches ? THEME_DARK : THEME_LIGHT; + } + + /** + * Set the theme on the document + */ + function setTheme(theme) { + if (theme === THEME_DARK) { + document.documentElement.setAttribute('data-theme', THEME_DARK); + } else { + document.documentElement.removeAttribute('data-theme'); + } + localStorage.setItem(THEME_KEY, theme); + } + + /** + * Toggle between light and dark themes + */ + function toggleTheme() { + const currentTheme = getStoredTheme() || THEME_LIGHT; + const newTheme = currentTheme === THEME_DARK ? THEME_LIGHT : THEME_DARK; + setTheme(newTheme); + } + + /** + * Initialize theme on page load + */ + function initTheme() { + // Apply theme immediately to prevent flash + setTheme(getPreferredTheme()); + + // Add event listener to toggle button when DOM is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', attachToggleListener); + } else { + attachToggleListener(); + } + } + + /** + * Attach click event listener to theme toggle button + */ + function attachToggleListener() { + const toggleButton = document.getElementById('theme-toggle'); + if (toggleButton) { + toggleButton.addEventListener('click', function(e) { + e.preventDefault(); + toggleTheme(); + }); Review Comment: The theme toggle button should indicate its current state for screen reader users. Consider updating the aria-label dynamically to indicate the current state (e.g., "Enable dark mode" vs "Enable light mode") or add an aria-pressed attribute that is toggled when the theme changes. This would improve accessibility by letting screen reader users know the current theme state and what clicking the button will do. ########## content/css/darkmode.css: ########## @@ -0,0 +1,673 @@ +/* Dark Mode Styles for Apache DataFusion Blog */ + +/* Root variables for light mode (default) */ +:root { + --bg-primary: #ffffff; + --bg-secondary: #f8f9fa; + --bg-tertiary: #e9ecef; + --text-primary: #212529; + --text-secondary: #6c757d; + --text-muted: #868e96; + --border-color: #dee2e6; + --callout-bg: #f8f9fa; + --code-bg: #f8f9fa; + --link-color: #0d6efd; + --link-hover: #0a58ca; + --toc-border: #eee; + --shadow: rgba(0, 0, 0, 0.1); + --accent-color: #0d6efd; +} + +/* Dark mode variables - Modern, high contrast palette */ +[data-theme="dark"] { + --bg-primary: #0d1117; + --bg-secondary: #161b22; + --bg-tertiary: #1c2128; + --text-primary: #e6edf3; + --text-secondary: #8b949e; + --text-muted: #6e7681; + --border-color: #30363d; + --callout-bg: #161b22; + --code-bg: #0d1117; + --link-color: #58a6ff; + --link-hover: #79c0ff; + --toc-border: #30363d; + --shadow: rgba(0, 0, 0, 0.5); + --accent-color: #58a6ff; +} + +/* Apply dark mode styles */ +[data-theme="dark"] body { + background-color: var(--bg-primary); + color: var(--text-primary); +} + +/* Main content areas */ +[data-theme="dark"] .bg-white { + background-color: var(--bg-primary) !important; +} + +[data-theme="dark"] .bg-light { + background-color: var(--bg-secondary) !important; +} + +[data-theme="dark"] #contents { + background-color: var(--bg-primary); + color: var(--text-primary); +} + +[data-theme="dark"] #contents > .bg-white { + background-color: var(--bg-secondary) !important; + border: 1px solid var(--border-color); +} + +/* Callout boxes - prominent styling */ +[data-theme="dark"] .callout { + background-color: var(--bg-tertiary); + border: 1px solid var(--border-color); + border-left: 4px solid var(--accent-color); + padding: 1.5rem; + margin: 1rem 0; + border-radius: 8px; + box-shadow: 0 2px 8px var(--shadow); +} + +[data-theme="dark"] .post { + background-color: transparent; +} + +[data-theme="dark"] .post header { + border-bottom: 1px solid var(--border-color); + padding-bottom: 1rem; + margin-bottom: 1rem; +} + +/* Table of Contents */ +[data-theme="dark"] .toc { + background-color: var(--bg-tertiary); + border: 1px solid var(--border-color); + color: var(--text-primary); + border-radius: 8px; +} + +[data-theme="dark"] .toc a { + color: var(--text-secondary); +} + +[data-theme="dark"] .toc a:hover { + color: var(--link-color); +} + +/* Links */ +[data-theme="dark"] a { + color: var(--link-color); + text-decoration: none; +} + +[data-theme="dark"] a:hover { + color: var(--link-hover); + text-decoration: underline; +} + +/* Code blocks and inline code */ +[data-theme="dark"] code { + background-color: var(--bg-tertiary); + color: #ff7b72; + padding: 0.2em 0.4em; + border-radius: 4px; + font-size: 0.9em; +} + +[data-theme="dark"] pre { + background-color: var(--code-bg); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 1rem; + overflow-x: auto; +} + +[data-theme="dark"] pre code { + background-color: transparent; + color: var(--text-primary); + padding: 0; +} + +/* Tables */ +[data-theme="dark"] .table { + color: var(--text-primary); + border-color: var(--border-color); +} + +[data-theme="dark"] .table-striped > tbody > tr:nth-of-type(odd) > * { + background-color: var(--bg-tertiary); + color: var(--text-primary); +} + +[data-theme="dark"] .table > :not(caption) > * > * { + background-color: transparent; + border-bottom-color: var(--border-color); + color: var(--text-primary); +} + +[data-theme="dark"] .table > thead { + border-bottom: 2px solid var(--border-color); +} + +/* Blockquotes */ +[data-theme="dark"] blockquote { + border-left: 4px solid var(--accent-color); + padding-left: 1rem; + margin-left: 0; + color: var(--text-secondary); + background-color: var(--bg-tertiary); + padding: 1rem; + border-radius: 4px; +} + +/* Horizontal rules */ +[data-theme="dark"] hr { + border-color: var(--border-color); + opacity: 0.5; +} + +/* Buttons - comprehensive styling */ +[data-theme="dark"] button, +[data-theme="dark"] .button, +[data-theme="dark"] a.button { + background-color: var(--accent-color); + color: #ffffff; + border: 1px solid var(--accent-color); + padding: 0.5rem 1.25rem; + border-radius: 6px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + text-decoration: none; + display: inline-block; +} + +[data-theme="dark"] button:hover, +[data-theme="dark"] .button:hover, +[data-theme="dark"] a.button:hover { + background-color: var(--link-hover); + border-color: var(--link-hover); + color: #ffffff; + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(88, 166, 255, 0.3); + text-decoration: none; +} + +[data-theme="dark"] button:active, +[data-theme="dark"] .button:active, +[data-theme="dark"] a.button:active { + transform: translateY(0); +} + +/* Comment buttons specific styling */ +[data-theme="dark"] #giscus-load, +[data-theme="dark"] #giscus-revoke { + background-color: var(--bg-tertiary); + color: var(--text-primary); + border: 1px solid var(--border-color); +} + +[data-theme="dark"] #giscus-load:hover, +[data-theme="dark"] #giscus-revoke:hover { + background-color: var(--accent-color); + border-color: var(--accent-color); + color: #ffffff; +} + +/* Cards and list items */ +[data-theme="dark"] .card { + background-color: var(--bg-tertiary); + border: 1px solid var(--border-color); + color: var(--text-primary); +} + +[data-theme="dark"] .list-group-item { + background-color: var(--bg-tertiary); + border: 1px solid var(--border-color); + color: var(--text-primary); +} + +[data-theme="dark"] .list-group-item:hover { + background-color: var(--bg-secondary); +} + +/* Post titles and article content */ +[data-theme="dark"] .post header .title h1 a { + color: var(--text-primary); + font-weight: 600; +} + +[data-theme="dark"] .post header .title h1 a:hover { + color: var(--link-hover); + text-decoration: none; +} + +[data-theme="dark"] .post header p { + color: var(--text-secondary); +} + +[data-theme="dark"] article { + color: var(--text-primary); +} + +/* Headings */ +[data-theme="dark"] h1, +[data-theme="dark"] h2, +[data-theme="dark"] h3, +[data-theme="dark"] h4, +[data-theme="dark"] h5, +[data-theme="dark"] h6 { + color: var(--text-primary); + font-weight: 600; +} + +[data-theme="dark"] h1 { + border-bottom: 2px solid var(--border-color); + padding-bottom: 0.5rem; +} + +[data-theme="dark"] p { + color: var(--text-primary); +} + +/* Lists */ +[data-theme="dark"] ul, +[data-theme="dark"] ol { + color: var(--text-primary); +} + +[data-theme="dark"] li { + color: var(--text-primary); +} + +/* Stats and tags */ +[data-theme="dark"] .stats li { + color: var(--text-secondary); +} + +[data-theme="dark"] .stats li a { + color: var(--text-secondary); + background-color: var(--bg-tertiary); + padding: 0.25rem 0.75rem; + border-radius: 12px; + border: 1px solid var(--border-color); +} + +[data-theme="dark"] .stats li a:hover { + color: var(--link-hover); + border-color: var(--accent-color); + text-decoration: none; +} + +/* Navbar - ensure it looks good in dark mode */ +[data-theme="dark"] .navbar-dark { + background-color: #0d1117 !important; Review Comment: For consistency with the rest of the CSS, consider using the CSS variable instead of the hardcoded color value. Replace `#0d1117` with `var(--bg-primary)` to maintain consistency with the color scheme defined at the top of the file. ```suggestion background-color: var(--bg-primary) !important; ``` ########## content/theme/templates/menu.html: ########## @@ -15,6 +15,10 @@ <a class="nav-link" href="/blog/feed.xml">RSS</a> </li> </ul> + <button id="theme-toggle" class="theme-toggle" aria-label="Toggle dark mode" title="Toggle dark mode"> Review Comment: The button element should have an explicit type attribute. Add `type="button"` to prevent the button from inadvertently submitting forms if it's ever placed inside a form element. ```suggestion <button id="theme-toggle" class="theme-toggle" type="button" aria-label="Toggle dark mode" title="Toggle dark mode"> ``` ########## content/js/darkmode.js: ########## @@ -0,0 +1,93 @@ +/** + * Dark Mode Toggle Functionality for Apache DataFusion Blog + */ + +(function() { + 'use strict'; + + // Constants + const THEME_KEY = 'datafusion-theme'; + const THEME_DARK = 'dark'; + const THEME_LIGHT = 'light'; + + /** + * Get the current theme from localStorage or system preference + */ + function getStoredTheme() { + return localStorage.getItem(THEME_KEY); + } + + /** + * Get the preferred theme based on system settings + */ + function getPreferredTheme() { + const storedTheme = getStoredTheme(); + if (storedTheme) { + return storedTheme; + } + // Check system preference + return window.matchMedia('(prefers-color-scheme: dark)').matches ? THEME_DARK : THEME_LIGHT; + } + + /** + * Set the theme on the document + */ + function setTheme(theme) { + if (theme === THEME_DARK) { + document.documentElement.setAttribute('data-theme', THEME_DARK); + } else { + document.documentElement.removeAttribute('data-theme'); + } + localStorage.setItem(THEME_KEY, theme); Review Comment: The localStorage access should be wrapped in try-catch blocks to handle cases where localStorage is disabled, unavailable (e.g., in private browsing mode), or when storage quota is exceeded. Without error handling, the entire script could fail silently, preventing the theme toggle functionality from working. Consider wrapping localStorage calls in try-catch blocks similar to how giscus-consent.js handles it. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
