Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
691dfb6
feat(features): add features section with 4 feature cards
May 22, 2026
9c432b6
feat(hero): implement hero section rendering with E2E tests
May 22, 2026
990b5b3
feat(footer): add footer section with links, copyright, and responsiv…
May 22, 2026
dd7b1cd
chore(scenario): backend fallback commit for "Footer Section"
May 22, 2026
61450d7
feat(cta): add CTA buttons with redirects, hover/focus states, and ac…
May 22, 2026
6adbe85
feat(nav): add responsive navigation with auth state and mobile menu
May 22, 2026
434d386
feat(nav): add responsive navigation with auth state and mobile menu
May 22, 2026
5cae4bc
chore(scenario): backend fallback commit for "Navigation Links"
May 22, 2026
3201e0e
feat(responsive): add responsive CSS and breakpoint tests
May 22, 2026
2d5da2c
feat(theme): implement dark mode theme with toggle, persistence, and …
May 22, 2026
63a8a7e
feat(accessibility): add comprehensive accessibility e2e tests
May 22, 2026
743bbc7
feat(performance): add performance tests and optimizations for homepage
May 22, 2026
e855a08
fix: resolve mobile theme toggle and Playwright strict mode violations
May 22, 2026
cd8c719
feat(seo): add comprehensive SEO meta tags, Open Graph, Twitter Cards…
May 22, 2026
95fec7b
fix(tests): add --config flag to e2e test script for Playwright confi…
May 22, 2026
7a35a95
feat(analytics): add analytics counter display with stats API
May 22, 2026
c9d77f7
chore(scenario): backend fallback commit for "Analytics Counter Display"
May 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .claude/skills/dark-mode-daisyui/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: dark-mode-daisyui
description: |
Implement dark mode theme switching using DaisyUI's data-theme attribute system
with localStorage persistence, system preference detection via matchMedia,
smooth CSS transitions, and accessible toggle buttons.
metadata:
triggers:
- "dark mode"
- "theme toggle"
- "DaisyUI theme"
- "prefers-color-scheme"
- "light dark theme"
- "data-theme"
scope: project
---

See [README.md](references/README.md) for full documentation.
122 changes: 122 additions & 0 deletions .claude/skills/dark-mode-daisyui/references/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Dark Mode Implementation with DaisyUI

## Overview

This project uses DaisyUI's theme system for dark mode. DaisyUI provides built-in light and dark themes that are activated by setting `data-theme` on the `<html>` element. All `bg-base-*` and `text-base-*` utility classes automatically adapt.

## When to Use This Skill

Use this skill when users request:
- Adding dark mode to a DaisyUI/Tailwind project
- Theme toggle with localStorage persistence
- System preference detection (prefers-color-scheme)
- Smooth theme transitions

## Core Capabilities

### 1. Theme Detection and Persistence

Location: `web/src/js/main.js`

```javascript
function initTheme() {
const root = document.documentElement;
const savedTheme = localStorage.getItem('theme');

let theme;
if (savedTheme) {
theme = savedTheme;
} else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
} else {
theme = 'light';
}

root.setAttribute('data-theme', theme);

// Listen for system preference changes
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addEventListener('change', function(event) {
if (!localStorage.getItem('theme')) {
const newTheme = event.matches ? 'dark' : 'light';
root.setAttribute('data-theme', newTheme);
}
});

initThemeToggle();
}
```

### 2. Toggle Button Handling

```javascript
function initThemeToggle() {
// IMPORTANT: Use querySelectorAll for multiple toggle buttons (desktop + mobile)
const toggleBtns = document.querySelectorAll('[data-testid="theme-toggle"]');
if (!toggleBtns.length) return;

toggleBtns.forEach(function(toggleBtn) {
toggleBtn.addEventListener('click', function() {
const root = document.documentElement;
const currentTheme = root.getAttribute('data-theme') || 'light';
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';

root.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);

// Update ALL toggle button icons/labels
toggleBtns.forEach(function(btn) {
updateToggleLabel(btn, newTheme);
});
});

const currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
updateToggleLabel(toggleBtn, currentTheme);
});
}

function updateToggleLabel(button, theme) {
const isDark = theme === 'dark';
button.setAttribute('aria-label', isDark ? 'Switch to light mode' : 'Switch to dark mode');
button.setAttribute('title', isDark ? 'Switch to light mode' : 'Switch to dark mode');

const icon = button.querySelector('.theme-icon');
if (icon) {
icon.textContent = isDark ? '☀' : '☽';
}
}
```

### 3. CSS Transitions

Location: `web/src/css/main.css`

```css
html {
transition: background-color 0.3s ease, color 0.3s ease;
}
body, .navbar, .hero, .card, .footer, section {
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
}
```

## Best Practices

- Use `querySelectorAll` not `querySelector` for toggle buttons when there are multiple (desktop + mobile)
- Remove hardcoded `data-theme="light"` from `<html>` so JS can set it dynamically before render
- Use DaisyUI semantic colors (`bg-base-100`, `text-base-content`) rather than explicit light/dark classes
- Check localStorage before system preference — user's explicit choice should override OS settings
- Update ALL toggle button labels/icons when theme changes, not just the clicked one

