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}

{note.title}

{/if} @@ -106,9 +118,7 @@ {#if note.tags && note.tags.length > 0}
{#each note.tags as tag} - - #{tag} - + {/each}
{/if} @@ -133,14 +143,16 @@ {:else} - + {#if !note.pinned} + + {/if} {#if $currentFilter === 'archived'} +{:else} + + #{tag} + +{/if} diff --git a/src/lib/components/TagFilter.svelte b/src/lib/components/TagFilter.svelte index 2bfbeb6..30e5dcb 100644 --- a/src/lib/components/TagFilter.svelte +++ b/src/lib/components/TagFilter.svelte @@ -1,5 +1,6 @@ + +
+
(sidebarOpen = !sidebarOpen)} /> + (sidebarOpen = false)} /> + +
+
+ {@render children()} +
+
+ +
+ Crumbs by Bretzel v{data.appVersion} — made with 🥨 in Strasbourg +
+ + +
diff --git a/src/routes/+page.svelte b/src/routes/(app)/+page.svelte similarity index 88% rename from src/routes/+page.svelte rename to src/routes/(app)/+page.svelte index 89fe20e..e45c708 100644 --- a/src/routes/+page.svelte +++ b/src/routes/(app)/+page.svelte @@ -6,6 +6,7 @@ import { onMount } from 'svelte'; import { get } from 'svelte/store'; import type { Note } from '$lib/types/index.js'; + import Plus from 'lucide-svelte/icons/plus'; let editingNote: Note | null = $state(null); let showNewNote = $state(false); @@ -43,9 +44,10 @@
diff --git a/src/routes/(auth)/+layout.svelte b/src/routes/(auth)/+layout.svelte new file mode 100644 index 0000000..650f9c0 --- /dev/null +++ b/src/routes/(auth)/+layout.svelte @@ -0,0 +1,7 @@ + + +
+ {@render children()} +
diff --git a/src/routes/(auth)/login/+page.svelte b/src/routes/(auth)/login/+page.svelte new file mode 100644 index 0000000..782f646 --- /dev/null +++ b/src/routes/(auth)/login/+page.svelte @@ -0,0 +1,68 @@ + + + + Login - Crumbs + + +
+
+ 🥨 +

Crumbs

+

Enter your password to continue

+
+ +
+ {#if errorMsg} +
+ {errorMsg} +
+ {/if} + + + + +
+
diff --git a/src/routes/(auth)/setup/+page.svelte b/src/routes/(auth)/setup/+page.svelte new file mode 100644 index 0000000..986aaec --- /dev/null +++ b/src/routes/(auth)/setup/+page.svelte @@ -0,0 +1,89 @@ + + + + Setup - Crumbs + + +
+
+ 🥨 +

Welcome to Crumbs

+

Set up your password to get started

+
+ +
+ {#if errorMsg} +
+ {errorMsg} +
+ {/if} + + + + + + +
+
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 808bb0f..b93e9ba 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,39 +1,7 @@ -
-
(sidebarOpen = !sidebarOpen)} /> - (sidebarOpen = false)} /> - -
-
- {@render children()} -
-
- -
- Crumbs by Bretzel v{data.appVersion} — made with 🥨 in Strasbourg -
- - -
+{@render children()} diff --git a/src/routes/login/+page.svelte b/src/routes/login/+page.svelte deleted file mode 100644 index 33277ce..0000000 --- a/src/routes/login/+page.svelte +++ /dev/null @@ -1,72 +0,0 @@ - - - - Login - Crumbs - - -
-
-
- 🥨 -

Crumbs

-

Enter your password to continue

-
- -
- {#if errorMsg} -
- {errorMsg} -
- {/if} - - - - -
-
-
diff --git a/src/routes/setup/+page.svelte b/src/routes/setup/+page.svelte deleted file mode 100644 index dc4fa80..0000000 --- a/src/routes/setup/+page.svelte +++ /dev/null @@ -1,93 +0,0 @@ - - - - Setup - Crumbs - - -
-
-
- 🥨 -

Welcome to Crumbs

-

Set up your password to get started

-
- -
- {#if errorMsg} -
- {errorMsg} -
- {/if} - - - - - - -
-
-