Skip to content

✨ feat: adding preset, dark mode service improvements, prevent SSR flickering#384

Merged
Luizgomess merged 8 commits intomasterfrom
themes-update
Dec 26, 2025
Merged

✨ feat: adding preset, dark mode service improvements, prevent SSR flickering#384
Luizgomess merged 8 commits intomasterfrom
themes-update

Conversation

@mikij
Copy link
Contributor

@mikij mikij commented Dec 22, 2025

What was done? 📝

Major Dark Mode Service Refactoring

The ZardDarkMode service has been significantly improved with modern Angular patterns:

Key Changes:

  • Removed lifecycle hooks: Eliminated OnDestroy in favor of DestroyRef for better resource management
  • Added initialization method: New init() method called via provideAppInitializer to ensure proper theme setup on app start
  • Improved API: Replaced getCurrentTheme() method with a currentTheme getter that returns a readonly signal
  • Better media query handling: Uses MediaMatcher from CDK instead of manual media query management
  • Enhanced system theme detection: More reliable system preference tracking with proper event listener management

Theme System Enhancements

New Theme Presets:

  • Added "Nord Ice" theme with complete color definitions for both light and dark variants
  • Improved theme data structure with better organization

UI Improvements:

  • Fixed template structure in theme sidebar component
  • Updated dark mode page template to use the new service API
  • Enhanced theme mode display and controls

SSR Compatibility Fixes

Production Build Optimizations:

  • Disabled inlineCritical CSS inlining to prevent SSR flickering issues
  • Added /themes route to prerender list for better SEO

Provider Updates:

  • Modified provideZard() to include dark mode initialization
  • Updated import paths for better module resolution

Font System Updates

Typography Enhancements:

  • Added Geist and Geist Mono variable fonts from Fontsource
  • Improved font loading and rendering consistency

Testing Infrastructure

Comprehensive Test Suite:

  • Added 190+ lines of unit tests for the dark mode service
  • Tests cover all major functionality: theme toggling, system preference detection, localStorage persistence, and SSR compatibility
  • Follows AAA (Arrange, Act, Assert) pattern with proper mocking

CLI and Build Improvements

Registry Updates:

  • Updated CLI dark mode setup command with new import paths
  • Enhanced package.json with new font dependencies
  • Improved gitignore with additional tooling entries

Summary

This branch represents a comprehensive overhaul of the theming system with a focus on:

  • Reliability: Better SSR support and flickering prevention
  • Modern APIs: Leveraging Angular 20+ features like signals and DestroyRef
  • User Experience: Smoother theme transitions and system preference integration
  • Maintainability: Cleaner code structure and comprehensive testing

The changes maintain backward compatibility while significantly improving the robustness and performance of the dark mode functionality.

Screenshots or GIFs 📸

|-----Figma-----|
|-----Implementation-----|

Link to Issue 🔗

Type of change 🏗

  • New feature (non-breaking change that adds functionality)
  • Bug fix (non-breaking change that fixes an issue)
  • Refactor (non-breaking change that improves the code or technical debt)
  • Chore (none of the above, such as upgrading libraries)

Breaking change 🚨

Checklist 🧐

  • Tested on Chrome
  • Tested on Safari
  • Tested on Firefox
  • No errors in the console

Summary by CodeRabbit

  • New Features

    • Added "Nord Ice" theme preset (light & dark) with preview colors.
  • Improvements

    • Dark-mode handling enhanced with app startup initialization and more robust system-preference behavior.
    • Fonts updated to Geist Variable + Geist Mono Variable; typography and container sizing refined.
    • /themes route now prerendered; page title/base handling streamlined.
  • Style

    • Adjusted per-color item spacing in the theme editor.
  • Tests

    • Added comprehensive unit tests for dark-mode behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

@mikij mikij requested a review from Luizgomess December 22, 2025 15:14
@coderabbitai
Copy link

coderabbitai bot commented Dec 22, 2025

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'tools', 'path_instructions'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
📝 Walkthrough

Walkthrough

Introduce a signal/effect-based ZardDarkMode with an init() AppInitializer hook, wire it into app startup, add Nord Ice theme preset and theme-sidebar markup tweaks, switch to Geist variable fonts, add unit tests for dark-mode, update call sites to the new dark-mode API, and add /themes to prerender routes.

Changes

