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,4 +1,4 @@
import { Archive, Settings2 } from "lucide-react";
import { Archive, Plus, Settings2 } from "lucide-react";
import { ArchivedHabits } from "../components/ArchivedHabits";
import { AccountSettings } from "../components/AccountSettings";
import { useCallback, useEffect, useRef, useState } from "react";
@@ -442,7 +442,6 @@ function Dashboard({ user, onExpired }: { user: PublicUser; onExpired: () => voi
>
<div className="ds-section-top">
<SectionHeading
number="YOUR HABITS"
id="habits-title"
title={
<>
@@ -581,7 +580,7 @@ function SavedHabit({
disabled={disabled || habit.requirements.tasks.length >= 100}
onClick={() => setAddingTask(true)}
>
Add task +
<Plus size={20} aria-hidden="true" /><span>Add task</span>
</Button>
</div>
</>