feat: DESIRE tier — dark mode, shadcn primitives, Result type, logger, DX scripts#8
feat: DESIRE tier — dark mode, shadcn primitives, Result type, logger, DX scripts#8bryansayler wants to merge 9 commits into
Conversation
globals.css already defined full .dark OKLCH color vars but had no way to activate them. Adds next-themes with: - ThemeProvider in providers.tsx (attribute="class", defaultTheme="system") - ThemeToggle component using Sun/Moon icons from lucide-react - Renders as a ghost Button; toggles between light/dark on click Drop <ThemeToggle /> anywhere in a layout to enable the toggle. The system preference is respected by default. https://claude.ai/code/session_012Mh4xLVoCPRt2pNacxpPtH
Adds the five shadcn/ui primitives most commonly needed for real UI work. Hand-written to match shadcn new-york v4 patterns since the shadcn CLI registry is unreachable in this environment. - Card (+ Header, Title, Description, Content, Footer) - Input (text field with ring focus styles) - Label (via @radix-ui/react-label + CVA) - Separator (via @radix-ui/react-separator, h/v) - Sonner Toaster (theme-aware via next-themes) https://claude.ai/code/session_012Mh4xLVoCPRt2pNacxpPtH
Lightweight Result<T, E> union type for representing success/failure without exceptions. Provides: - ok(), err() constructors - tryCatch() / tryCatchAsync() wrappers - unwrap(), unwrapOr() extractors - map(), mapErr() transformers 10 unit tests covering all paths. Use for DB operations, API calls, and anywhere "this might fail" needs to be explicit in the type. https://claude.ai/code/session_012Mh4xLVoCPRt2pNacxpPtH
Single shared logger instance with ISO timestamps and structured
JSON output. Uses pino/file transport in development for readable
stdout; raw JSON in production for log aggregators.
Set LOG_LEVEL env var to control verbosity (default: info).
import { logger } from "@/lib/logger";
logger.info({ userId }, "user signed in");
https://claude.ai/code/session_012Mh4xLVoCPRt2pNacxpPtH
- db:reset: wipes local.db and re-runs migrations (clean slate) - db:seed: runs scripts/seed.ts to populate test users Seed script inserts two demo users (admin@quirk.systems and dev@quirk.systems). Extend with additional tables as schema grows. Only for local development — never run against production. https://claude.ai/code/session_012Mh4xLVoCPRt2pNacxpPtH
Adds logger.ts, result.ts, theme-toggle.tsx, expanded shadcn ui list, ThemeProvider, db:reset, and db:seed to the directory structure and commands tables. https://claude.ai/code/session_012Mh4xLVoCPRt2pNacxpPtH
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 40eb5d35f0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
| } | ||
|
|
||
| export function unwrap<T>(result: Result<T>): T { |
There was a problem hiding this comment.
Accept generic error variants in unwrap helper
Result is defined with a generic error type and this module already produces non-Error variants (for example via err("...") or mapErr), but unwrap only accepts Result<T> which defaults the error side to Error. That makes unwrap unusable for valid Result<T, E> values where E is not Error, breaking composability of the API introduced in this commit; the signature should carry E through (and unwrapOr has the same issue).
Useful? React with 👍 / 👎.
Both helpers were typed as Result<T> which defaults E to Error, making them unusable with Result<T, string> or any custom error variant. Now carry E through so the full Result<T, E> API composes. https://claude.ai/code/session_012Mh4xLVoCPRt2pNacxpPtH
The scaffold's first impression is no longer a dead <h1>. The home page now showcases what's configured: - ThemeToggle wired (dark mode works out of the box) - Sonner Toaster mounted in layout (toast() calls render immediately) - Four Card tiles summarizing App Router, Database, Testing, and Tooling capabilities - GitHub + Next.js Docs link buttons Adds src/middleware.ts as a passthrough skeleton with PUBLIC_PATHS set and a TODO for Auth.js integration once PR #6 merges. Matcher excludes static assets and _next paths. Updates the page test to match the new description text. https://claude.ai/code/session_012Mh4xLVoCPRt2pNacxpPtH
Summary
DESIRE tier from the original plan. Adds the polish and DX features that make the scaffold feel complete rather than just functional.
Changes
Dark mode
next-themeswithThemeProviderinproviders.tsx(attribute="class", defaultTheme="system")ThemeTogglecomponent — Sun/Moon icon button using lucide-react.darkOKLCH vars; this activates themshadcn/ui primitives
Hand-written to match shadcn new-york v4 patterns (CLI registry was unreachable).
lib/result.ts
Lightweight
Result<T, E>union type for explicit error handling:ok(),err()constructorstryCatch()/tryCatchAsync()wrappersunwrap(),unwrapOr()extractorsmap(),mapErr()transformerslib/logger.ts
Structured pino logger with ISO timestamps. JSON output in prod, readable in dev.
LOG_LEVELenv var for verbosity.DX scripts
db:reset— wipes local.db and re-runs migrationsdb:seed— runsscripts/seed.tswith demo users (admin@quirk.systems, dev@quirk.systems)CLAUDE.md
Updated directory tree, component list, and commands table to reflect all additions.
Test plan
bun run validatepasses (lint + type-check + 12 unit tests + build)bun run dev→ import<ThemeToggle />in layout → toggle dark/lightimport { toast } from 'sonner'→toast('hello')renders themed toastNotes for reviewer
next-env.d.tseslint ignore is included here since it's needed on every branch that runsnext buildbefore lint.bunx shadcn@latest add <component>will overwrite them harmlessly.https://claude.ai/code/session_012Mh4xLVoCPRt2pNacxpPtH
Generated by Claude Code