feat: add theme provider and control components for light/dark mode

- Implemented ThemeProvider to manage theme state and preferences.
- Added ThemeControl component for users to switch between system, light, and dark themes.
- Integrated localStorage for theme preference persistence.
- Updated document styles based on theme changes.

test: add tests for permanent deletion of habits and related records

- Created tests to ensure permanent deletion of habits removes all dependent records.
- Verified that deletion requires ownership, authentication, and checks for archived habits.
- Added tests to confirm rollback behavior on deletion failures.

test: add tests for habit palette and progress card functionality

- Implemented tests for habit color progression and theme-based color shading.
- Added tests for progress card calculations and calendar display logic.

feat: define theme types and preferences

- Introduced Theme and ThemePreference types for better type safety.
- Created utility functions for resolving theme based on user preference and system settings.
- Defined theme palettes for light and dark modes to ensure adequate contrast.
This commit is contained in:
syntaxbullet
2026-09-05 10:07:28 +02:00
parent 9e9871c08a
commit 00729096bf
47 changed files with 780 additions and 337 deletions

View File

@@ -1,3 +1,5 @@
import { habitProgressColor } from "../../lib/habit-palette";
import type { Theme } from "../../lib/theme";
export const PROGRESS_SHADES = [
"#eeeeee",
"#d8d8d8",
@@ -103,7 +105,7 @@ export function describeDay(day: CalendarDay, unit: string) {
}
/** Only show shades that the chart's completion targets can produce. */
export function legendShades(days: CalendarDay[], color = "#111111") {
export function legendShades(days: CalendarDay[], color = "#111111", theme?: Theme) {
const levels = new Set<number>();
for (const target of new Set(days.map((day) => day.target))) {
if (!Number.isFinite(target) || target <= 0) continue;
@@ -118,7 +120,7 @@ export function legendShades(days: CalendarDay[], color = "#111111") {
...[...levels]
.sort((a, b) => a - b)
.map((value) =>
progressShade({ date: "", value, target: 8, state: "due" }, color),
theme ? habitProgressColor(color, (value - 1) / 7, theme) : progressShade({ date: "", value, target: 8, state: "due" }, color),
),
];
}