## Resources

### references/

- `README.md` - This documentation

### Related Files

- `web/src/js/main.js` - Theme detection, toggle, and persistence logic
- `web/src/css/main.css` - Theme transition styles
- `web/templates/partials/nav.html` - Theme toggle buttons in nav
- `tests/e2e/theme.spec.js` - Full E2E test suite for dark mode
18 changes: 18 additions & 0 deletions .claude/skills/e2e-color-brightness-testing/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: e2e-color-brightness-testing
description: |
Extract normalized brightness from computed CSS colors in Playwright E2E tests.
Handles multiple color formats (rgb, rgba, oklch, oklab, hsl) that modern browsers
return from getComputedStyle, enabling robust color-based assertions across browsers.
metadata:
triggers:
- "color brightness test"
- "computed color testing"
- "oklch test"
- "color format parsing"
- "getComputedStyle test"
- "dark mode color assertion"
scope: project
---

See [README.md](references/README.md) for full documentation.
100 changes: 100 additions & 0 deletions .claude/skills/e2e-color-brightness-testing/references/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# E2E Color Brightness Testing

## Overview

When testing dark mode or any color-dependent UI feature with Playwright, `getComputedStyle` returns colors in different formats depending on the browser and CSS engine. This skill provides a robust `getBrightness()` helper that normalizes any format to a 0-255 brightness scale.

## When to Use This Skill

Use this skill when users request:
- Testing CSS colors in E2E tests
- Handling oklch/oklab color formats from getComputedStyle
- Writing assertions for dark/light mode color verification
- Parsing multiple CSS color formats in tests

## Core Capabilities

### 1. Multi-Format Color Brightness Extraction

```javascript
function getBrightness(colorStr) {
if (!colorStr) return null;

// rgb/rgba: rgb(255, 255, 255) or rgba(255, 255, 255, 0.5)
const rgbMatch = colorStr.match(/rgba?\((\d+(?:\.\d+)?),\s*(\d+(?:\.\d+)?),\s*(\d+(?:\.\d+)?)/);
if (rgbMatch) {
const r = parseFloat(rgbMatch[1]);
const g = parseFloat(rgbMatch[2]);
const b = parseFloat(rgbMatch[3]);
return (r + g + b) / 3;
}

// oklch: oklch(0.278078 0.029596 256.848) — first value is lightness 0-1
const oklchMatch = colorStr.match(/oklch\(([\d.]+)/);
if (oklchMatch) {
return parseFloat(oklchMatch[1]) * 255;
}

// oklab: oklab(0.419385 0.00478227 -0.0474926) — first value is lightness 0-1
const oklabMatch = colorStr.match(/oklab\(([\d.]+)/);
if (oklabMatch) {
return parseFloat(oklabMatch[1]) * 255;
}

// hsl: hsl(210, 100%, 50%)
const hslMatch = colorStr.match(/hsl\([\d.]+,\s*[\d.]+%?,\s*([\d.]+)%?\)/);
if (hslMatch) {
return (parseFloat(hslMatch[1]) / 100) * 255;
}

return null;
}
```

### 2. Usage in Playwright Tests

```javascript
const bodyBg = await body.evaluate(el => {
const computed = window.getComputedStyle(el);
return computed.backgroundColor;
});

const brightness = getBrightness(bodyBg);
expect(brightness).not.toBeNull();
expect(brightness).toBeGreaterThan(200); // Light background
```

### 3. Handling Playwright Strict Mode with Multiple Elements

When multiple elements share the same `data-testid`, use the `:visible` pseudo-class:

```javascript
// Selects only the visible toggle based on viewport
const toggleBtn = page.locator('[data-testid="theme-toggle"]:visible');
```

## Best Practices

- Always normalize colors to brightness rather than comparing raw strings
- Include parsers for oklch and oklab — modern Chromium returns these formats
- Use empirically-determined thresholds based on your design system
- Use `:visible` pseudo-class for elements that exist in both desktop and mobile layouts

## Recommended Brightness Thresholds (DaisyUI)

| Context | Threshold |
|---------|-----------|
| Light background | > 200 |
| Dark background | < 100 |
| Dark text (light mode) | < 120 |
| Light text (dark mode) | > 180 |

## Resources

### references/

- `README.md` - This documentation

### Related Files

- `tests/e2e/theme.spec.js` - Full implementation with getBrightness() helper
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/target
**/*.rs.bk
.something/
node_modules/
1 change: 1 addition & 0 deletions mirdb-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ tokio-proto = "0.1"
tokio-service = "0.1"
glob = "0.3.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
bincode = "1.1.2"
integer-encoding = "1.0"
snap = "0.2"
Expand Down
1 change: 1 addition & 0 deletions mirdb-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ mod test_utils;
mod thread_pool;
mod types;
mod wal;
mod web;

pub struct Server {
store: Arc<Store>,
Expand Down
Loading