Conversation
- Updated Breadcrumb component to support dark mode styles. - Enhanced Button component with dark mode background and hover effects. - Modified Cloud component to display different SVGs for light and dark modes. - Improved FeatureCard component with dark mode text and background colors. - Added dark mode styles to FlipCard component for better visibility. - Updated Footer component to include dark mode background and text colors. - Enhanced Header component with dark mode support for text and backgrounds. - Improved Hero component to support dark mode text colors. - Updated ReadTime component for dark mode text color. - Enhanced SectionHeader component with dark mode text color. - Updated Sidebar component to support dark mode text colors. - Enhanced TableOfContents component with dark mode styles for links and backgrounds. - Updated BaseLayout and DocsLayout to support dark mode background and text colors. - Enhanced various pages (about, blog, docs, tutorials) for dark mode text colors. - Improved global styles for prose in both light and dark modes.
…d event delegation
Feat/dark mode
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
chore: remove glow effect from neon border in FlipCard component
…les for better integration with prose
…oved design consistency
…dability in installation guide
…for improved readability
Chore/UI rework
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This pull request merges changes from the main branch to production, introducing dark mode support and UI updates. The changes include comprehensive dark mode styling across all components, a theme toggle functionality, mobile navigation menu, consolidated iconify-icon script loading, and various UI refinements.
Changes:
- Added complete dark mode support with theme toggle and persistence using localStorage
- Implemented mobile navigation menu with hamburger toggle for responsive design
- Consolidated iconify-icon script loading to BaseLayout.astro (removed from individual components)
- Enhanced prose styles with dedicated light and dark mode variants for better content readability
- Updated version from 1.0.2 to 1.1.1 with corresponding CHANGELOG entries
Reviewed changes
Copilot reviewed 31 out of 31 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| template/src/types/constants.ts | Changed CDN base URL from versioned to @main branch |
| template/src/styles/global.css | Added comprehensive dark mode prose styles and custom variant |
| template/src/layouts/BaseLayout.astro | Added theme initialization script and iconify-icon global loading |
| template/src/components/Header.astro | Implemented theme toggle, mobile menu, and refactored event handling |
| template/src/components/Button.astro | Added dark mode button styles and icon sizing updates |
| template/src/components/*.astro | Applied dark mode color classes throughout UI components |
| template/src/pages/*.astro | Added dark mode text colors to page content |
| template/src/content/docs/installation/index.mdx | Replaced Button components with markdown links |
| template/astro.config.mjs | Removed wrap: true from Shiki config |
| package.json | Version bump to 1.1.1 |
| CHANGELOG.md | Added entries for versions 1.1.0 and 1.1.1 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @custom-variant dark (&:where(.dark, .dark *)); | ||
|
|
There was a problem hiding this comment.
A custom variant @custom-variant dark (&:where(.dark, .dark *)); has been added, but it doesn't appear to be used anywhere in the codebase. The dark mode implementation is using standard Tailwind's dark: variant with the class strategy (html.dark).
This custom variant definition is redundant and should be removed unless there's a specific use case for it. If it's intended for future use, add a comment explaining its purpose.
| @custom-variant dark (&:where(.dark, .dark *)); |
| <div class="step relative [counter-increment:step]"> | ||
| <div class="absolute -left-[calc(1.5rem+1px)] -translate-x-1/2 w-8 h-8 rounded-full bg-transparent border-2 border-primary-500 flex items-center justify-center text-sm font-semibold text-primary-700 dark:text-primary-300 before:content-[counter(step)] z-10" /> | ||
| <div class="step-line absolute -left-[calc(1.5rem+1px)] -translate-x-1/2 top-10 w-0.5 rounded-full bg-gray-300 dark:bg-gray-700" style="height: calc(100% - 0.5rem);" /> | ||
| <div class="step-line absolute -left-[calc(1.5rem+1px)] -translate-x-1/2 top-10 w-0.5 rounded-full bg-gray-300 dark:bg-gray-700" style="height: calc(100% - 2rem);" /> |
There was a problem hiding this comment.
The step line height has been changed from calc(100% - 0.5rem) to calc(100% - 2rem). This makes the connecting line significantly shorter (1.5rem shorter), which may create an unexpected visual gap between steps. This seems like an unintentional change that would affect the visual continuity of the Steps component. Please verify this change is intentional and matches the design requirements.
| <div class="step-line absolute -left-[calc(1.5rem+1px)] -translate-x-1/2 top-10 w-0.5 rounded-full bg-gray-300 dark:bg-gray-700" style="height: calc(100% - 2rem);" /> | |
| <div class="step-line absolute -left-[calc(1.5rem+1px)] -translate-x-1/2 top-10 w-0.5 rounded-full bg-gray-300 dark:bg-gray-700" style="height: calc(100% - 0.5rem);" /> |
| // Theme toggle - using event delegation | ||
| document.addEventListener('click', function(e) { | ||
| const toggle = (e.target as HTMLElement).closest('#theme-toggle'); | ||
| if (!toggle) return; | ||
|
|
||
| const isDark = document.documentElement.classList.contains(THEME_DARK); | ||
| setTheme(isDark ? THEME_LIGHT : THEME_DARK); | ||
| const isDark = document.documentElement.classList.contains('dark'); | ||
| document.documentElement.classList.toggle('dark', !isDark); | ||
| localStorage.setItem('theme', isDark ? 'light' : 'dark'); | ||
| }); | ||
|
|
||
| // Mobile menu toggle - using event delegation | ||
| document.addEventListener('click', function(e) { | ||
| const toggle = (e.target as HTMLElement).closest('#mobile-menu-toggle'); | ||
| if (toggle) { | ||
| e.stopPropagation(); | ||
| const mobileMenu = document.getElementById('mobile-menu'); | ||
| if (!mobileMenu) return; | ||
|
|
||
| const menuIcon = toggle.querySelector('.menu-icon'); | ||
| const closeIcon = toggle.querySelector('.close-icon'); | ||
| const isOpen = !mobileMenu.classList.contains('hidden'); | ||
|
|
||
| mobileMenu.classList.toggle('hidden'); | ||
| menuIcon?.classList.toggle('hidden'); | ||
| closeIcon?.classList.toggle('hidden'); | ||
| toggle.setAttribute('aria-expanded', String(!isOpen)); | ||
| return; | ||
| } | ||
|
|
||
| // Close mobile menu when clicking outside | ||
| const mobileToggle = document.getElementById('mobile-menu-toggle'); | ||
| const mobileMenu = document.getElementById('mobile-menu'); | ||
| if (mobileToggle && mobileMenu) { | ||
| if (!mobileToggle.contains(e.target as Node) && !mobileMenu.contains(e.target as Node)) { | ||
| closeMobileMenu(); | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| initTheme(); | ||
| document.addEventListener('astro:page-load', initTheme); | ||
| initHeader(); | ||
| document.addEventListener('astro:page-load', initHeader); | ||
| })(); |
There was a problem hiding this comment.
The theme toggle and mobile menu event listeners are attached to the document using event delegation, but they're set up inside an IIFE that runs on every page load/navigation. While there's a guard with __headerInitialized, the event listeners are attached directly to document without the guard, meaning multiple listeners will accumulate with each navigation in a SPA context.
The event listeners should either:
- Be attached inside the
__headerInitializedguard, or - Be properly cleaned up before re-attaching, or
- Use a pattern that naturally deduplicates (e.g., named function references that can be removed)
This can lead to memory leaks and multiple event handler executions.
| index === defaultIndex | ||
| ? 'text-primary-600 dark:text-white bg-gray-100 dark:bg-gray-800' | ||
| : 'text-gray-700 dark:text-gray-400 bg-transparent hover:text-gray-900 dark:hover:text-gray-200', | ||
| : 'text-gray-700 dark:text-gray-400 bg-transparent hover:text-primary-700 dark:hover:text-gray-200', |
There was a problem hiding this comment.
The inactive tab hover color has been changed from hover:text-gray-900 to hover:text-primary-700, but only in light mode. In dark mode, it remains dark:hover:text-gray-200. This creates an inconsistency in the hover behavior:
- Light mode: Hovers to primary color (brand color)
- Dark mode: Hovers to gray
Consider making the hover behavior consistent across both modes. Either use primary colors in both modes (e.g., dark:hover:text-primary-400) or gray colors in both modes.
| : 'text-gray-700 dark:text-gray-400 bg-transparent hover:text-primary-700 dark:hover:text-gray-200', | |
| : 'text-gray-700 dark:text-gray-400 bg-transparent hover:text-primary-700 dark:hover:text-primary-400', |
| const theme = localStorage.getItem('theme') || | ||
| (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); | ||
| if (theme === 'dark') { | ||
| document.documentElement.classList.add('dark'); |
There was a problem hiding this comment.
The theme initialization script is using is:inline which is correct for preventing flash of unstyled content. However, the script only adds the 'dark' class but never removes it. If a user has 'light' stored in localStorage but the page previously had the dark class from SSR or previous navigation, the dark class won't be removed.
The script should explicitly handle both cases:
if (theme === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}| document.documentElement.classList.add('dark'); | |
| document.documentElement.classList.add('dark'); | |
| } else { | |
| document.documentElement.classList.remove('dark'); |
|
|
||
| <style> | ||
| .step:last-child .step-line { | ||
| .step:last-of-type .step-line { |
There was a problem hiding this comment.
The selector has been changed from .step:last-child to .step:last-of-type. However, both selectors should work the same way in this context since all steps are sibling div elements with the class "step". This change appears unnecessary but is not harmful. If there was a specific issue with :last-child, please document it in a comment.
| .step:last-of-type .step-line { | |
| .step:last-child .step-line { |
| <style> | ||
| .btn :global(p) { | ||
| <style is:global> | ||
| .btn :is(p) { |
There was a problem hiding this comment.
The style tag has been changed from <style> to <style is:global>. However, the selector .btn :is(p) (changed from .btn :global(p)) is now less specific. With is:global, all styles are global, so the :global() pseudo-class is no longer needed and :is() is correct. However, :is(p) is equivalent to just p in this context, making the change semantically neutral but potentially confusing. Consider simplifying to .btn p for clarity.
| .btn :is(p) { | |
| .btn p { |
| <nav | ||
| id="mobile-menu" | ||
| class="mobile-menu hidden md:hidden mt-2 py-4 px-6 bg-white/90 dark:bg-gray-900/90 backdrop-blur-xl border border-white/30 dark:border-gray-700/50 shadow-lg shadow-black/5 dark:shadow-black/20 rounded-2xl" | ||
| > | ||
| <div class="flex flex-col gap-2"> | ||
| {navLinks.map((link) => ( | ||
| <a | ||
| href={link.href} | ||
| class:list={[ | ||
| "block py-2 px-3 text-sm font-medium transition-colors rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800", | ||
| currentPath === link.href || (link.href !== "/" && (currentPath === link.href || currentPath.startsWith(link.href + "/"))) | ||
| ? "text-gray-900 dark:text-white bg-gray-100 dark:bg-gray-800" | ||
| : "text-gray-600 dark:text-gray-400", | ||
| ]} | ||
| > | ||
| {link.label} | ||
| </a> | ||
| ))} | ||
| </div> | ||
| </nav> |
There was a problem hiding this comment.
The mobile menu navigation links should close the mobile menu when clicked to improve user experience. Currently, clicking a link in the mobile menu will navigate but leave the menu open. Consider adding click handlers to menu links that call closeMobileMenu() when a link is activated, especially for same-page navigation.
| <button | ||
| id="mobile-menu-toggle" | ||
| class="p-2 text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100 transition-colors md:hidden" | ||
| aria-label="Toggle mobile menu" | ||
| aria-expanded="false" | ||
| > | ||
| <svg class="menu-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"> | ||
| <line x1="6" y1="6" x2="18" y2="6"></line> | ||
| <line x1="3" y1="12" x2="21" y2="12"></line> | ||
| <line x1="6" y1="18" x2="18" y2="18"></line> | ||
| </svg> | ||
| <iconify-icon icon="mdi:close" class="close-icon hidden" width="20" height="20"></iconify-icon> | ||
| </button> | ||
| </div> | ||
| </div> | ||
|
|
||
| <!-- Mobile Navigation Menu --> | ||
| <nav | ||
| id="mobile-menu" | ||
| class="mobile-menu hidden md:hidden mt-2 py-4 px-6 bg-white/90 dark:bg-gray-900/90 backdrop-blur-xl border border-white/30 dark:border-gray-700/50 shadow-lg shadow-black/5 dark:shadow-black/20 rounded-2xl" | ||
| > | ||
| <div class="flex flex-col gap-2"> | ||
| {navLinks.map((link) => ( | ||
| <a | ||
| href={link.href} | ||
| class:list={[ | ||
| "block py-2 px-3 text-sm font-medium transition-colors rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800", | ||
| currentPath === link.href || (link.href !== "/" && (currentPath === link.href || currentPath.startsWith(link.href + "/"))) | ||
| ? "text-gray-900 dark:text-white bg-gray-100 dark:bg-gray-800" | ||
| : "text-gray-600 dark:text-gray-400", | ||
| ]} | ||
| > | ||
| {link.label} | ||
| </a> | ||
| ))} | ||
| </div> | ||
| </nav> |
There was a problem hiding this comment.
The mobile menu lacks keyboard navigation support. Users who navigate with keyboard cannot:
- Close the menu with the Escape key
- Tab trap is not implemented (focus should stay within the menu when open)
- No indication of which element should receive focus when menu opens
Consider implementing:
- Escape key handler to close the menu
- Focus trap when menu is open
- Auto-focus the first menu item or close button when menu opens
- Return focus to the toggle button when menu closes
These are important for WCAG 2.1 compliance and keyboard-only users.
| export const GITHUB_URL = 'https://github.com/Sithumli/DocuBase'; | ||
|
|
||
| export const ASSETS_CDN_BASE = 'https://cdn.jsdelivr.net/gh/Sithumli/DocuBase@__DOCUBASE_VERSION__/assets'; | ||
| export const ASSETS_CDN_BASE = 'https://cdn.jsdelivr.net/gh/Sithumli/DocuBase@main/assets'; |
There was a problem hiding this comment.
The ASSETS_CDN_BASE URL has been changed from a versioned placeholder __DOCUBASE_VERSION__ to @main. This means assets will always be served from the main branch instead of a specific version. This is problematic for production deployments because:
- Assets from the main branch may not match the deployed version
- Changes to assets in main could break production sites unexpectedly
- CDN caching becomes less reliable
For production, it's recommended to use versioned asset URLs (e.g., @v1.1.1 or @1.1.1) to ensure stability and proper cache invalidation.
Main → Prod