feat: add Home page with user dashboard and habit tracking features

- Implemented Home component with user authentication and loading states.
- Created Welcome component for unauthenticated users with a sign-in option.
- Developed Dashboard component to display user's habits and progress.
- Added functionality for habit management, including adding, updating, and deleting habits.
- Integrated HabitChart and HabitHistory components for visual representation of habits.
- Introduced sharing functionality for progress via Discord integration.

feat: establish Discord sharing configuration and routes

- Added DiscordSharingConfig type and readDiscordSharingConfig function for environment variable management.
- Created sharing contracts for input validation and data structure.
- Implemented sharing routes for previewing and sending progress images to Discord.
- Added tests for sharing routes to ensure authentication and proper error handling.
This commit is contained in:
syntaxbullet
2026-09-04 17:48:54 +02:00
parent dde5e77317
commit ecc2620a4c
34 changed files with 4017 additions and 140 deletions

View File

@@ -2,6 +2,7 @@ import { useId, useLayoutEffect, useRef, useState, type CSSProperties, type Reac
import { CalendarLegend } from "./CalendarLegend";
import { Field } from "./Field";
import { Button } from "./primitives";
import { CalendarDays, Keyboard } from "lucide-react";
import {
describeDay,
calendarTimeline,
@@ -87,7 +88,7 @@ export function CalendarHeatmap({
<div
className={`ds-calendar${compact ? " ds-calendar--compact" : ""}`}
data-months={months}
style={{ "--calendar-weeks": timeline.weeks } as CSSProperties}
style={{ "--calendar-weeks": timeline.weeks, "--calendar-color": color } as CSSProperties}
>
<div className="ds-calendar-range-toolbar">
<span className="ds-calendar-range-label" aria-live="polite">
@@ -273,20 +274,29 @@ export function CalendarHeatmap({
(compact ? "Demo history" : "Illustrative history")}
</span>
</span>
<span id={instructionsId} className="ds-muted">
Select a day. Up/down: one day. Left/right: one week. Home/end: first/last date.
</span>
<details className="ds-calendar-help">
<summary><Keyboard size={16} aria-hidden="true" /> Keyboard shortcuts</summary>
<p id={instructionsId}>
Select a day. Up/down: one day. Left/right: one week. Home/end: first/last date.
</p>
</details>
</div>
<div id={inspectorId} className="ds-date-inspector" aria-live="polite">
<span>
{new Date(`${selected.date}T12:00:00Z`).toLocaleDateString("en", {
month: "long",
day: "numeric",
year: "numeric",
timeZone: "UTC",
})}
</span>
<span>{describeDay(selected, unit)}</span>
<div className="ds-date-inspector-heading">
<CalendarDays size={22} aria-hidden="true" />
<div>
<span className="ds-eyebrow">SELECTED DAY</span>
<time dateTime={selected.date}>
{new Date(`${selected.date}T12:00:00Z`).toLocaleDateString("en", {
month: "long",
day: "numeric",
year: "numeric",
timeZone: "UTC",
})}
</time>
<span className="ds-date-inspector-status">{describeDay(selected, unit)}</span>
</div>
</div>
</div>
</div>
);