diff --git a/.gitignore b/.gitignore index 111cf4c..c0a8248 100644 --- a/.gitignore +++ b/.gitignore @@ -32,8 +32,8 @@ vite.config.ts.timestamp-* /test-results /playwright-report -# Skills CLI (actual files are in .agents/skills/) -/.claude/skills +# Claude Code +/.claude/ # Local notes todo.md diff --git a/CLAUDE.md b/CLAUDE.md index d831a45..278bad2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,21 +14,73 @@ Crumbs by Bretzel — self-hostable note-taking app. Single-user, offline-first - **PWA**: `@vite-pwa/sveltekit` for service worker and offline caching - **Package manager**: pnpm +## Design system: Retro Parchment + +The UI follows a **parchment + 8-bit retro** aesthetic. All design decisions must preserve this character. + +### Color palette + +All colors are CSS variables in `src/app.css`. Never use hardcoded Tailwind colors (e.g. `text-gray-500`, `bg-red-600`) — always reference CSS variables: + +| Variable | Value | Usage | +|---|---|---| +| `--bg-base` | `#f0e6d3` | Page background (warm parchment) | +| `--bg-surface` | `#faf5eb` | Cards, panels, inputs | +| `--primary` | `#C8860A` | Brand gold — links, active states, accents | +| `--primary-hover` | `#E8A020` | Gold hover state | +| `--text` | `#1a1a2e` | Primary text (near-black) | +| `--text-muted` | `#6b6272` | Secondary text, placeholders | +| `--border` | `#1a1a2e` | Strong borders (editor, login card) | +| `--border-subtle` | `#d4cabb` | Default card borders, dividers | +| `--destructive` | `#a63d2f` | Delete actions, error icons | +| `--error-bg/border/text` | warm reds | Error states (themed, not clinical red) | +| `--success-bg/text` | warm greens | Success states | +| `--card-shadow` | `2px 2px 0px` | Hard-offset retro shadow (no blur) | +| `--card-shadow-hover` | `3px 3px 0px` | Hover shadow in primary gold | + +Note colors for cards are defined in `src/lib/utils/colors.ts`. + +### Typography + +- **Body**: `JetBrains Mono` (monospace) — the hacker/dev aesthetic +- **Brand / empty states**: `Press Start 2P` (pixel font) — the 8-bit accent +- These two fonts are intentional. Do not replace them or add others. + +### Visual rules + +- **Shadows**: Always hard-offset (`2px 2px 0px`) with zero blur. Never use `shadow-sm`, `shadow-md` etc. — they look too modern. +- **Corners**: `rounded-sm` everywhere. Sharp, not rounded. Exception: color picker circles use `rounded-full`. +- **Borders**: Default card borders use `--border-subtle`. `--border` is for strong emphasis (editor, login card). Hover borders use `--primary`. +- **Animations**: Crisp and fast (150ms `ease-out`). No spring physics, no bounce. The retro feel comes from snappy transitions. +- **Background texture**: A subtle 4px pixel grid overlay at 3% opacity (defined in `body::before`). +- **Checkboxes**: Use `accent-color: var(--primary)` globally — gold checkboxes match the theme. +- **Icons**: Lucide icons throughout. Keep at 16-20px size. + +### Layout groups + +- `(auth)` — Login/setup pages: minimal centered layout, no app chrome +- `(app)` — Main app: header, sidebar, footer, toast notifications + ## Project structure ``` src/ - routes/ # SvelteKit pages and API routes - +page.svelte # Main notes view - login/ # Login page - setup/ # First-time password setup + routes/ + +layout.svelte # Root layout (imports CSS only) + (auth)/ # Layout group: login/setup (minimal, no app chrome) + +layout.svelte # Centered parchment background + login/ # Login page + setup/ # First-time password setup + (app)/ # Layout group: main app (header, sidebar, footer) + +layout.svelte # App shell with Header, Sidebar, Toast + +page.svelte # Main notes view api/auth/ # Login, logout, setup endpoints api/notes/ # CRUD + attachments api/search/ # Full-text search api/sync/ # Offline sync api/tags/ # Tag management lib/ - components/ # Svelte components (NoteCard, NoteEditor, ColorPicker, etc.) + components/ # Svelte components (NoteCard, NoteEditor, TagChip, etc.) stores/ # Svelte stores (notes.ts, theme.ts) server/db/ # Drizzle schema + connection (schema.ts, index.ts) server/ # Auth logic, attachment handling diff --git a/src/app.css b/src/app.css index 80921a2..9e0a08e 100644 --- a/src/app.css +++ b/src/app.css @@ -38,6 +38,17 @@ body::before { z-index: 0; } +/* Editor entrance animations */ +@keyframes fade-in { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes pop-in { + from { opacity: 0; transform: scale(0.95) translateY(8px); } + to { opacity: 1; transform: scale(1) translateY(0); } +} + /* Prose overrides for parchment theme */ .prose { --tw-prose-body: var(--text); diff --git a/src/lib/components/NoteCard.svelte b/src/lib/components/NoteCard.svelte index 5690c5d..52f221a 100644 --- a/src/lib/components/NoteCard.svelte +++ b/src/lib/components/NoteCard.svelte @@ -2,6 +2,7 @@ import { NOTE_COLORS } from '$lib/utils/colors.js'; import { renderMarkdown } from '$lib/utils/markdown.js'; import { togglePin, trashNote, archiveNote, unarchiveNote, restoreNote, deleteNote, updateNote, currentFilter } from '$lib/stores/notes.js'; + import TagChip from './TagChip.svelte'; import type { Note } from '$lib/types/index.js'; import Undo2 from 'lucide-svelte/icons/undo-2'; import Trash2 from 'lucide-svelte/icons/trash-2'; @@ -75,6 +76,17 @@ data-testid="note-card" data-note-id={note.id} > + {#if note.pinned} + + {/if} + {#if note.title}