Cohort / File(s) Change Summary
Dark Mode Service
libs/zard/src/lib/shared/services/dark-mode.ts
Rewrote lifecycle to constructor/effect + init(); added MediaMatcher & DestroyRef; replaced previous API with a currentTheme ReadonlySignal; updated updateThemeMode signature; hardened localStorage and system-listener handling.
Dark Mode Tests
libs/zard/src/lib/shared/services/dark-mode.spec.ts
Added comprehensive unit tests: init, system-preference listening, SSR handling, toggle flows, and listener lifecycle with mocked matchMedia/localStorage.
App Init Wiring
apps/web/src/app/app.config.ts
Added provideAppInitializer(() => inject(ZardDarkMode).init()) to run dark-mode init during app startup.
Call Site Updates
apps/web/src/app/domain/pages/dark-mode/*, apps/web/src/app/core/layouts/documentation/documentation.layout.ts, apps/web/src/app/domain/components/block-preview/block-preview.component.ts
Updated consumers to use currentTheme() signal access instead of removed getters/properties (theme/getCurrentTheme); removed obsolete properties and adjusted template/local bindings.
Theme Presets & Sidebar
apps/web/src/app/domain/pages/themes/data/theme-presets.ts, apps/web/src/app/domain/pages/themes/components/theme-sidebar/theme-sidebar.component.html
Added nordIceTheme and Nord Ice entry in THEME_PRESETS; adjusted sidebar HTML to wrap each color item with a py-3 per-item container (spacing change).
Fonts & Global Styles / Index
apps/web/src/styles.css, apps/web/src/index.html
Switched to Geist variable fonts imports, added --font-geist-mono, updated font variable mappings, adjusted container max-width utility, removed Google Fonts preconnects, and simplified early theme class toggling.
Prerender & Build Config
apps/web/prerender-routes.txt, apps/web/project.json
Added /themes to prerender routes; set optimization.styles.inlineCritical = false in production config.
Minor Formatting
apps/web/src/app/shared/services/markdown.service.ts
Reflowed Tailwind class arrays to multi-line for readability only.

Sequence Diagram(s)

sequenceDiagram
    actor Browser
    participant App as Angular App
    participant Init as AppInitializer
    participant Zard as ZardDarkMode
    participant Media as MediaMatcher
    participant DOM as Document

    Note right of App: App bootstrap
    App->>Init: run app initializers
    Init->>Zard: init()
    Note right of Zard: constructor/effect may run earlier (signals)
    Zard->>Zard: read stored theme (localStorage, guarded)
    alt stored theme present
        Zard->>DOM: apply stored theme (html class / data-theme)
    else
        Zard->>Media: query prefers-color-scheme
        Media-->>Zard: current preference
        Zard->>DOM: apply SYSTEM-derived theme (html class / data-theme)
    end

    alt SYSTEM mode active
        Browser->>Media: system preference changes
        Media->>Zard: change event
        Zard->>Zard: updateThemeMode(isDark, SYSTEM)
        Zard->>DOM: update classes / data-theme
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • srizzon
  • Luizgomess
  • ribeiromatheuss

"Effects hum, MediaMatcher sings,
Nord Ice brings its frosty rings,
Geist variables take the stage,
Signals, init, and tests engage—
Light and dark in tidy wings."

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the three main changes: adding a theme preset, improving the dark mode service, and fixing SSR flickering issues.
Description check ✅ Passed The description is comprehensive and well-structured, covering all major changes with clear sections, detailed explanations, and completed checklist items matching the template.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch themes-update

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 181d369 and 05b92aa.

⛔ Files ignored due to path filters (1)
  • apps/web/public/r/dark-mode.json is excluded by !apps/web/public/** and included by apps/**
📒 Files selected for processing (3)
  • apps/web/src/app/app.config.ts
  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧰 Additional context used
📓 Path-based instructions (3)
libs/zard/**/*.{css,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS custom properties for design tokens and theming in the component library

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use Jest with @happy-dom/jest-environment and Angular TestBed utilities for testing

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
  • apps/web/src/app/app.config.ts
🧠 Learnings (36)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Implement TailwindCSS v4 with PostCSS for styling and use class merging with tailwind-merge to resolve conflicts
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • apps/web/src/app/app.config.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Place tests co-located with components using the .spec.ts naming convention

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate test files with components using `.spec.ts` suffix next to component files

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
  • apps/web/src/app/app.config.ts
📚 Learning: 2025-12-13T11:50:56.310Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 372
File: libs/zard/src/lib/shared/components/card/card.component.spec.ts:86-88
Timestamp: 2025-12-13T11:50:56.310Z
Learning: Do not flag or suggest removing `standalone: true` from test components (*.spec.ts files) or demo components (demo/*.ts files) in libs/zard/src/lib/shared/components/**/*.ts, as it is not a significant concern and the explicit flag is acceptable in these contexts.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-26T11:20:45.264Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/select/select.component.spec.ts:79-88
Timestamp: 2025-11-26T11:20:45.264Z
Learning: In ZardUI select component tests (libs/zard/src/lib/components/select/select.component.spec.ts), use fakeAsync() with flush() instead of setTimeout because the component uses setTimeout(..., 0) for focus management, which requires advancing macrotasks in tests.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to **/*.spec.ts : Use Jest with happy-dom/jest-environment and Angular TestBed utilities for testing

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use OnPush change detection strategy in Angular components: `changeDetection: ChangeDetectionStrategy.OnPush`

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Create demo components in the `demo/` folder with a main export, default example, and variant examples

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use Signal-based inputs with the `input()` function instead of Input decorators in Angular components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for performance optimization in components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-30T19:07:11.572Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 352
File: apps/web/src/app/domain/components/sidebar/scroll-on-active.directive.ts:23-27
Timestamp: 2025-11-30T19:07:11.572Z
Learning: In apps/web/src/app/domain/components/sidebar/scroll-on-active.directive.ts, the guard checking if scrollIntoView exists before calling it is necessary due to mobile browser compatibility issues. Physical testing on mobile devices shows scrollIntoView may not be present or functional. This defensive pattern should be kept despite scrollIntoView being part of the standard DOM API.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Use Jest with `happy-dom/jest-environment` for testing Angular components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-15T11:43:06.831Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 373
File: libs/zard/src/lib/shared/components/select/select.component.ts:33-33
Timestamp: 2025-12-15T11:43:06.831Z
Learning: In files under libs/zard/src/lib/**/*.{ts,tsx,js}, prefer the @/ path alias for imports that map to libs/zard/src/lib/* directories. For example, write import { mergeClasses } from '@/shared/utils/merge-classes' instead of using the 'zard/' alias. This improves path readability and aligns with the project's alias configuration.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use `mergeClasses()` utility with `clsx` and `tailwind-merge` to resolve class conflicts in component styling

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Implement TailwindCSS v4 with PostCSS for styling and use class merging with tailwind-merge to resolve conflicts

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-30T13:27:41.206Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/popover/popover.component.ts:28-29
Timestamp: 2025-11-30T13:27:41.206Z
Learning: In libs/zard/src/lib/components/core/**/*.ts files (core utilities, plugins, and providers), use relative imports for intra-core dependencies because the ZardUI CLI performs path transformations during component installation. The CLI expects specific relative path patterns and transforms them to the target project structure. For all other component imports and application code, use zard/* path aliases.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-14T22:52:09.135Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 326
File: libs/zard/src/lib/components/input/float.label.component.ts:71-0
Timestamp: 2025-11-14T22:52:09.135Z
Learning: In libs/zard/src/lib/components/*/*.component.ts files, move HostListener and HostBinding to the Component decorator's host property instead of using decorators on class members (e.g., host: { '(input)': 'onInput()' }).

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use mergeClasses utility from zard/shared/utils for combining CVA variants with custom classes

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use computed properties in Angular components for reactive class calculations: `protected readonly classes = computed(() => ...)`

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-29T15:31:22.377Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 339
File: libs/zard/src/lib/components/carousel/carousel.component.ts:92-92
Timestamp: 2025-11-29T15:31:22.377Z
Learning: In libs/zard/src/lib/components/**/*.component.ts files using TailwindCSS, avoid suggesting individual class bindings like `[class.fill-primary]="condition"` because they can cause TailwindCSS issues. Prefer string concatenation or `[class]` binding with conditional expressions instead.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T21:17:39.497Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 383
File: libs/zard/src/lib/shared/components/carousel/carousel.component.ts:114-115
Timestamp: 2025-12-21T21:17:39.497Z
Learning: In Angular components using signal inputs (input()) with types from external libraries like Embla Carousel, explicit type annotations (e.g., `readonly zOptions: InputSignal<EmblaOptionsType> = input<EmblaOptionsType>(...)`) may be necessary to prevent TypeScript IDE errors about inferred types referencing non-portable node_modules paths. This is not redundant when the annotation prevents the "cannot be named without a reference to node_modules" error.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Applies to libs/blocks/src/lib/**/*.component.html : Use TailwindCSS utility classes for styling, following responsive design patterns with prefixes for breakpoints (sm:, lg:) and ensure accessibility with semantic HTML and ARIA guidelines

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.variants.ts : Use CVA (Class Variance Authority) for type-safe styling variants in components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/src/styles.css : Set up `src/styles.css` with Tailwind CSS configuration and design tokens using CSS `theme` and `plugin` directives

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.variants.ts : Use CVA (Class Variance Authority) for typed variants in component styling

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Components should be built with TailwindCSS v4 using the new inline configuration approach (no `tailwind.config.js` needed, configuration via `.postcssrc.json`, design tokens defined in CSS with `theme`)

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Use TailwindCSS v4 with PostCSS for styling the component library

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-26T10:13:44.258Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/layout/sidebar.component.ts:22-22
Timestamp: 2025-11-26T10:13:44.258Z
Learning: The ZardUI CLI will automatically add `provideZard()` to the app configuration and install the core component before the next CLI release, addressing the breaking change requirement for the event manager plugins.

Applied to files:

  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-30T08:50:23.436Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/core/providezard.ts:0-0
Timestamp: 2025-11-30T08:50:23.436Z
Learning: In libs/zard/src/lib/components/core/providezard.ts, the import paths `../core/event-manager-plugins/...` are intentionally structured this way because the ZardUI CLI transforms them to 'shared/components/core/event-manager-plugins/...' format. Other relative path combinations don't work with the current CLI implementation. This path pattern should not be simplified until the CLI transformation logic is updated.

Applied to files:

  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Create components as standalone components with `standalone: true` in Angular

Applied to files:

  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export all components in `libs/zard/src/lib/components/components.ts` for public API

Applied to files:

  • apps/web/src/app/app.config.ts
🔇 Additional comments (13)
apps/web/src/app/app.config.ts (2)

2-13: LGTM! Clean imports following path alias conventions.

The imports are well-organized and correctly use the @zard/* path alias for the dark mode service import.


31-31: App initializer pattern correctly implements early theme setup.

The provideAppInitializer approach ensures the dark mode service initializes before first render, preventing SSR flicker. The synchronous init() call is appropriate here and won't block app startup.

libs/zard/src/lib/shared/services/dark-mode.spec.ts (4)

1-65: Excellent test setup with comprehensive mocking and cleanup.

The test suite properly:

  • Mocks browser APIs (matchMedia, localStorage) for isolation
  • Configures TestBed with the service under test
  • Calls TestBed.tick() after initialization to flush effects
  • Clears mocks and localStorage between tests to prevent state leakage

This follows Jest and Angular TestBed best practices.


67-120: Thorough coverage of system theme detection and listener lifecycle.

The tests properly verify:

  • Media query initialization and matcher configuration
  • Event listener registration when theme is set to SYSTEM
  • Listener cleanup when switching away from SYSTEM
  • Dynamic system preference changes updating the theme
  • Fresh service initialization with system dark mode preference

The use of TestBed.tick() after state changes ensures effects execute before assertions.


122-158: Excellent SSR safety coverage.

The tests verify:

  • Proper listener setup when initializing with SYSTEM theme default
  • Graceful degradation in SSR environments (no browser API access)
  • All theme toggle operations work safely without throwing in SSR context

The SSR test correctly simulates server environment by providing a non-browser PLATFORM_ID and confirms the service doesn't access browser-only APIs.


160-212: Comprehensive toggleTheme test coverage.

The test suite verifies:

  • Implicit toggling between light and dark modes
  • Toggling from system-detected theme (both dark and light) to explicit modes
  • Explicit theme setting via the targetMode parameter
  • Proper listener cleanup when switching away from SYSTEM mode
  • Correct theme resolution when SYSTEM mode depends on media query state

All tests properly use TestBed.tick() to flush effects before assertions.

libs/zard/src/lib/shared/services/dark-mode.ts (7)

1-24: Excellent use of modern Angular APIs and dependency injection patterns.

The service correctly:

  • Uses inject() function for dependency injection (modern Angular pattern)
  • Replaces OnDestroy with DestroyRef for lifecycle management
  • Uses signals for reactive state management
  • Integrates MediaMatcher from Angular CDK for media query handling
  • Employs proper browser/server detection with isPlatformBrowser

26-37: Constructor correctly implements reactive theme management with effect-based lifecycle.

The implementation:

  • Guards browser-only code with isBrowser check for SSR safety
  • Uses MediaMatcher.matchMedia() for system theme detection
  • Registers cleanup via DestroyRef.onDestroy() (modern Angular pattern)
  • Employs effect() to reactively apply theme changes when signal updates

This centralizes theme application logic and eliminates the need for manual OnDestroy implementation.


39-51: Computed signal correctly resolves system theme to actual mode.

The themeMode computed signal:

  • Resolves SYSTEM to DARK or LIGHT based on media query state
  • Returns explicit modes unchanged
  • Provides a clean API for consumers who need the resolved theme

The init() method:

  • Guards against multiple initializations with the initialized flag
  • Only runs in browser context for SSR safety
  • Bootstraps theme state during app initialization

53-73: Public API correctly exposes theme control and readonly access.

The toggleTheme() method:

  • Guards against SSR with browser check
  • Supports both explicit mode setting and implicit toggling
  • Implicit toggle switches between resolved DARK/LIGHT modes

The currentTheme getter:

  • Returns ReadonlySignal to prevent external mutation
  • Provides clear JSDoc with usage example
  • Enables reactive template bindings via signal

75-92: Initialization correctly restores stored theme and sets up system listeners.

The query getter:

  • Throws descriptive error if accessed in SSR context
  • Guards against missing _query instance

The initializeTheme() method:

  • Loads stored theme preference via getStoredTheme()
  • Sets up system change listeners when using SYSTEM mode or no stored preference
  • Uses initialized flag to prevent duplicate initialization

94-127: Robust error handling around localStorage operations.

Both methods properly:

  • Guard browser-only operations
  • Wrap localStorage access in try-catch blocks
  • Log errors with console.warn() without crashing the app
  • Validate stored values against the expected enum values
  • Gracefully handle QuotaExceededError and SecurityError (private browsing)

The applyTheme() method correctly manages listener lifecycle:

  • Adds system change listener when theme is SYSTEM
  • Removes listener when switching to explicit LIGHT/DARK

129-153: DOM manipulation and listener management correctly implemented.

The helper methods:

updateThemeMode():

  • Updates both the dark class and data-theme attribute
  • Accepts resolved dark mode state and theme mode for flexible updates

isDarkModeActive():

  • Correctly determines dark mode: explicit DARK or SYSTEM with query match
  • Guards browser-only logic

handleSystemChanges():

  • Wraps listener operations in try-catch for defensive programming
  • Handles both adding and removing listeners based on parameter
  • Logs errors without crashing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4319964 and cc9b487.

📒 Files selected for processing (2)
  • apps/web/src/app/domain/pages/themes/components/theme-sidebar/theme-sidebar.component.html
  • apps/web/src/app/domain/pages/themes/data/theme-presets.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • apps/web/src/app/domain/pages/themes/data/theme-presets.ts
🧠 Learnings (4)
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library

Applied to files:

  • apps/web/src/app/domain/pages/themes/components/theme-sidebar/theme-sidebar.component.html
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Applies to libs/blocks/src/lib/**/*.component.html : Use TailwindCSS utility classes for styling, following responsive design patterns with prefixes for breakpoints (sm:, lg:) and ensure accessibility with semantic HTML and ARIA guidelines

Applied to files:

  • apps/web/src/app/domain/pages/themes/components/theme-sidebar/theme-sidebar.component.html
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Implement TailwindCSS v4 with PostCSS for styling and use class merging with tailwind-merge to resolve conflicts

Applied to files:

  • apps/web/src/app/domain/pages/themes/components/theme-sidebar/theme-sidebar.component.html
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/src/styles.css : Set up `src/styles.css` with Tailwind CSS configuration and design tokens using CSS `theme` and `plugin` directives

Applied to files:

  • apps/web/src/app/domain/pages/themes/components/theme-sidebar/theme-sidebar.component.html
🧬 Code graph analysis (1)
apps/web/src/app/domain/pages/themes/data/theme-presets.ts (1)
apps/web/src/app/domain/pages/themes/models/theme.model.ts (1)
  • ThemeDefinition (35-40)
🔇 Additional comments (2)
apps/web/src/app/domain/pages/themes/data/theme-presets.ts (2)

694-694: Destructive color deviation from other themes noted.

This dark mode destructive color (oklch(0.606 0.121 15)) differs from the standard oklch(0.704 0.191 22.216) used in other themes (Neutral, Slate, Zinc, etc.). If this is intentional for Violet's palette harmony, looks good. Just flagging for awareness in case cross-theme consistency was desired.


796-796: LGTM!

The Nord Ice preset entry follows the established pattern. Preview colors align with the icy blue Nord aesthetic.

@mikij mikij force-pushed the themes-update branch 2 times, most recently from c8b5ab6 to a9a7e63 Compare December 22, 2025 15:25
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/app/domain/pages/themes/data/theme-presets.ts (1)

661-661: Verify destructive color consistency in violet theme.

The violet theme applies a custom dark destructive color ('oklch(0.606 0.121 15)' at line 694) while keeping the light destructive color as the standard ('oklch(0.577 0.245 27.325)' at line 661). All other themes use consistent destructive colors across both modes. This creates a visual inconsistency between the violet theme's light and dark variants.

Confirm whether this custom dark color for violet theme is intentional, or if the light destructive should also be updated to maintain visual parity.

♻️ Duplicate comments (2)
apps/web/src/app/domain/pages/themes/data/theme-presets.ts (1)

765-765: Decimal precision inconsistency in destructive color.

Line 765 uses 4-decimal precision ('oklch(0.6061 0.1206 15.34)') while the rest of the file consistently uses 3 decimals for oklch values. For consistency with the codebase standard, consider adjusting to 3-decimal precision: 'oklch(0.606 0.121 15.34)'.

🔎 Proposed fix for consistency
-    destructive: 'oklch(0.6061 0.1206 15.34)',
+    destructive: 'oklch(0.606 0.121 15.34)',
apps/web/src/app/domain/pages/themes/components/theme-sidebar/theme-sidebar.component.html (1)

76-84: Per-item wrapper creates cumulative padding between color pickers.

The restructuring moved py-3 from a parent container to individual per-item wrappers. This creates cumulative spacing: each color picker now has 12px top + 12px bottom padding, resulting in 24px of space between adjacent items (versus the 16px that space-y-4 would have provided on a parent).

If this increased spacing is intentional as part of the "visual fix" mentioned in the PR objectives, this looks good. However, if the intent was to maintain similar spacing, consider using space-y-3 on a parent wrapper or adjusting to py-1.5 per-item to achieve ~12-16px total spacing.

💡 Alternative: If less spacing is desired

Option 1 - Use parent wrapper with space-y utility:

+        <div class="space-y-3">
          @for (colorKey of group.colors; track colorKey) {
-            <div class="py-3">
              <app-color-picker-field
                [colorKey]="colorKey"
                [value]="currentColors()[colorKey]"
                (valueChange)="onColorChange(colorKey, $event)"
              />
-            </div>
          }
+        </div>

Option 2 - Reduce per-item padding:

          @for (colorKey of group.colors; track colorKey) {
-            <div class="py-3">
+            <div class="py-1.5">
              <app-color-picker-field
                [colorKey]="colorKey"
                [value]="currentColors()[colorKey]"
                (valueChange)="onColorChange(colorKey, $event)"
              />
            </div>
          }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc9b487 and c8b5ab6.

📒 Files selected for processing (2)
  • apps/web/src/app/domain/pages/themes/components/theme-sidebar/theme-sidebar.component.html
  • apps/web/src/app/domain/pages/themes/data/theme-presets.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • apps/web/src/app/domain/pages/themes/data/theme-presets.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Follow PR checklist including: passing tests, code pattern compliance, updated documentation, working demos, no lint/typecheck warnings, linked issues, conventional commit in title
📚 Learning: 2025-11-29T15:31:22.377Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 339
File: libs/zard/src/lib/components/carousel/carousel.component.ts:92-92
Timestamp: 2025-11-29T15:31:22.377Z
Learning: In libs/zard/src/lib/components/**/*.component.ts files using TailwindCSS, avoid suggesting individual class bindings like `[class.fill-primary]="condition"` because they can cause TailwindCSS issues. Prefer string concatenation or `[class]` binding with conditional expressions instead.

Applied to files:

  • apps/web/src/app/domain/pages/themes/components/theme-sidebar/theme-sidebar.component.html
🔇 Additional comments (1)
apps/web/src/app/domain/pages/themes/data/theme-presets.ts (1)

796-796: Nord Ice preset addition looks good!

The new preset entry follows the established pattern correctly and includes appropriate preview colors that align with the Nord Ice theme palette.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f42732a and b474abe.

⛔ Files ignored due to path filters (1)
  • .gitignore is excluded by none and included by none
📒 Files selected for processing (2)
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧰 Additional context used
📓 Path-based instructions (2)
libs/zard/**/*.{css,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS custom properties for design tokens and theming in the component library

Files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library
📚 Learning: 2025-11-30T13:27:41.206Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/popover/popover.component.ts:28-29
Timestamp: 2025-11-30T13:27:41.206Z
Learning: In libs/zard/src/lib/components/core/**/*.ts files (core utilities, plugins, and providers), use relative imports for intra-core dependencies because the ZardUI CLI performs path transformations during component installation. The CLI expects specific relative path patterns and transforms them to the target project structure. For all other component imports and application code, use zard/* path aliases.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Add barrel exports for all new components in libs/zard/src/lib/components/components.ts

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-30T08:50:23.436Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/core/providezard.ts:0-0
Timestamp: 2025-11-30T08:50:23.436Z
Learning: In libs/zard/src/lib/components/core/providezard.ts, the import paths `../core/event-manager-plugins/...` are intentionally structured this way because the ZardUI CLI transforms them to 'shared/components/core/event-manager-plugins/...' format. Other relative path combinations don't work with the current CLI implementation. This path pattern should not be simplified until the CLI transformation logic is updated.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-15T11:43:06.831Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 373
File: libs/zard/src/lib/shared/components/select/select.component.ts:33-33
Timestamp: 2025-12-15T11:43:06.831Z
Learning: In files under libs/zard/src/lib/**/*.{ts,tsx,js}, prefer the @/ path alias for imports that map to libs/zard/src/lib/* directories. For example, write import { mergeClasses } from '@/shared/utils/merge-classes' instead of using the 'zard/' alias. This improves path readability and aligns with the project's alias configuration.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Place tests co-located with components using the .spec.ts naming convention

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate test files with components using `.spec.ts` suffix next to component files

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-26T11:20:45.264Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/select/select.component.spec.ts:79-88
Timestamp: 2025-11-26T11:20:45.264Z
Learning: In ZardUI select component tests (libs/zard/src/lib/components/select/select.component.spec.ts), use fakeAsync() with flush() instead of setTimeout because the component uses setTimeout(..., 0) for focus management, which requires advancing macrotasks in tests.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-13T11:50:56.310Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 372
File: libs/zard/src/lib/shared/components/card/card.component.spec.ts:86-88
Timestamp: 2025-12-13T11:50:56.310Z
Learning: Do not flag or suggest removing `standalone: true` from test components (*.spec.ts files) or demo components (demo/*.ts files) in libs/zard/src/lib/shared/components/**/*.ts, as it is not a significant concern and the explicit flag is acceptable in these contexts.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Create demo components in the `demo/` folder with a main export, default example, and variant examples

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to **/*.spec.ts : Use Jest with happy-dom/jest-environment and Angular TestBed utilities for testing

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Use Jest with `happy-dom/jest-environment` for testing Angular components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
🔇 Additional comments (5)
libs/zard/src/lib/shared/services/dark-mode.ts (2)

23-28: LGTM! Constructor initialization follows Angular best practices.

The constructor properly initializes dark mode in browser context using isPlatformBrowser guard and inject() function. This ensures SSR compatibility and follows modern Angular patterns with functional injection.


125-133: Excellent refactor: centralized state with signals.

Refactoring isDarkMode() to read from themeSignal() instead of directly accessing localStorage centralizes state management and aligns with Angular's signal-based reactivity patterns. The logic correctly evaluates dark mode as either explicit DARK preference or SYSTEM mode with dark system preference.

libs/zard/src/lib/shared/services/dark-mode.test.ts (3)

1-60: LGTM! Test setup follows Angular testing best practices.

The test setup properly mocks browser APIs (matchMedia, localStorage) and uses TestBed for Angular service testing. The mock implementations are clean and the beforeEach/afterEach hooks ensure proper test isolation.


62-119: Comprehensive initialization test coverage.

The test cases thoroughly validate constructor-driven initialization, system preference detection, and listener management. Accessing private properties like darkModeService['darkModeQuery'] on line 64 is acceptable for unit test verification.

Minor observation: Line 101 creates a new service instance while the one from beforeEach still exists. Consider explicitly resetting TestBed before creating the new instance to avoid potential state conflicts, though this is not critical.


121-168: Excellent toggle behavior coverage.

The toggleTheme test suite comprehensively validates all toggle scenarios: bidirectional light/dark toggling, system mode transitions, and explicit mode setting. The verification of listener cleanup (lines 141, 152, 166) ensures proper resource management during mode transitions.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b474abe and c647214.

⛔ Files ignored due to path filters (1)
  • .gitignore is excluded by none and included by none
📒 Files selected for processing (2)
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧰 Additional context used
📓 Path-based instructions (2)
libs/zard/**/*.{css,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS custom properties for design tokens and theming in the component library

Files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Keep commit messages in present tense, single line format with scope and description (e.g., '✨ feat(popover): add popover component')
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library
📚 Learning: 2025-11-30T13:27:41.206Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/popover/popover.component.ts:28-29
Timestamp: 2025-11-30T13:27:41.206Z
Learning: In libs/zard/src/lib/components/core/**/*.ts files (core utilities, plugins, and providers), use relative imports for intra-core dependencies because the ZardUI CLI performs path transformations during component installation. The CLI expects specific relative path patterns and transforms them to the target project structure. For all other component imports and application code, use zard/* path aliases.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Add barrel exports for all new components in libs/zard/src/lib/components/components.ts

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-30T08:50:23.436Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/core/providezard.ts:0-0
Timestamp: 2025-11-30T08:50:23.436Z
Learning: In libs/zard/src/lib/components/core/providezard.ts, the import paths `../core/event-manager-plugins/...` are intentionally structured this way because the ZardUI CLI transforms them to 'shared/components/core/event-manager-plugins/...' format. Other relative path combinations don't work with the current CLI implementation. This path pattern should not be simplified until the CLI transformation logic is updated.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-29T15:31:22.377Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 339
File: libs/zard/src/lib/components/carousel/carousel.component.ts:92-92
Timestamp: 2025-11-29T15:31:22.377Z
Learning: In libs/zard/src/lib/components/**/*.component.ts files using TailwindCSS, avoid suggesting individual class bindings like `[class.fill-primary]="condition"` because they can cause TailwindCSS issues. Prefer string concatenation or `[class]` binding with conditional expressions instead.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-15T11:43:06.831Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 373
File: libs/zard/src/lib/shared/components/select/select.component.ts:33-33
Timestamp: 2025-12-15T11:43:06.831Z
Learning: In files under libs/zard/src/lib/**/*.{ts,tsx,js}, prefer the @/ path alias for imports that map to libs/zard/src/lib/* directories. For example, write import { mergeClasses } from '@/shared/utils/merge-classes' instead of using the 'zard/' alias. This improves path readability and aligns with the project's alias configuration.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Place tests co-located with components using the .spec.ts naming convention

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate test files with components using `.spec.ts` suffix next to component files

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-26T11:20:45.264Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/select/select.component.spec.ts:79-88
Timestamp: 2025-11-26T11:20:45.264Z
Learning: In ZardUI select component tests (libs/zard/src/lib/components/select/select.component.spec.ts), use fakeAsync() with flush() instead of setTimeout because the component uses setTimeout(..., 0) for focus management, which requires advancing macrotasks in tests.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-13T11:50:56.310Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 372
File: libs/zard/src/lib/shared/components/card/card.component.spec.ts:86-88
Timestamp: 2025-12-13T11:50:56.310Z
Learning: Do not flag or suggest removing `standalone: true` from test components (*.spec.ts files) or demo components (demo/*.ts files) in libs/zard/src/lib/shared/components/**/*.ts, as it is not a significant concern and the explicit flag is acceptable in these contexts.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to **/*.spec.ts : Use Jest with happy-dom/jest-environment and Angular TestBed utilities for testing

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Use Jest with `happy-dom/jest-environment` for testing Angular components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
🔇 Additional comments (5)
libs/zard/src/lib/shared/services/dark-mode.ts (3)

23-28: Clean constructor initialization with proper SSR guard.

Using this.isBrowser to gate browser-specific initialization is the right approach for Angular Universal compatibility. The eager initialization of darkModeQuery and initializeTheme() ensures consistent theme state from service creation.


88-102: Initialization logic is clean and handles all theme states correctly.

The flow properly distinguishes between stored explicit themes (LIGHT/DARK) and SYSTEM mode, only registering the system listener when appropriate. The previous redundant nested condition has been addressed.


128-131: Good refactor: reading from signal rather than localStorage.

Using this.themeSignal() as the source of truth is consistent with Angular's reactive patterns and avoids redundant localStorage reads. The signal is already kept in sync with persistence in applyTheme() and initializeTheme().

libs/zard/src/lib/shared/services/dark-mode.test.ts (2)

121-168: Solid coverage of toggleTheme behavior.

These tests thoroughly exercise the toggle functionality across all theme modes, including proper verification that system listeners are added/removed when transitioning to/from SYSTEM mode. The assertions on both themeMode() and listener management are well-structured.


83-96: Good defensive test structure with fallback fail().

Using find() to locate the registered callback and calling fail() if not found ensures the test doesn't silently pass when listener registration fails. This pattern makes test failures more diagnosable.

@mikij mikij force-pushed the themes-update branch 2 times, most recently from 5e6b3ab to c8825e0 Compare December 22, 2025 17:59
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
libs/zard/src/lib/shared/services/dark-mode.test.ts (2)

58-60: Past review comment remains valid: Clear localStorage between tests.

The localStorage mock isn't cleared in afterEach, which could cause state leakage between tests if any test modifies it.

🔎 Proposed fix
  afterEach(() => {
    jest.clearAllMocks();
+   window.localStorage.clear();
  });

Based on learnings, this aligns with Jest best practices for test isolation.


98-104: Past review comment remains valid: Test doesn't verify initialization.

Since ZardDarkMode is a root-level singleton, TestBed.inject(ZardDarkMode) on line 101 returns the instance already created in beforeEach (line 55) when matches was false. Setting matches = true on line 99 after construction doesn't test initialization—it only tests the computed signal's reactivity.

🔎 Proposed fix to properly test initialization
  it('initializes with system dark theme when no stored theme exists', () => {
+   TestBed.resetTestingModule();
    mockMediaQueryList.matches = true;
+   mockMediaQueryList.addEventListener.mockClear();
+
+   TestBed.configureTestingModule({
+     providers: [ZardDarkMode],
+   });

    const newService = TestBed.inject(ZardDarkMode);

    expect(newService.themeMode()).toBe(EDarkModes.DARK);
+   expect(mockMediaQueryList.addEventListener).toHaveBeenCalled();
  });

The test on lines 106-119 demonstrates the correct pattern for verifying initialization behavior.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c647214 and 5e6b3ab.

⛔ Files ignored due to path filters (1)
  • .gitignore is excluded by none and included by none
📒 Files selected for processing (3)
  • apps/web/src/index.html
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧰 Additional context used
📓 Path-based instructions (2)
libs/zard/**/*.{css,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS custom properties for design tokens and theming in the component library

Files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library
📚 Learning: 2025-11-30T13:27:41.206Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/popover/popover.component.ts:28-29
Timestamp: 2025-11-30T13:27:41.206Z
Learning: In libs/zard/src/lib/components/core/**/*.ts files (core utilities, plugins, and providers), use relative imports for intra-core dependencies because the ZardUI CLI performs path transformations during component installation. The CLI expects specific relative path patterns and transforms them to the target project structure. For all other component imports and application code, use zard/* path aliases.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • apps/web/src/index.html
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-30T08:50:23.436Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/core/providezard.ts:0-0
Timestamp: 2025-11-30T08:50:23.436Z
Learning: In libs/zard/src/lib/components/core/providezard.ts, the import paths `../core/event-manager-plugins/...` are intentionally structured this way because the ZardUI CLI transforms them to 'shared/components/core/event-manager-plugins/...' format. Other relative path combinations don't work with the current CLI implementation. This path pattern should not be simplified until the CLI transformation logic is updated.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-29T15:31:22.377Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 339
File: libs/zard/src/lib/components/carousel/carousel.component.ts:92-92
Timestamp: 2025-11-29T15:31:22.377Z
Learning: In libs/zard/src/lib/components/**/*.component.ts files using TailwindCSS, avoid suggesting individual class bindings like `[class.fill-primary]="condition"` because they can cause TailwindCSS issues. Prefer string concatenation or `[class]` binding with conditional expressions instead.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • apps/web/src/index.html
📚 Learning: 2025-12-15T11:43:06.831Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 373
File: libs/zard/src/lib/shared/components/select/select.component.ts:33-33
Timestamp: 2025-12-15T11:43:06.831Z
Learning: In files under libs/zard/src/lib/**/*.{ts,tsx,js}, prefer the @/ path alias for imports that map to libs/zard/src/lib/* directories. For example, write import { mergeClasses } from '@/shared/utils/merge-classes' instead of using the 'zard/' alias. This improves path readability and aligns with the project's alias configuration.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Place tests co-located with components using the .spec.ts naming convention

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate test files with components using `.spec.ts` suffix next to component files

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-26T11:20:45.264Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/select/select.component.spec.ts:79-88
Timestamp: 2025-11-26T11:20:45.264Z
Learning: In ZardUI select component tests (libs/zard/src/lib/components/select/select.component.spec.ts), use fakeAsync() with flush() instead of setTimeout because the component uses setTimeout(..., 0) for focus management, which requires advancing macrotasks in tests.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-13T11:50:56.310Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 372
File: libs/zard/src/lib/shared/components/card/card.component.spec.ts:86-88
Timestamp: 2025-12-13T11:50:56.310Z
Learning: Do not flag or suggest removing `standalone: true` from test components (*.spec.ts files) or demo components (demo/*.ts files) in libs/zard/src/lib/shared/components/**/*.ts, as it is not a significant concern and the explicit flag is acceptable in these contexts.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Create demo components in the `demo/` folder with a main export, default example, and variant examples

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to **/*.spec.ts : Use Jest with happy-dom/jest-environment and Angular TestBed utilities for testing

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Use Jest with `happy-dom/jest-environment` for testing Angular components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
🔇 Additional comments (5)
libs/zard/src/lib/shared/services/dark-mode.ts (3)

23-28: LGTM! Clean constructor initialization.

The constructor properly initializes dark mode query and theme state in the browser context. Good use of platform checking and the Angular inject() function.


88-102: LGTM! Initialization logic is correct.

The theme initialization properly handles all cases (no stored theme, SYSTEM mode, and explicit LIGHT/DARK). The redundant nested condition from the previous review has been successfully addressed.


123-131: LGTM! Proper signal usage.

Line 129 correctly derives the stored theme from themeSignal() rather than directly accessing localStorage, which is the idiomatic approach for Angular signals. This ensures consistency with the signal-based state management.

libs/zard/src/lib/shared/services/dark-mode.test.ts (2)

62-96: LGTM! Well-structured initialization tests.

These tests properly verify:

  • Dark mode query initialization on service creation
  • System listener registration/removal when switching modes
  • Theme updates when system preference changes

The callback extraction pattern on line 86 is a clean way to test event handling.


121-168: LGTM! Comprehensive toggleTheme coverage.

The test suite thoroughly covers all toggle scenarios:

  • Parameterless toggle alternating between modes
  • Toggle from SYSTEM mode (both light and dark system preferences)
  • Explicit theme mode setting
  • Proper listener cleanup when switching away from SYSTEM mode

Excellent test coverage for this critical functionality.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
libs/zard/src/lib/shared/services/dark-mode.test.ts (1)

100-106: Test still doesn't verify initialization behavior.

This test was previously flagged as not properly testing initialization because TestBed.inject(ZardDarkMode) returns the singleton created in beforeEach (with matches: false). Setting matches = true on line 101 after construction doesn't test initialization—it tests signal reactivity.

Despite being marked "✅ Addressed in commit 5e6b3ab" in past comments, the issue persists in this code.

🔎 Proposed fix to properly test initialization

Follow the pattern from the test on lines 108-121:

  it('initializes with system dark theme when no stored theme exists', () => {
+   TestBed.resetTestingModule();
    mockMediaQueryList.matches = true;
+   mockMediaQueryList.addEventListener.mockClear();
+
+   TestBed.configureTestingModule({
+     providers: [ZardDarkMode],
+   });

    const newService = TestBed.inject(ZardDarkMode);

    expect(newService.themeMode()).toBe(EDarkModes.DARK);
  });

This ensures the service is constructed after setting matches = true, properly verifying initialization behavior.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5e6b3ab and 4c6e15f.

⛔ Files ignored due to path filters (1)
  • .gitignore is excluded by none and included by none
📒 Files selected for processing (3)
  • apps/web/src/index.html
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧰 Additional context used
📓 Path-based instructions (2)
libs/zard/**/*.{css,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS custom properties for design tokens and theming in the component library

Files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support

Applied to files:

  • apps/web/src/index.html
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes

Applied to files:

  • apps/web/src/index.html
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Place tests co-located with components using the .spec.ts naming convention

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate test files with components using `.spec.ts` suffix next to component files

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-26T11:20:45.264Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/select/select.component.spec.ts:79-88
Timestamp: 2025-11-26T11:20:45.264Z
Learning: In ZardUI select component tests (libs/zard/src/lib/components/select/select.component.spec.ts), use fakeAsync() with flush() instead of setTimeout because the component uses setTimeout(..., 0) for focus management, which requires advancing macrotasks in tests.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-13T11:50:56.310Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 372
File: libs/zard/src/lib/shared/components/card/card.component.spec.ts:86-88
Timestamp: 2025-12-13T11:50:56.310Z
Learning: Do not flag or suggest removing `standalone: true` from test components (*.spec.ts files) or demo components (demo/*.ts files) in libs/zard/src/lib/shared/components/**/*.ts, as it is not a significant concern and the explicit flag is acceptable in these contexts.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Create demo components in the `demo/` folder with a main export, default example, and variant examples

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to **/*.spec.ts : Use Jest with happy-dom/jest-environment and Angular TestBed utilities for testing

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-15T11:43:06.831Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 373
File: libs/zard/src/lib/shared/components/select/select.component.ts:33-33
Timestamp: 2025-12-15T11:43:06.831Z
Learning: In files under libs/zard/src/lib/**/*.{ts,tsx,js}, prefer the @/ path alias for imports that map to libs/zard/src/lib/* directories. For example, write import { mergeClasses } from '@/shared/utils/merge-classes' instead of using the 'zard/' alias. This improves path readability and aligns with the project's alias configuration.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-30T13:27:41.206Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/popover/popover.component.ts:28-29
Timestamp: 2025-11-30T13:27:41.206Z
Learning: In libs/zard/src/lib/components/core/**/*.ts files (core utilities, plugins, and providers), use relative imports for intra-core dependencies because the ZardUI CLI performs path transformations during component installation. The CLI expects specific relative path patterns and transforms them to the target project structure. For all other component imports and application code, use zard/* path aliases.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-29T15:31:22.377Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 339
File: libs/zard/src/lib/components/carousel/carousel.component.ts:92-92
Timestamp: 2025-11-29T15:31:22.377Z
Learning: In libs/zard/src/lib/components/**/*.component.ts files using TailwindCSS, avoid suggesting individual class bindings like `[class.fill-primary]="condition"` because they can cause TailwindCSS issues. Prefer string concatenation or `[class]` binding with conditional expressions instead.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
🔇 Additional comments (7)
apps/web/src/index.html (1)

70-75: Verify asymmetric localStorage persistence is intentional.

When no stored preference exists and system prefers dark mode, line 71 persists 'system' to localStorage. However, when system prefers light mode (lines 73-75), no value is persisted. This asymmetry means:

  • First visit in dark mode → localStorage.darkMode = 'system'
  • First visit in light mode → localStorage.darkMode remains unset

If the user's system preference changes after their first visit, the behavior will differ depending on whether their initial visit was in dark or light mode. Is this intentional?

💡 Consider symmetric initialization

If consistent behavior is desired:

       } else if (systemDarkMode && hasDocument) {
         localStorage.setItem('darkMode', 'system');
         document.documentElement.classList.add('dark');
       } else if (hasDocument) {
+        localStorage.setItem('darkMode', 'system');
         document.documentElement.classList.remove('dark');
       }

This ensures both paths persist 'system' when no preference is stored, making the service initialization in dark-mode.ts behave consistently regardless of initial system preference.

libs/zard/src/lib/shared/services/dark-mode.ts (3)

23-28: LGTM: Clean constructor initialization.

The constructor properly initializes the dark mode query and theme state in the browser environment. Guards with isBrowser check and delegates to initializeTheme for setup logic, keeping concerns separated.


88-102: LGTM: Solid initialization logic.

The initializeTheme method correctly:

  • Loads persisted preference and sets the signal
  • Defaults to system preference when no explicit choice is stored
  • Manages system-change listeners appropriately (enabled for SYSTEM mode, disabled otherwise)

The previously flagged redundant nested condition has been removed.


129-129: LGTM: Signal as source of truth.

Using themeSignal() instead of reading localStorage directly is more efficient and aligns with Angular's signal-based reactivity. The signal is kept in sync with localStorage via applyTheme, making this a clean refactor.

libs/zard/src/lib/shared/services/dark-mode.test.ts (3)

1-62: LGTM: Comprehensive test setup.

The test setup correctly:

  • Mocks matchMedia with controllable matches state and listener tracking
  • Mocks localStorage with a proper in-memory implementation
  • Clears localStorage in afterEach to prevent state leakage between tests (addressing previous feedback)

Clean and thorough test infrastructure.


64-98: LGTM: Thorough system-change detection tests.

These tests comprehensively verify:

  • Dark mode query initialization in the constructor
  • Listener lifecycle (add when entering SYSTEM mode, remove when leaving)
  • System preference change callback updates the theme correctly

Clear test structure with good coverage of the system-aware behavior.


108-170: LGTM: Excellent test coverage of public API.

Lines 108-121 correctly reset TestBed to create a fresh service instance, properly testing constructor initialization behavior.

The toggleTheme test suite (lines 123-170) comprehensively covers:

  • Toggling without arguments (light ↔ dark)
  • Toggling from system-based modes
  • Setting specific target modes
  • Listener lifecycle during mode transitions

Well-organized tests with clear expectations.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
apps/web/src/index.html (1)

126-126: Remove unused hasBody variable.

The hasBody variable is declared but never used. After the refactor to use document.documentElement, this check is no longer needed.

🔎 Proposed fix
-      let hasBody = !!document && !!document.body;
       let hasDocument = !!document && !!document.documentElement;
libs/zard/src/lib/shared/services/dark-mode.test.ts (1)

100-106: Test doesn't verify initialization—it tests computed signal reactivity.

The service is providedIn: 'root', so TestBed.inject(ZardDarkMode) at line 103 returns the singleton created in beforeEach with matches: false already initialized. Setting matches = true on line 101 after the singleton exists only changes the mock's state. When themeMode() is called, the computed signal reads the live isDarkMode() value (which checks the current matches), making the test pass but testing reactivity, not initialization.

To properly test initialization with system dark mode enabled, reset TestBed like the test at lines 108-121:

   it('initializes with system dark theme when no stored theme exists', () => {
+    TestBed.resetTestingModule();
     mockMediaQueryList.matches = true;
+    mockMediaQueryList.addEventListener.mockClear();
+
+    TestBed.configureTestingModule({
+      providers: [ZardDarkMode],
+    });

     const newService = TestBed.inject(ZardDarkMode);

     expect(newService.themeMode()).toBe(EDarkModes.DARK);
   });
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c6e15f and 422f9eb.

⛔ Files ignored due to path filters (1)
  • .gitignore is excluded by none and included by none
📒 Files selected for processing (4)
  • apps/web/src/index.html
  • apps/web/src/styles.css
  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧰 Additional context used
📓 Path-based instructions (2)
libs/zard/**/*.{css,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS custom properties for design tokens and theming in the component library

Files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Place tests co-located with components using the .spec.ts naming convention

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate test files with components using `.spec.ts` suffix next to component files

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • apps/web/src/index.html
📚 Learning: 2025-12-13T11:50:56.310Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 372
File: libs/zard/src/lib/shared/components/card/card.component.spec.ts:86-88
Timestamp: 2025-12-13T11:50:56.310Z
Learning: Do not flag or suggest removing `standalone: true` from test components (*.spec.ts files) or demo components (demo/*.ts files) in libs/zard/src/lib/shared/components/**/*.ts, as it is not a significant concern and the explicit flag is acceptable in these contexts.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-26T11:20:45.264Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/select/select.component.spec.ts:79-88
Timestamp: 2025-11-26T11:20:45.264Z
Learning: In ZardUI select component tests (libs/zard/src/lib/components/select/select.component.spec.ts), use fakeAsync() with flush() instead of setTimeout because the component uses setTimeout(..., 0) for focus management, which requires advancing macrotasks in tests.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Create demo components in the `demo/` folder with a main export, default example, and variant examples

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Add barrel exports for all new components in libs/zard/src/lib/components/components.ts

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to **/*.spec.ts : Use Jest with happy-dom/jest-environment and Angular TestBed utilities for testing

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
📚 Learning: 2025-12-15T11:43:06.831Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 373
File: libs/zard/src/lib/shared/components/select/select.component.ts:33-33
Timestamp: 2025-12-15T11:43:06.831Z
Learning: In files under libs/zard/src/lib/**/*.{ts,tsx,js}, prefer the @/ path alias for imports that map to libs/zard/src/lib/* directories. For example, write import { mergeClasses } from '@/shared/utils/merge-classes' instead of using the 'zard/' alias. This improves path readability and aligns with the project's alias configuration.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.test.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/src/styles.css : Set up `src/styles.css` with Tailwind CSS configuration and design tokens using CSS `theme` and `plugin` directives

Applied to files:

  • apps/web/src/index.html
📚 Learning: 2025-11-29T15:31:22.377Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 339
File: libs/zard/src/lib/components/carousel/carousel.component.ts:92-92
Timestamp: 2025-11-29T15:31:22.377Z
Learning: In libs/zard/src/lib/components/**/*.component.ts files using TailwindCSS, avoid suggesting individual class bindings like `[class.fill-primary]="condition"` because they can cause TailwindCSS issues. Prefer string concatenation or `[class]` binding with conditional expressions instead.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
🔇 Additional comments (6)
libs/zard/src/lib/shared/services/dark-mode.ts (3)

23-28: LGTM: Constructor follows Angular best practices.

The constructor properly gates browser-only initialization using isPlatformBrowser() and leverages the inject() function. The initialization flow is explicit and clear.


88-102: LGTM: Initialization logic is clear and correct.

The initializeTheme method properly handles three scenarios:

  1. No stored theme → defaults to system preference with listener
  2. Stored SYSTEM mode → applies system preference with listener
  3. Stored explicit mode → applies stored preference without listener

The flow is straightforward and the system listener management is correctly placed.


123-131: LGTM: Improved efficiency by reading from signal instead of localStorage.

Refactoring isDarkMode to read from themeSignal (line 129) instead of directly accessing localStorage improves performance and maintains the signal as the single source of truth. This follows reactive patterns and reduces I/O overhead.

libs/zard/src/lib/shared/services/dark-mode.test.ts (3)

14-62: LGTM: Comprehensive test setup with proper mocking and cleanup.

The test setup properly mocks window.matchMedia and localStorage with complete implementations. The afterEach hook on line 61 clears localStorage between tests, preventing state leakage.


85-98: LGTM: Proper verification of system preference change handling.

The test correctly retrieves the registered callback (line 88), simulates a system preference change (line 92), and validates the theme update (line 94). The fail() guard (line 96) properly handles unexpected callback absence.


123-170: LGTM: Comprehensive toggleTheme test coverage.

The test suite thoroughly covers:

  • Simple toggle between LIGHT and DARK modes
  • Transitions from SYSTEM mode to explicit modes with listener cleanup
  • Setting specific theme modes with proper listener management
  • System preference integration (lines 136, 147, 164)

All critical paths are validated.

@mikij mikij force-pushed the themes-update branch 2 times, most recently from 408a462 to 415baf5 Compare December 23, 2025 20:28
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
apps/web/src/index.html (1)

123-123: Remove unused hasBody variable.

The hasBody variable is declared but never used. The code correctly uses hasDocument and document.documentElement throughout. Clean up the dead code.

🔎 Proposed fix
-      let hasBody = !!document && !!document.body;
       let hasDocument = !!document && !!document.documentElement;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 408a462 and 415baf5.

📒 Files selected for processing (3)
  • apps/web/src/index.html
  • apps/web/src/server.ts
  • apps/web/src/styles.css
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • apps/web/src/server.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Keep commit messages in present tense, single line format with scope and description (e.g., '✨ feat(popover): add popover component')
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Applies to libs/blocks/src/lib/**/*.component.html : Use TailwindCSS utility classes for styling, following responsive design patterns with prefixes for breakpoints (sm:, lg:) and ensure accessibility with semantic HTML and ARIA guidelines

Applied to files:

  • apps/web/src/index.html
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library

Applied to files:

  • apps/web/src/index.html
🪛 GitHub Check: CodeQL
apps/web/src/server.ts

[failure] 227-227: Incomplete URL substring sanitization
'fonts.googleapis.com' can be anywhere in the URL, and arbitrary hosts may come before or after it.

🔇 Additional comments (2)
apps/web/src/server.ts (1)

232-237: LGTM: Caching strategy aligns with font optimization goals.

The 1-year immutable cache for fonts (line 232) and 5-minute revalidation for HTML (line 236) appropriately balance performance and update propagation. This complements the font preloading strategy in index.html.

apps/web/src/index.html (1)

126-135: LGTM: Dark mode initialization correctly handles localStorage preferences.

The dark mode logic properly handles 'dark', 'light', and system preference fallback, aligning with the dark-mode service changes in libs/zard/src/lib/shared/services/dark-mode.ts.

@mikij mikij force-pushed the themes-update branch 2 times, most recently from e59d413 to 5536138 Compare December 24, 2025 11:50
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
libs/zard/src/lib/shared/services/dark-mode.ts (1)

114-121: Consider consolidating dark mode class naming.

Line 118 adds dark-theme class alongside the existing dark class on line 117. While not incorrect, maintaining two classes for the same state could cause confusion. Verify that both classes are required for compatibility or different styling contexts.

#!/bin/bash
# Verify usage of both 'dark' and 'dark-theme' classes across the codebase
rg -n "\.dark-theme\b|class.*dark-theme" --type=css --type=html --type=ts -C2
♻️ Duplicate comments (1)
libs/zard/src/lib/shared/services/dark-mode.spec.ts (1)

104-118: Add TestBed.tick() after init() for consistent effect flushing.

Line 115 calls newService.init() but doesn't flush effects before the assertion on line 117. While this test may currently pass, adding TestBed.tick() after init() ensures effects run consistently across all tests.

🔎 Proposed fix for consistency
    const newService = TestBed.inject(ZardDarkMode);
    newService.init();
+   TestBed.tick();

    expect(newService.themeMode()).toBe(EDarkModes.DARK);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9040700 and b377bb3.

⛔ Files ignored due to path filters (4)
  • apps/web/public/r/dark-mode.json is excluded by !apps/web/public/** and included by apps/**
  • package-lock.json is excluded by !**/package-lock.json and included by none
  • package.json is excluded by none and included by none
  • packages/cli/src/commands/add/dark-mode-setup.ts is excluded by !packages/** and included by none
📒 Files selected for processing (6)
  • apps/web/project.json
  • apps/web/src/app/shared/services/markdown.service.ts
  • apps/web/src/index.html
  • apps/web/src/styles.css
  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • apps/web/src/app/shared/services/markdown.service.ts
  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
libs/zard/**/*.{css,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS custom properties for design tokens and theming in the component library

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use Jest with @happy-dom/jest-environment and Angular TestBed utilities for testing

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
🧠 Learnings (28)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Implement TailwindCSS v4 with PostCSS for styling and use class merging with tailwind-merge to resolve conflicts

Applied to files:

  • apps/web/src/app/shared/services/markdown.service.ts
  • apps/web/src/styles.css
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use `mergeClasses()` utility with `clsx` and `tailwind-merge` to resolve class conflicts in component styling

Applied to files:

  • apps/web/src/app/shared/services/markdown.service.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Applies to libs/blocks/src/lib/**/*.component.html : Use TailwindCSS utility classes for styling, following responsive design patterns with prefixes for breakpoints (sm:, lg:) and ensure accessibility with semantic HTML and ARIA guidelines

Applied to files:

  • apps/web/src/app/shared/services/markdown.service.ts
  • apps/web/src/index.html
  • apps/web/src/styles.css
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Components should be built with TailwindCSS v4 using the new inline configuration approach (no `tailwind.config.js` needed, configuration via `.postcssrc.json`, design tokens defined in CSS with `theme`)

Applied to files:

  • apps/web/src/app/shared/services/markdown.service.ts
  • apps/web/src/styles.css
📚 Learning: 2025-11-29T15:31:22.377Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 339
File: libs/zard/src/lib/components/carousel/carousel.component.ts:92-92
Timestamp: 2025-11-29T15:31:22.377Z
Learning: In libs/zard/src/lib/components/**/*.component.ts files using TailwindCSS, avoid suggesting individual class bindings like `[class.fill-primary]="condition"` because they can cause TailwindCSS issues. Prefer string concatenation or `[class]` binding with conditional expressions instead.

Applied to files:

  • apps/web/src/app/shared/services/markdown.service.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library

Applied to files:

  • apps/web/src/index.html
  • apps/web/src/styles.css
  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-26T10:13:44.258Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/layout/sidebar.component.ts:22-22
Timestamp: 2025-11-26T10:13:44.258Z
Learning: The ZardUI CLI will automatically add `provideZard()` to the app configuration and install the core component before the next CLI release, addressing the breaking change requirement for the event manager plugins.

Applied to files:

  • apps/web/src/index.html
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/src/styles.css : Set up `src/styles.css` with Tailwind CSS configuration and design tokens using CSS `theme` and `plugin` directives

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Use TailwindCSS v4 with PostCSS for styling the component library

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Place tests co-located with components using the .spec.ts naming convention

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate test files with components using `.spec.ts` suffix next to component files

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-26T11:20:45.264Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/select/select.component.spec.ts:79-88
Timestamp: 2025-11-26T11:20:45.264Z
Learning: In ZardUI select component tests (libs/zard/src/lib/components/select/select.component.spec.ts), use fakeAsync() with flush() instead of setTimeout because the component uses setTimeout(..., 0) for focus management, which requires advancing macrotasks in tests.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-13T11:50:56.310Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 372
File: libs/zard/src/lib/shared/components/card/card.component.spec.ts:86-88
Timestamp: 2025-12-13T11:50:56.310Z
Learning: Do not flag or suggest removing `standalone: true` from test components (*.spec.ts files) or demo components (demo/*.ts files) in libs/zard/src/lib/shared/components/**/*.ts, as it is not a significant concern and the explicit flag is acceptable in these contexts.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to **/*.spec.ts : Use Jest with happy-dom/jest-environment and Angular TestBed utilities for testing

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use OnPush change detection strategy in Angular components: `changeDetection: ChangeDetectionStrategy.OnPush`

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Create demo components in the `demo/` folder with a main export, default example, and variant examples

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use Signal-based inputs with the `input()` function instead of Input decorators in Angular components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for performance optimization in components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-15T11:43:06.831Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 373
File: libs/zard/src/lib/shared/components/select/select.component.ts:33-33
Timestamp: 2025-12-15T11:43:06.831Z
Learning: In files under libs/zard/src/lib/**/*.{ts,tsx,js}, prefer the @/ path alias for imports that map to libs/zard/src/lib/* directories. For example, write import { mergeClasses } from '@/shared/utils/merge-classes' instead of using the 'zard/' alias. This improves path readability and aligns with the project's alias configuration.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-14T22:52:09.135Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 326
File: libs/zard/src/lib/components/input/float.label.component.ts:71-0
Timestamp: 2025-11-14T22:52:09.135Z
Learning: In libs/zard/src/lib/components/*/*.component.ts files, move HostListener and HostBinding to the Component decorator's host property instead of using decorators on class members (e.g., host: { '(input)': 'onInput()' }).

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use computed properties in Angular components for reactive class calculations: `protected readonly classes = computed(() => ...)`

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-30T13:27:41.206Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/popover/popover.component.ts:28-29
Timestamp: 2025-11-30T13:27:41.206Z
Learning: In libs/zard/src/lib/components/core/**/*.ts files (core utilities, plugins, and providers), use relative imports for intra-core dependencies because the ZardUI CLI performs path transformations during component installation. The CLI expects specific relative path patterns and transforms them to the target project structure. For all other component imports and application code, use zard/* path aliases.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T21:17:39.497Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 383
File: libs/zard/src/lib/shared/components/carousel/carousel.component.ts:114-115
Timestamp: 2025-12-21T21:17:39.497Z
Learning: In Angular components using signal inputs (input()) with types from external libraries like Embla Carousel, explicit type annotations (e.g., `readonly zOptions: InputSignal<EmblaOptionsType> = input<EmblaOptionsType>(...)`) may be necessary to prevent TypeScript IDE errors about inferred types referencing non-portable node_modules paths. This is not redundant when the annotation prevents the "cannot be named without a reference to node_modules" error.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
🔇 Additional comments (20)
apps/web/src/app/shared/services/markdown.service.ts (1)

52-59: Formatting improvements for readability — LGTM!

The multi-line reformatting of the h2 and inline code class arrays improves maintainability and readability without altering behavior. All Tailwind utility classes remain valid and unchanged in value/order.

Also applies to: 95-104

apps/web/src/index.html (1)

5-6: LGTM! Clean consolidation of critical head elements.

Moving <base href="/" /> and <title> to the top of the <head> follows best practices—base href is required for Angular routing and should be declared early, and title placement here improves SEO parsing. The title content correctly matches your OpenGraph metadata at line 27.

apps/web/src/styles.css (2)

2-3: LGTM! Font loading strategy improved.

Using @fontsource-variable npm packages eliminates the fragility of hard-coded Google Fonts URLs (version paths, filename mismatches) flagged in previous reviews. This approach provides version-controlled, self-hosted variable fonts that are more reliable and maintainable.


14-15: LGTM! Font variables align with imports.

CSS custom properties correctly reference the imported @fontsource-variable font families with appropriate fallbacks. Aligns with the coding guideline to use CSS custom properties for design tokens and theming.

libs/zard/src/lib/shared/services/dark-mode.spec.ts (6)

14-58: LGTM! Test setup follows best practices.

Mock structure is comprehensive, covering matchMedia and localStorage. Calling TestBed.tick() after init() ensures effects are flushed before tests run—correct pattern per Jest and Angular TestBed utilities guidelines.


60-64: LGTM! Cleanup prevents test state leakage.

Clearing both Jest mocks and the localStorage mock ensures tests remain isolated and don't affect each other.


66-69: LGTM! Initialization verification is correct.

Test confirms matchMedia query setup and default theme behavior.


71-88: LGTM! Listener lifecycle tests are comprehensive.

Tests verify that system change listeners are correctly attached when theme is set to SYSTEM and detached when changing away from SYSTEM. Proper use of TestBed.tick() ensures effects execute before assertions.


90-102: LGTM! System preference change simulation is correct.

Test properly extracts the registered callback, verifies its existence, and simulates a system preference change to validate reactivity. Addresses previous concern about using fail() (not available in Jest) by using expect().toBeDefined() instead.


120-189: LGTM! Theme toggle tests are comprehensive and correct.

Test suite thoroughly covers toggle behavior across different scenarios (light↔dark, system→explicit mode). Proper use of TestBed.tick() throughout ensures effects execute before assertions, addressing all previous review concerns.

libs/zard/src/lib/shared/services/dark-mode.ts (9)

1-15: LGTM! Modern Angular patterns applied correctly.

Service uses inject() for DI, DestroyRef for lifecycle management (replacing OnDestroy), and MediaMatcher from Angular CDK for browser API abstraction. Aligns with Angular best practices: signals, inject(), and strict typing.


16-23: LGTM! Dependency injection and state management properly implemented.

Consistent use of inject() for all dependencies. Signal-based state with EDarkModes.SYSTEM default is appropriate. MediaMatcher query initialized eagerly for immediate availability.


25-31: LGTM! Computed signal correctly derives resolved theme.

The computed() signal properly resolves SYSTEM mode to DARK/LIGHT based on system preference while returning explicit modes directly. Follows Angular signal best practices.


33-37: LGTM! Lifecycle cleanup properly implemented with DestroyRef.

Constructor correctly guards browser-specific cleanup with isBrowser check and uses DestroyRef.onDestroy() to remove system change listeners. Modern Angular pattern replacing OnDestroy.


39-43: LGTM! Initialization separated from construction for SSR safety.

Public init() method allows deferred browser-context initialization, invoked via app initializer (per providezard.ts changes). Correctly guards with isBrowser check.


58-65: LGTM! Readonly signal exposure with clear documentation.

Getter returns asReadonly() signal, preventing external mutation while maintaining reactivity. JSDoc clearly explains usage and return type. Addresses previous review feedback about signal exposure pattern.


67-79: LGTM! Theme initialization logic is correct and clean.

Method properly loads stored theme, applies initial mode, and conditionally attaches system change listeners only when needed (SYSTEM mode). Addresses previous review comment about redundant nested conditions.


81-96: LGTM! Theme application correctly manages state and listeners.

Method stores theme, updates signal, derives active mode via isDarkModeActive(), and properly manages system change listeners based on mode (attached for SYSTEM, removed otherwise).


123-137: LGTM! System integration properly uses MediaMatcher.

isDarkModeActive() centralizes active mode detection, checking both explicit DARK and SYSTEM with query match. handleSystemChanges() properly manages MediaMatcher listener lifecycle with consistent callback reference.

apps/web/project.json (1)

42-46: This optimization is appropriate for the project architecture.

The inlineCritical: false setting is correct for this SSR + prerendered application. Since styles are rendered server-side and pages are pregenerated, inlining critical CSS in the <head> would be redundant. TailwindCSS v4 uses different optimization strategies that don't rely on critical CSS extraction, so the assumption about FCP/LCP degradation doesn't apply here.

Likely an incorrect or invalid review comment.

@mikij mikij force-pushed the themes-update branch 3 times, most recently from 762c7d1 to 4d9440b Compare December 24, 2025 19:50
@mikij mikij changed the title ✨ feat: adding preset and visual fix ✨ feat: adding preset, dark mode service improvements, prevent SSR flickering Dec 24, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/web/src/index.html (2)

75-75: Log errors for debuggability.

The empty catch block silently swallows all errors. While preventing crashes is good, this makes debugging theme initialization issues difficult (e.g., localStorage access failures, matchMedia errors).

🔎 Proposed fix
-        } catch (_) {}
+        } catch (e) {
+          console.error('[Theme Init]', e);
+        }

61-77: Fix data-theme attribute inconsistency between inline script and service initialization.

The inline script (line 75) sets data-theme to the raw localStorage value ('dark', 'light', or 'system'), preserving user intent. However, ZardDarkMode.updateThemeMode() (line 118) sets data-theme to only the resolved theme ('dark' or 'light'), dropping the 'system' value entirely.

This causes a behavioral mismatch when no theme is explicitly set:

  • Script: data-theme="system"
  • Service after init(): data-theme="dark" or "light" (resolved value)

If CSS or logic depends on detecting data-theme="system" to distinguish user preference from system default, the service initialization will break this. Update updateThemeMode() to preserve the raw theme value in data-theme while the colorScheme style and dark class remain resolved-only.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b30011e and 545a52d.

⛔ Files ignored due to path filters (4)
  • apps/web/public/r/dark-mode.json is excluded by !apps/web/public/** and included by apps/**
  • package-lock.json is excluded by !**/package-lock.json and included by none
  • package.json is excluded by none and included by none
  • packages/cli/src/commands/add/dark-mode-setup.ts is excluded by !packages/** and included by none
📒 Files selected for processing (4)
  • apps/web/project.json
  • apps/web/src/index.html
  • apps/web/src/styles.css
  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
🧰 Additional context used
📓 Path-based instructions (3)
libs/zard/**/*.{css,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS custom properties for design tokens and theming in the component library

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use Jest with @happy-dom/jest-environment and Angular TestBed utilities for testing

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
🧠 Learnings (23)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Place tests co-located with components using the .spec.ts naming convention

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate test files with components using `.spec.ts` suffix next to component files

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-13T11:50:56.310Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 372
File: libs/zard/src/lib/shared/components/card/card.component.spec.ts:86-88
Timestamp: 2025-12-13T11:50:56.310Z
Learning: Do not flag or suggest removing `standalone: true` from test components (*.spec.ts files) or demo components (demo/*.ts files) in libs/zard/src/lib/shared/components/**/*.ts, as it is not a significant concern and the explicit flag is acceptable in these contexts.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-26T11:20:45.264Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/select/select.component.spec.ts:79-88
Timestamp: 2025-11-26T11:20:45.264Z
Learning: In ZardUI select component tests (libs/zard/src/lib/components/select/select.component.spec.ts), use fakeAsync() with flush() instead of setTimeout because the component uses setTimeout(..., 0) for focus management, which requires advancing macrotasks in tests.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to **/*.spec.ts : Use Jest with happy-dom/jest-environment and Angular TestBed utilities for testing

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Create demo components in the `demo/` folder with a main export, default example, and variant examples

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use OnPush change detection strategy in Angular components: `changeDetection: ChangeDetectionStrategy.OnPush`

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Add barrel exports for all new components in libs/zard/src/lib/components/components.ts

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use Signal-based inputs with the `input()` function instead of Input decorators in Angular components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for performance optimization in components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-15T11:43:06.831Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 373
File: libs/zard/src/lib/shared/components/select/select.component.ts:33-33
Timestamp: 2025-12-15T11:43:06.831Z
Learning: In files under libs/zard/src/lib/**/*.{ts,tsx,js}, prefer the @/ path alias for imports that map to libs/zard/src/lib/* directories. For example, write import { mergeClasses } from '@/shared/utils/merge-classes' instead of using the 'zard/' alias. This improves path readability and aligns with the project's alias configuration.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Applies to libs/blocks/src/lib/**/*.component.html : Use TailwindCSS utility classes for styling, following responsive design patterns with prefixes for breakpoints (sm:, lg:) and ensure accessibility with semantic HTML and ARIA guidelines

Applied to files:

  • apps/web/src/index.html
  • apps/web/src/styles.css
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library

Applied to files:

  • apps/web/src/index.html
  • apps/web/src/styles.css
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/src/styles.css : Set up `src/styles.css` with Tailwind CSS configuration and design tokens using CSS `theme` and `plugin` directives

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Implement TailwindCSS v4 with PostCSS for styling and use class merging with tailwind-merge to resolve conflicts

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Use TailwindCSS v4 with PostCSS for styling the component library

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Components should be built with TailwindCSS v4 using the new inline configuration approach (no `tailwind.config.js` needed, configuration via `.postcssrc.json`, design tokens defined in CSS with `theme`)

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Applies to libs/blocks/src/lib/**/*.component.html : Block components should implement responsive design that works across all viewport sizes: Desktop (100% width), Tablet (768px), and Mobile (375px)

Applied to files:

  • apps/web/src/styles.css
🔇 Additional comments (9)
apps/web/project.json (1)

42-46: LGTM! Valid SSR optimization to prevent flickering.

Disabling critical CSS inlining prevents style duplication during SSR hydration, which can cause flash-of-unstyled-content issues. This is a well-established pattern for Angular Universal applications.

apps/web/src/styles.css (3)

2-3: Excellent! Using Fontsource npm packages instead of CDN.

This modern approach provides better performance (no external requests), version control, and offline support. The previous concerns about hard-coded Google Fonts URLs have been properly addressed.


14-15: Font variables correctly configured.

The CSS custom properties for Geist Variable and Geist Mono Variable align with the Fontsource imports and follow the project's theming pattern using CSS custom properties.


213-213: Container width update aligns with design system changes.

The shift from an explicit 1400px constraint to the max-w-350 token maintains consistency with the project's design token system while keeping the effective maximum width.

libs/zard/src/lib/shared/services/dark-mode.spec.ts (4)

1-64: Excellent test setup with comprehensive mocking.

The test configuration properly mocks browser APIs (matchMedia, localStorage) and uses TestBed with proper initialization and cleanup. All previously identified issues have been addressed:

  • localStorage.clear() prevents state leakage (line 63)
  • TestBed.tick() flushes effects after init() (line 57)
  • ✅ Clean mock setup and teardown

66-102: Core functionality thoroughly tested with proper effect flushing.

These tests verify initialization, listener management, and system preference detection. Critical improvements from previous reviews are properly implemented:

  • TestBed.tick() consistently called after operations that trigger effects (lines 73, 80, 84, 92)
  • Callback existence checked before usage (line 96)
  • System theme detection correctly validates behavior

104-136: Re-initialization scenarios handled correctly.

Both tests properly reset TestBed before creating new service instances, ensuring clean state for initialization testing. The pattern of resetTestingModule() → configure → inject → init()tick() correctly validates bootstrap behavior.


138-190: Comprehensive toggle behavior coverage.

The toggle tests verify all state transitions (LIGHT ↔ DARK ↔ SYSTEM) with proper effect flushing and listener management assertions. Each scenario includes TestBed.tick() after theme changes, ensuring effects execute before assertions.

apps/web/src/index.html (1)

5-6: LGTM! Structural improvement for SEO and URL resolution.

Moving <base> and <title> to the top of <head> follows best practices—<base> ensures relative URLs resolve correctly throughout the document, and an early <title> improves perceived load time and SEO.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 545a52d and faac262.

⛔ Files ignored due to path filters (4)
  • apps/web/public/r/dark-mode.json is excluded by !apps/web/public/** and included by apps/**
  • package-lock.json is excluded by !**/package-lock.json and included by none
  • package.json is excluded by none and included by none
  • packages/cli/src/commands/add/dark-mode-setup.ts is excluded by !packages/** and included by none
📒 Files selected for processing (5)
  • apps/web/project.json
  • apps/web/src/index.html
  • apps/web/src/styles.css
  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧰 Additional context used
📓 Path-based instructions (3)
libs/zard/**/*.{css,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS custom properties for design tokens and theming in the component library

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use Jest with @happy-dom/jest-environment and Angular TestBed utilities for testing

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧠 Learnings (28)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/src/styles.css : Set up `src/styles.css` with Tailwind CSS configuration and design tokens using CSS `theme` and `plugin` directives
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library

Applied to files:

  • apps/web/src/styles.css
  • apps/web/src/index.html
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/src/styles.css : Set up `src/styles.css` with Tailwind CSS configuration and design tokens using CSS `theme` and `plugin` directives

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Implement TailwindCSS v4 with PostCSS for styling and use class merging with tailwind-merge to resolve conflicts

Applied to files:

  • apps/web/src/styles.css
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Use TailwindCSS v4 with PostCSS for styling the component library

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Applies to libs/blocks/src/lib/**/*.component.html : Use TailwindCSS utility classes for styling, following responsive design patterns with prefixes for breakpoints (sm:, lg:) and ensure accessibility with semantic HTML and ARIA guidelines

Applied to files:

  • apps/web/src/styles.css
  • apps/web/src/index.html
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Components should be built with TailwindCSS v4 using the new inline configuration approach (no `tailwind.config.js` needed, configuration via `.postcssrc.json`, design tokens defined in CSS with `theme`)

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Applies to libs/blocks/src/lib/**/*.component.html : Block components should implement responsive design that works across all viewport sizes: Desktop (100% width), Tablet (768px), and Mobile (375px)

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Place tests co-located with components using the .spec.ts naming convention

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate test files with components using `.spec.ts` suffix next to component files

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-13T11:50:56.310Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 372
File: libs/zard/src/lib/shared/components/card/card.component.spec.ts:86-88
Timestamp: 2025-12-13T11:50:56.310Z
Learning: Do not flag or suggest removing `standalone: true` from test components (*.spec.ts files) or demo components (demo/*.ts files) in libs/zard/src/lib/shared/components/**/*.ts, as it is not a significant concern and the explicit flag is acceptable in these contexts.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-26T11:20:45.264Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/select/select.component.spec.ts:79-88
Timestamp: 2025-11-26T11:20:45.264Z
Learning: In ZardUI select component tests (libs/zard/src/lib/components/select/select.component.spec.ts), use fakeAsync() with flush() instead of setTimeout because the component uses setTimeout(..., 0) for focus management, which requires advancing macrotasks in tests.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to **/*.spec.ts : Use Jest with happy-dom/jest-environment and Angular TestBed utilities for testing

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Create demo components in the `demo/` folder with a main export, default example, and variant examples

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use OnPush change detection strategy in Angular components: `changeDetection: ChangeDetectionStrategy.OnPush`

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Add barrel exports for all new components in libs/zard/src/lib/components/components.ts

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use Signal-based inputs with the `input()` function instead of Input decorators in Angular components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for performance optimization in components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-15T11:43:06.831Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 373
File: libs/zard/src/lib/shared/components/select/select.component.ts:33-33
Timestamp: 2025-12-15T11:43:06.831Z
Learning: In files under libs/zard/src/lib/**/*.{ts,tsx,js}, prefer the @/ path alias for imports that map to libs/zard/src/lib/* directories. For example, write import { mergeClasses } from '@/shared/utils/merge-classes' instead of using the 'zard/' alias. This improves path readability and aligns with the project's alias configuration.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-14T22:52:09.135Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 326
File: libs/zard/src/lib/components/input/float.label.component.ts:71-0
Timestamp: 2025-11-14T22:52:09.135Z
Learning: In libs/zard/src/lib/components/*/*.component.ts files, move HostListener and HostBinding to the Component decorator's host property instead of using decorators on class members (e.g., host: { '(input)': 'onInput()' }).

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use computed properties in Angular components for reactive class calculations: `protected readonly classes = computed(() => ...)`

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-30T13:27:41.206Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/popover/popover.component.ts:28-29
Timestamp: 2025-11-30T13:27:41.206Z
Learning: In libs/zard/src/lib/components/core/**/*.ts files (core utilities, plugins, and providers), use relative imports for intra-core dependencies because the ZardUI CLI performs path transformations during component installation. The CLI expects specific relative path patterns and transforms them to the target project structure. For all other component imports and application code, use zard/* path aliases.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-29T15:31:22.377Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 339
File: libs/zard/src/lib/components/carousel/carousel.component.ts:92-92
Timestamp: 2025-11-29T15:31:22.377Z
Learning: In libs/zard/src/lib/components/**/*.component.ts files using TailwindCSS, avoid suggesting individual class bindings like `[class.fill-primary]="condition"` because they can cause TailwindCSS issues. Prefer string concatenation or `[class]` binding with conditional expressions instead.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T21:17:39.497Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 383
File: libs/zard/src/lib/shared/components/carousel/carousel.component.ts:114-115
Timestamp: 2025-12-21T21:17:39.497Z
Learning: In Angular components using signal inputs (input()) with types from external libraries like Embla Carousel, explicit type annotations (e.g., `readonly zOptions: InputSignal<EmblaOptionsType> = input<EmblaOptionsType>(...)`) may be necessary to prevent TypeScript IDE errors about inferred types referencing non-portable node_modules paths. This is not redundant when the annotation prevents the "cannot be named without a reference to node_modules" error.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
🔇 Additional comments (12)
apps/web/project.json (1)

42-46: LGTM—disabling inlineCritical prevents SSR theme flickering.

The optimization setting correctly disables critical CSS inlining in production builds, which prevents flash-of-unstyled-content during SSR hydration when the dark mode theme is applied client-side. This aligns with the PR's SSR improvements.

apps/web/src/styles.css (2)

2-3: Excellent—using @fontsource packages resolves all previous font loading issues.

Switching from hardcoded Google Fonts URLs to npm-managed @fontsource-variable packages provides:

  • Proper version control and reproducible builds
  • No broken gstatic URLs or version mismatches
  • Offline font availability during development
  • Consistent font loading behavior

This addresses all previous review concerns about font URL fragility.


14-15: Font variable updates are consistent with the @fontsource imports.

The CSS custom properties correctly reference the variable font families imported via @fontsource-variable, maintaining proper fallback stacks (sans-serif, monospace).

apps/web/src/index.html (2)

5-6: Standard meta tags added—LGTM.

The <base href="/"> and <title> tags are correctly placed in the <head> for SEO and routing.


61-77: Theme initialization script correctly prevents SSR flickering.

The inline script executes before Angular hydration to apply the theme synchronously:

  1. Reads localStorage.theme (system/dark/light)
  2. Checks system preference via matchMedia
  3. Applies 'dark' class and data-theme attribute
  4. Sets colorScheme style for native UI

This prevents flash-of-incorrect-theme during SSR hydration. The logic correctly handles all three theme modes.

libs/zard/src/lib/shared/services/dark-mode.ts (5)

1-18: Excellent—modernized service using Angular best practices.

The refactor adopts:

  • DestroyRef for cleanup instead of OnDestroy lifecycle hook
  • MediaMatcher from @angular/cdk/layout for robust system preference detection
  • inject() function for dependency injection
  • Signals (signal, computed, effect) for reactive state management

This aligns with Angular's modern API surface and improves maintainability.


33-43: Effect-based theme synchronization is clean and reactive.

The constructor establishes a reactive pipeline:

  1. Effect (lines 35-39) runs whenever themeSignal changes, applying theme to DOM
  2. Cleanup (line 41) properly removes system change listeners on destroy

This may trigger twice during initialization (default SYSTEM value → stored value from localStorage), but DOM operations are cheap and the declarative approach improves clarity.


45-49: Initialization separated from construction for SSR compatibility.

The init() method (lines 45-49) is invoked via APP_INITIALIZER per the provider changes, allowing the service to:

  1. Skip localStorage access during SSR (where it's unavailable)
  2. Read stored theme once DOM is available (line 74)
  3. Set up system listeners only when needed (lines 79-81)

This pattern prevents SSR errors and ensures correct theme application on hydration.

Also applies to: 73-82


64-71: Readonly signal exposure prevents external mutation—correct pattern.

The getter returns asReadonly(), ensuring components can read but not modify the theme signal. The JSDoc clearly documents usage:

  • Template: service.currentTheme() for reactive bindings
  • Code: service.currentTheme() returns "light", "dark", or "system"

For resolved theme (LIGHT/DARK only), consumers should use themeMode() instead.


84-97: System change listener management is correct and efficient.

The service correctly manages MediaQueryList listeners:

  • Lines 92-96: Adds listener when switching to SYSTEM mode, removes when switching to explicit (LIGHT/DARK)
  • Line 21: Arrow function preserves context for event handler
  • Lines 126-132: Conditional listener attachment based on mode

This prevents memory leaks and unnecessary listener overhead when using explicit themes.

Also applies to: 126-132

libs/zard/src/lib/shared/services/dark-mode.spec.ts (2)

14-64: Test setup is comprehensive with proper mocking and cleanup.

The beforeEach correctly:

  1. Mocks window.matchMedia with a Jest-compatible MediaQueryList interface
  2. Mocks localStorage with getter/setter/clear operations
  3. Initializes the service via init() and flushes effects with TestBed.tick() (correct replacement for deprecated flushEffects())

The afterEach (lines 60-64) prevents state leakage by clearing both Jest mocks and the localStorage mock.


66-190: Comprehensive test coverage with correct effect flushing.

The test suite covers all critical paths:

  • Initialization with stored/default themes
  • System preference detection and change handling
  • Listener lifecycle (attach/detach based on mode)
  • Theme toggling (explicit and implicit)
  • SSR compatibility (init() called separately from constructor)

All tests correctly use TestBed.tick() to flush effects before assertions (lines 57, 73, 80, 84, 116, 132, 154, 158, 167, 171, 186), addressing the async nature of Angular effects.

The tests follow the AAA (Arrange-Act-Assert) pattern and properly isolate concerns.

@mikij mikij force-pushed the themes-update branch 2 times, most recently from 282106f to e882fe9 Compare December 25, 2025 11:33
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 282106f and e882fe9.

⛔ Files ignored due to path filters (5)
  • apps/web/public/r/dark-mode.json is excluded by !apps/web/public/** and included by apps/**
  • package-lock.json is excluded by !**/package-lock.json and included by none
  • package.json is excluded by none and included by none
  • packages/cli/src/commands/add/dark-mode-setup.ts is excluded by !packages/** and included by none
  • packages/cli/src/commands/init/theme-loader.ts is excluded by !packages/** and included by none
📒 Files selected for processing (5)
  • apps/web/project.json
  • apps/web/src/index.html
  • apps/web/src/styles.css
  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧰 Additional context used
📓 Path-based instructions (3)
libs/zard/**/*.{css,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS custom properties for design tokens and theming in the component library

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use Jest with @happy-dom/jest-environment and Angular TestBed utilities for testing

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧠 Learnings (34)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Implement TailwindCSS v4 with PostCSS for styling and use class merging with tailwind-merge to resolve conflicts
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/src/styles.css : Set up `src/styles.css` with Tailwind CSS configuration and design tokens using CSS `theme` and `plugin` directives

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library

Applied to files:

  • apps/web/src/styles.css
  • apps/web/src/index.html
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Applies to libs/blocks/src/lib/**/*.component.html : Use TailwindCSS utility classes for styling, following responsive design patterns with prefixes for breakpoints (sm:, lg:) and ensure accessibility with semantic HTML and ARIA guidelines

Applied to files:

  • apps/web/src/styles.css
  • apps/web/src/index.html
📚 Learning: 2025-12-25T11:10:09.078Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 384
File: apps/web/src/styles.css:213-213
Timestamp: 2025-12-25T11:10:09.078Z
Learning: In Tailwind CSS v4, max-width utilities support dynamic numeric values derived from the spacing scale (using the --spacing variable, default 0.25rem = 4px). Prefer using numeric classes like max-w-350 when the value aligns with the spacing scale, since 350 × 0.25rem = 87.5rem = 1400px. Avoid arbitrary values expressed with brackets (e.g., max-w-[1400px]) when a scale-based value is available and accurate. Apply this guidance to CSS files in the web app (e.g., apps/web/src/styles.css) and across the codebase where Tailwind is used.

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-11-29T15:31:22.377Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 339
File: libs/zard/src/lib/components/carousel/carousel.component.ts:92-92
Timestamp: 2025-11-29T15:31:22.377Z
Learning: In libs/zard/src/lib/components/**/*.component.ts files using TailwindCSS, avoid suggesting individual class bindings like `[class.fill-primary]="condition"` because they can cause TailwindCSS issues. Prefer string concatenation or `[class]` binding with conditional expressions instead.

Applied to files:

  • apps/web/src/styles.css
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Implement TailwindCSS v4 with PostCSS for styling and use class merging with tailwind-merge to resolve conflicts

Applied to files:

  • apps/web/src/styles.css
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Components should be built with TailwindCSS v4 using the new inline configuration approach (no `tailwind.config.js` needed, configuration via `.postcssrc.json`, design tokens defined in CSS with `theme`)

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-11-07T08:49:00.973Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 311
File: libs/zard/src/lib/components/carousel/carousel.variants.ts:28-56
Timestamp: 2025-11-07T08:49:00.973Z
Learning: In Tailwind CSS v4, fractional spacing values like `pt-4.5` (1.125rem) and `-left-12.5` (3.125rem) are valid canonical classes supported by default, unlike Tailwind v3 which had a more restricted spacing scale. These should be used instead of arbitrary bracket notation like `pt-[1.125rem]`.

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use `mergeClasses()` utility with `clsx` and `tailwind-merge` to resolve class conflicts in component styling

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Use TailwindCSS v4 with PostCSS for styling the component library

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.variants.ts : Use CVA (Class Variance Authority) for type-safe styling variants in components

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.variants.ts : Use CVA (Class Variance Authority) for typed variants in component styling

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Applies to libs/blocks/src/lib/**/*.component.html : Block components should implement responsive design that works across all viewport sizes: Desktop (100% width), Tablet (768px), and Mobile (375px)

Applied to files:

  • apps/web/src/styles.css
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Place tests co-located with components using the .spec.ts naming convention

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate test files with components using `.spec.ts` suffix next to component files

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-13T11:50:56.310Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 372
File: libs/zard/src/lib/shared/components/card/card.component.spec.ts:86-88
Timestamp: 2025-12-13T11:50:56.310Z
Learning: Do not flag or suggest removing `standalone: true` from test components (*.spec.ts files) or demo components (demo/*.ts files) in libs/zard/src/lib/shared/components/**/*.ts, as it is not a significant concern and the explicit flag is acceptable in these contexts.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to **/*.spec.ts : Use Jest with happy-dom/jest-environment and Angular TestBed utilities for testing

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-26T11:20:45.264Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/select/select.component.spec.ts:79-88
Timestamp: 2025-11-26T11:20:45.264Z
Learning: In ZardUI select component tests (libs/zard/src/lib/components/select/select.component.spec.ts), use fakeAsync() with flush() instead of setTimeout because the component uses setTimeout(..., 0) for focus management, which requires advancing macrotasks in tests.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Create demo components in the `demo/` folder with a main export, default example, and variant examples

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Add barrel exports for all new components in libs/zard/src/lib/components/components.ts

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use OnPush change detection strategy in Angular components: `changeDetection: ChangeDetectionStrategy.OnPush`

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use Signal-based inputs with the `input()` function instead of Input decorators in Angular components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for performance optimization in components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-15T11:43:06.831Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 373
File: libs/zard/src/lib/shared/components/select/select.component.ts:33-33
Timestamp: 2025-12-15T11:43:06.831Z
Learning: In files under libs/zard/src/lib/**/*.{ts,tsx,js}, prefer the @/ path alias for imports that map to libs/zard/src/lib/* directories. For example, write import { mergeClasses } from '@/shared/utils/merge-classes' instead of using the 'zard/' alias. This improves path readability and aligns with the project's alias configuration.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-14T22:52:09.135Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 326
File: libs/zard/src/lib/components/input/float.label.component.ts:71-0
Timestamp: 2025-11-14T22:52:09.135Z
Learning: In libs/zard/src/lib/components/*/*.component.ts files, move HostListener and HostBinding to the Component decorator's host property instead of using decorators on class members (e.g., host: { '(input)': 'onInput()' }).

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-30T13:27:41.206Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/popover/popover.component.ts:28-29
Timestamp: 2025-11-30T13:27:41.206Z
Learning: In libs/zard/src/lib/components/core/**/*.ts files (core utilities, plugins, and providers), use relative imports for intra-core dependencies because the ZardUI CLI performs path transformations during component installation. The CLI expects specific relative path patterns and transforms them to the target project structure. For all other component imports and application code, use zard/* path aliases.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-30T08:50:23.436Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/core/providezard.ts:0-0
Timestamp: 2025-11-30T08:50:23.436Z
Learning: In libs/zard/src/lib/components/core/providezard.ts, the import paths `../core/event-manager-plugins/...` are intentionally structured this way because the ZardUI CLI transforms them to 'shared/components/core/event-manager-plugins/...' format. Other relative path combinations don't work with the current CLI implementation. This path pattern should not be simplified until the CLI transformation logic is updated.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use computed properties in Angular components for reactive class calculations: `protected readonly classes = computed(() => ...)`

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T21:17:39.497Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 383
File: libs/zard/src/lib/shared/components/carousel/carousel.component.ts:114-115
Timestamp: 2025-12-21T21:17:39.497Z
Learning: In Angular components using signal inputs (input()) with types from external libraries like Embla Carousel, explicit type annotations (e.g., `readonly zOptions: InputSignal<EmblaOptionsType> = input<EmblaOptionsType>(...)`) may be necessary to prevent TypeScript IDE errors about inferred types referencing non-portable node_modules paths. This is not redundant when the annotation prevents the "cannot be named without a reference to node_modules" error.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
🔇 Additional comments (17)
apps/web/src/index.html (2)

5-6: LGTM! Standard HTML document structure improvements.

Adding explicit <base> and <title> elements improves SEO and ensures consistent URL resolution. The title clearly communicates the product positioning.


61-76: Excellent SSR-safe theme initialization!

The inline script correctly:

  • Runs synchronously before body render to prevent flicker
  • Safely handles missing localStorage with try-catch
  • Detects system preference via matchMedia
  • Applies the scheme-light-dark class for CSS color-scheme coordination
  • Sets both dark class and data-theme attribute

This pairs well with the new ZardDarkMode.init() flow for hydration.

apps/web/src/styles.css (3)

2-3: Excellent font loading strategy upgrade!

Switching from hardcoded CDN URLs to @fontsource-variable packages provides:

  • Version control and reproducibility via package.json
  • Improved offline development experience
  • Variable font support with proper subsetting
  • Eliminates the versioning issues flagged in previous reviews

Based on learnings, this aligns with using CSS custom properties for design tokens.


14-15: LGTM! Font token structure follows best practices.

The two-tier variable approach (public --font-geist-* → theme --font-sans/mono) enables:

  • Theme-level font family switching
  • Consistent token reference in components
  • Future extensibility for additional themes

Also applies to: 109-110


213-213: Correct Tailwind CSS v4 usage confirmed.

The max-w-350 class leverages Tailwind v4's dynamic spacing scale (350 × 0.25rem = 87.5rem = 1400px), which is cleaner than the arbitrary value syntax. This is the preferred approach in v4.

Based on learnings, Tailwind CSS v4 max-width utilities support dynamic numeric values derived from the spacing scale.

libs/zard/src/lib/shared/services/dark-mode.ts (6)

1-1: Excellent use of Angular CDK MediaMatcher!

Using @angular/cdk/layout's MediaMatcher is the Angular-idiomatic way to handle media queries with proper testing support and SSR compatibility. This is superior to raw window.matchMedia.

Also applies to: 18-18


3-3: Modern lifecycle management with DestroyRef!

Replacing OnDestroy with DestroyRef follows Angular's modern functional approach:

  • ✅ Works with inject()
  • ✅ Simpler cleanup via onDestroy() callback
  • ✅ Better composability with functional patterns

The effect cleanup is properly registered in the constructor.

Also applies to: 15-15, 17-17, 41-42


33-43: Effect-based reactivity eliminates manual subscription management!

The constructor's effect() automatically synchronizes DOM state whenever themeSignal changes, eliminating error-prone manual subscription/unsubscription. The destroyRef.onDestroy() cleanup ensures listeners are removed.

This is Angular Signals best practice.


64-71: Readonly signal exposure prevents external mutation!

Returning asReadonly() enforces unidirectional data flow while maintaining reactivity. The JSDoc clearly explains usage for both imperative reads and template bindings.


111-115: Simplified theme application focuses on class and attribute.

Removing colorScheme DOM manipulation addresses SSR flickering issues mentioned in the PR objectives. The scheme-light-dark class in index.html now handles this declaratively via CSS.


125-131: Clean listener lifecycle management.

The default parameter addListener = true enables concise call sites (handleSystemChanges() for add, handleSystemChanges(false) for remove). The effect in the constructor ensures listeners are added/removed reactively when switching modes.

libs/zard/src/lib/shared/services/dark-mode.spec.ts (6)

14-58: Comprehensive test setup with proper isolation!

The beforeEach correctly mocks:

  • matchMedia with a mock MediaQueryList supporting addEventListener/removeEventListener
  • localStorage with a functional in-memory implementation
  • ✅ TestBed configuration for clean service instantiation
  • TestBed.tick() after init() to flush effects

This ensures tests are isolated and deterministic.

As per coding guidelines, using Jest with Angular TestBed utilities for testing.


60-64: Proper test cleanup prevents state leakage!

Calling localStorage.clear() in afterEach ensures subsequent tests start with a clean slate. This was correctly added based on previous review feedback.


71-88: Effect flushing with TestBed.tick() is correct!

Since the service uses effect() to manage listeners, these tests properly call TestBed.tick() after toggleTheme() to flush scheduled effects before asserting on addEventListener/removeEventListener calls.

This replaces the deprecated TestBed.flushEffects() per Angular 20+ guidance.


90-102: System preference callback test demonstrates proper verification!

This test:

  1. Arrange: Sets theme to SYSTEM and flushes effects
  2. Act: Captures the registered callback and invokes it with matches: true
  3. Assert: Verifies themeMode() reflects the dark preference

The callback extraction from mock.calls is a solid approach to test internal listener behavior.


104-119: Re-initialization tests properly reset TestBed state!

Both tests correctly use TestBed.resetTestingModule() to create fresh service instances, ensuring initialization logic is actually tested rather than relying on the singleton from beforeEach.

This pattern properly verifies bootstrap-time behavior.

Also applies to: 121-136


138-190: Toggle scenarios comprehensively cover mode transitions!

The test suite validates:

  • ✅ Implicit toggle (no argument)
  • ✅ Explicit mode setting (targetMode)
  • ✅ System mode with both light and dark OS preferences
  • ✅ Listener lifecycle during mode transitions

All tests follow AAA pattern and properly flush effects. Excellent coverage!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4184e0f and 6ab97f8.

📒 Files selected for processing (1)
  • apps/web/src/app/app.config.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • apps/web/src/app/app.config.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Implement TailwindCSS v4 with PostCSS for styling and use class merging with tailwind-merge to resolve conflicts
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes
📚 Learning: 2025-11-26T10:13:44.258Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/layout/sidebar.component.ts:22-22
Timestamp: 2025-11-26T10:13:44.258Z
Learning: The ZardUI CLI will automatically add `provideZard()` to the app configuration and install the core component before the next CLI release, addressing the breaking change requirement for the event manager plugins.

Applied to files:

  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-30T13:27:41.206Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/popover/popover.component.ts:28-29
Timestamp: 2025-11-30T13:27:41.206Z
Learning: In libs/zard/src/lib/components/core/**/*.ts files (core utilities, plugins, and providers), use relative imports for intra-core dependencies because the ZardUI CLI performs path transformations during component installation. The CLI expects specific relative path patterns and transforms them to the target project structure. For all other component imports and application code, use zard/* path aliases.

Applied to files:

  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use OnPush change detection strategy in Angular components: `changeDetection: ChangeDetectionStrategy.OnPush`

Applied to files:

  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-30T08:50:23.436Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/core/providezard.ts:0-0
Timestamp: 2025-11-30T08:50:23.436Z
Learning: In libs/zard/src/lib/components/core/providezard.ts, the import paths `../core/event-manager-plugins/...` are intentionally structured this way because the ZardUI CLI transforms them to 'shared/components/core/event-manager-plugins/...' format. Other relative path combinations don't work with the current CLI implementation. This path pattern should not be simplified until the CLI transformation logic is updated.

Applied to files:

  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export all components in `libs/zard/src/lib/components/components.ts` for public API

Applied to files:

  • apps/web/src/app/app.config.ts
🔇 Additional comments (2)
apps/web/src/app/app.config.ts (2)

2-8: LGTM! Modern Angular DI patterns.

The addition of inject and provideAppInitializer follows Angular's modern functional approach for dependency injection and bootstrap-time initialization.


13-13: LGTM! Path alias follows guidelines.

The import uses the @zard/services/* path alias pattern as specified in the coding guidelines.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ab97f8 and 00e5427.

⛔ Files ignored due to path filters (1)
  • apps/web/public/r/dark-mode.json is excluded by !apps/web/public/** and included by apps/**
📒 Files selected for processing (3)
  • apps/web/src/app/app.config.ts
  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧰 Additional context used
📓 Path-based instructions (3)
libs/zard/**/*.{css,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS custom properties for design tokens and theming in the component library

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use Jest with @happy-dom/jest-environment and Angular TestBed utilities for testing

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use path aliases @zard/* to map to libs/zard/src/lib/* in imports

Files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • apps/web/src/app/app.config.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
🧠 Learnings (29)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Implement TailwindCSS v4 with PostCSS for styling and use class merging with tailwind-merge to resolve conflicts
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Place tests co-located with components using the .spec.ts naming convention

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Use Angular TestBed and ComponentFixture utilities for testing components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate test files with components using `.spec.ts` suffix next to component files

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-13T11:50:56.310Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 372
File: libs/zard/src/lib/shared/components/card/card.component.spec.ts:86-88
Timestamp: 2025-12-13T11:50:56.310Z
Learning: Do not flag or suggest removing `standalone: true` from test components (*.spec.ts files) or demo components (demo/*.ts files) in libs/zard/src/lib/shared/components/**/*.ts, as it is not a significant concern and the explicit flag is acceptable in these contexts.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-26T11:20:45.264Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/select/select.component.spec.ts:79-88
Timestamp: 2025-11-26T11:20:45.264Z
Learning: In ZardUI select component tests (libs/zard/src/lib/components/select/select.component.spec.ts), use fakeAsync() with flush() instead of setTimeout because the component uses setTimeout(..., 0) for focus management, which requires advancing macrotasks in tests.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to **/*.spec.ts : Use Jest with happy-dom/jest-environment and Angular TestBed utilities for testing

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:12:15.303Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-12-21T00:12:15.303Z
Learning: Applies to packages/cli/**/*.{ts,tsx,css} : Components should include built-in dark mode support

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Add barrel exports for all new components in libs/zard/src/lib/components/components.ts

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • apps/web/src/app/app.config.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Create demo components in the `demo/` folder with a main export, default example, and variant examples

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Create components as standalone components with `standalone: true` in Angular

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use OnPush change detection strategy in Angular components: `changeDetection: ChangeDetectionStrategy.OnPush`

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use Signal-based inputs with the `input()` function instead of Input decorators in Angular components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for performance optimization in components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-30T19:07:11.572Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 352
File: apps/web/src/app/domain/components/sidebar/scroll-on-active.directive.ts:23-27
Timestamp: 2025-11-30T19:07:11.572Z
Learning: In apps/web/src/app/domain/components/sidebar/scroll-on-active.directive.ts, the guard checking if scrollIntoView exists before calling it is necessary due to mobile browser compatibility issues. Physical testing on mobile devices shows scrollIntoView may not be present or functional. This defensive pattern should be kept despite scrollIntoView being part of the standard DOM API.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Use Jest with `happy-dom/jest-environment` for testing Angular components

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
📚 Learning: 2025-12-21T00:12:01.332Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-12-21T00:12:01.332Z
Learning: Blocks must use the DarkModeService for automatic theme detection and adaptation, ensuring that components and preview images respond to theme changes

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-15T11:43:06.831Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 373
File: libs/zard/src/lib/shared/components/select/select.component.ts:33-33
Timestamp: 2025-12-15T11:43:06.831Z
Learning: In files under libs/zard/src/lib/**/*.{ts,tsx,js}, prefer the @/ path alias for imports that map to libs/zard/src/lib/* directories. For example, write import { mergeClasses } from '@/shared/utils/merge-classes' instead of using the 'zard/' alias. This improves path readability and aligns with the project's alias configuration.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.spec.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-26T10:13:44.258Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/layout/sidebar.component.ts:22-22
Timestamp: 2025-11-26T10:13:44.258Z
Learning: The ZardUI CLI will automatically add `provideZard()` to the app configuration and install the core component before the next CLI release, addressing the breaking change requirement for the event manager plugins.

Applied to files:

  • apps/web/src/app/app.config.ts
📚 Learning: 2025-11-30T13:27:41.206Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/popover/popover.component.ts:28-29
Timestamp: 2025-11-30T13:27:41.206Z
Learning: In libs/zard/src/lib/components/core/**/*.ts files (core utilities, plugins, and providers), use relative imports for intra-core dependencies because the ZardUI CLI performs path transformations during component installation. The CLI expects specific relative path patterns and transforms them to the target project structure. For all other component imports and application code, use zard/* path aliases.

Applied to files:

  • apps/web/src/app/app.config.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-30T08:50:23.436Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 348
File: libs/zard/src/lib/components/core/providezard.ts:0-0
Timestamp: 2025-11-30T08:50:23.436Z
Learning: In libs/zard/src/lib/components/core/providezard.ts, the import paths `../core/event-manager-plugins/...` are intentionally structured this way because the ZardUI CLI transforms them to 'shared/components/core/event-manager-plugins/...' format. Other relative path combinations don't work with the current CLI implementation. This path pattern should not be simplified until the CLI transformation logic is updated.

Applied to files:

  • apps/web/src/app/app.config.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export all components in `libs/zard/src/lib/components/components.ts` for public API

Applied to files:

  • apps/web/src/app/app.config.ts
  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/**/*.{css,ts} : Use CSS custom properties for design tokens and theming in the component library

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T00:11:39.443Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T00:11:39.443Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Implement TailwindCSS v4 with PostCSS for styling and use class merging with tailwind-merge to resolve conflicts

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-25T18:54:01.560Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T18:54:01.560Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use `mergeClasses()` utility with `clsx` and `tailwind-merge` to resolve class conflicts in component styling

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-14T22:52:09.135Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 326
File: libs/zard/src/lib/components/input/float.label.component.ts:71-0
Timestamp: 2025-11-14T22:52:09.135Z
Learning: In libs/zard/src/lib/components/*/*.component.ts files, move HostListener and HostBinding to the Component decorator's host property instead of using decorators on class members (e.g., host: { '(input)': 'onInput()' }).

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-11-29T15:31:22.377Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 339
File: libs/zard/src/lib/components/carousel/carousel.component.ts:92-92
Timestamp: 2025-11-29T15:31:22.377Z
Learning: In libs/zard/src/lib/components/**/*.component.ts files using TailwindCSS, avoid suggesting individual class bindings like `[class.fill-primary]="condition"` because they can cause TailwindCSS issues. Prefer string concatenation or `[class]` binding with conditional expressions instead.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
📚 Learning: 2025-12-21T21:17:39.497Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 383
File: libs/zard/src/lib/shared/components/carousel/carousel.component.ts:114-115
Timestamp: 2025-12-21T21:17:39.497Z
Learning: In Angular components using signal inputs (input()) with types from external libraries like Embla Carousel, explicit type annotations (e.g., `readonly zOptions: InputSignal<EmblaOptionsType> = input<EmblaOptionsType>(...)`) may be necessary to prevent TypeScript IDE errors about inferred types referencing non-portable node_modules paths. This is not redundant when the annotation prevents the "cannot be named without a reference to node_modules" error.

Applied to files:

  • libs/zard/src/lib/shared/services/dark-mode.ts
🔇 Additional comments (20)
libs/zard/src/lib/shared/services/dark-mode.ts (10)

1-3: LGTM: Modern Angular imports with CDK integration.

The imports follow Angular best practices: CDK MediaMatcher for media queries, inject() for DI, signals/computed/effect for reactivity, and DestroyRef for lifecycle management.


25-36: LGTM: Excellent use of modern Angular patterns.

The constructor demonstrates best practices:

  • inject() for dependency injection (no constructor parameters)
  • DestroyRef for cleanup instead of OnDestroy lifecycle hook
  • effect() for reactive theme synchronization
  • Browser-only guard prevents SSR issues

38-43: LGTM: Defensive getter prevents SSR access violations.

The query getter with explicit SSR guard and error message is good defensive programming, ensuring MediaQueryList is never accessed on the server.


45-51: LGTM: Clean computed signal for theme resolution.

The themeMode computed signal correctly derives the resolved theme from currentTheme, handling the SYSTEM mode by checking system preferences.


53-57: LGTM: Well-documented initialization method.

The init() method with JSDoc clarifying APP_INITIALIZER usage and browser-only guard is correct.


59-70: LGTM: Clean toggle implementation.

The toggleTheme method correctly handles both explicit theme setting and toggling between light/dark modes with proper browser guards.


72-79: LGTM: Well-documented readonly signal exposure.

The currentTheme getter with comprehensive JSDoc and asReadonly() prevents external mutation while maintaining reactivity.


81-90: LGTM: Clean initialization logic.

The initializeTheme method correctly reads stored preferences and sets up system preference monitoring when needed, with no redundant checks.


92-125: LGTM: Robust error handling for storage operations.

Both applyTheme and getStoredTheme include try-catch blocks around localStorage operations, gracefully handling QuotaExceededError and SecurityError scenarios with appropriate warnings.


133-151: LGTM: Robust system preference detection.

Both isDarkModeActive and handleSystemChanges are well-implemented with proper error handling and clear logic for media query management.

libs/zard/src/lib/shared/services/dark-mode.spec.ts (7)

1-14: LGTM: Clean test setup with proper imports.

The test file uses Angular testing utilities correctly with proper TypeScript typing for mocks.


15-65: LGTM: Comprehensive test setup with proper cleanup.

The beforeEach and afterEach blocks demonstrate excellent testing practices:

  • Thorough mocking of matchMedia and localStorage
  • TestBed.tick() after init() ensures effects are flushed
  • localStorage.clear() prevents state leakage between tests

All past review concerns have been addressed.


67-89: LGTM: System change listener tests properly flush effects.

The tests correctly use TestBed.tick() after toggleTheme() calls to ensure effects run before assertions on addEventListener/removeEventListener.


91-120: LGTM: Callback verification and initialization tests are robust.

The tests correctly:

  • Use expect(callback).toBeDefined() instead of Jest's non-existent fail() function
  • Reset TestBed to test initialization with different system preferences
  • Flush effects with TestBed.tick() before assertions

All past review concerns have been addressed.


122-158: LGTM: Comprehensive SSR and initialization coverage.

The tests include excellent coverage for:

  • System appearance change detection from init()
  • Graceful degradation in SSR environments (non-browser PLATFORM_ID)

The SSR test verifies no browser APIs are accessed and toggleTheme doesn't throw, ensuring server-side safety.


160-212: LGTM: Comprehensive toggleTheme test coverage.

The toggleTheme tests thoroughly cover:

  • Basic light/dark toggling
  • System mode transitions with proper effect flushing (TestBed.tick())
  • Explicit theme mode setting
  • Listener lifecycle management verification

All past review concerns about missing TestBed.tick() calls have been addressed.


6-213: Excellent test coverage demonstrating Angular testing best practices.

The test suite is comprehensive and well-structured, covering:

  • System preference detection and listener lifecycle
  • Theme initialization and toggling scenarios
  • SSR environment graceful degradation
  • LocalStorage persistence and error handling

All tests properly use TestBed.tick() to flush effects, ensuring synchronous verification of async behavior. The cleanup strategy prevents state leakage between tests.

apps/web/src/app/app.config.ts (3)

1-13: LGTM: Clean imports for app initialization pattern.

The added imports (inject, provideAppInitializer) and ZardDarkMode service import follow Angular best practices and use the correct @zard/ path alias.


17-32: LGTM: Proper app initializer for early theme setup.

The provideAppInitializer pattern ensures the dark mode service initializes during app bootstrap, preventing SSR flickering. The service's init() method includes appropriate error handling for localStorage operations (as verified in dark-mode.ts).

This pattern is synchronous (returns void), maintaining fast app startup while ensuring theme is applied before first render.


31-31: Well-architected bootstrap initialization pattern.

The app initializer approach ensures dark mode preferences are loaded and applied during app bootstrap, preventing FOUC (flash of unstyled content) and SSR flickering. This aligns perfectly with the service's new init() method design.

@Luizgomess Luizgomess merged commit 7df85ea into master Dec 26, 2025
5 checks passed
@Luizgomess Luizgomess deleted the themes-update branch December 26, 2025 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants