diff --git a/docs/superpowers/plans/2026-03-20-pixelarticons-migration.md b/docs/superpowers/plans/2026-03-20-pixelarticons-migration.md new file mode 100644 index 0000000..5544f6a --- /dev/null +++ b/docs/superpowers/plans/2026-03-20-pixelarticons-migration.md @@ -0,0 +1,672 @@ +# Pixelarticons Migration + Favorites Rename — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Replace Lucide icons with pixelarticons via @iconify/svelte across the app (except 4 formatting letterforms), and rename user-facing "pinned" to "favorites" with a heart icon. + +**Architecture:** Each component file gets its Lucide imports replaced with a single `Icon` import from `@iconify/svelte`. The `size` prop becomes `width`, and the icon name becomes a `pixelarticons:name` string. The 4 formatting letterforms (Bold, Italic, Strikethrough, Underline) stay as Lucide. The favorites rename touches stores, components, MCP server, and one e2e test. + +**Tech Stack:** `@iconify/svelte` v5.2.1, `@iconify-json/pixelarticons` v1.2.4 (both already installed), `lucide-svelte` (kept for 4 icons) + +**Spec:** `docs/superpowers/specs/2026-03-20-pixelarticons-migration-design.md` + +--- + +## File Structure + +No new files created. All changes are modifications to existing files: + +**Icon migration (16 files):** Replace Lucide imports with `@iconify/svelte` Icon component. +**Favorites rename (4 source files + 1 test file):** Rename stores, functions, labels, test IDs. + +--- + +### Task 1: Favorites Rename — Stores + +**Files:** +- Modify: `src/lib/stores/notes.ts:38-44,234-236` + +- [ ] **Step 1: Rename store exports and function** + +In `src/lib/stores/notes.ts`, make these changes: + +```typescript +// Line 38-44: Rename stores +export const favoriteNotes = derived(filteredNotes, ($notes) => + sortNotes($notes.filter((n) => n.pinned)) +); + +export const unfavoritedNotes = derived(filteredNotes, ($notes) => + sortNotes($notes.filter((n) => !n.pinned)) +); + +// Line 234-236: Rename function +export async function toggleFavorite(id: string, currentPinned: boolean): Promise { + return updateNote(id, { pinned: !currentPinned }); +} +``` + +Note: The `pinned` field in updateNote stays — it's the DB column name. + +- [ ] **Step 2: Verify no type errors** + +Run: `pnpm check 2>&1 | head -30` +Expected: Errors in files that still reference old names (NoteCard, NotesView) — that's expected, we fix those next. + +- [ ] **Step 3: Commit** + +```bash +git add src/lib/stores/notes.ts +git commit -m "refactor: rename pinned stores to favorites" +``` + +--- + +### Task 2: Favorites Rename — NoteCard Component + +**Files:** +- Modify: `src/lib/components/NoteCard.svelte:4,110-118,170-178` + +- [ ] **Step 1: Update import** + +Change line 4: +```typescript +import { toggleFavorite, trashNote, archiveNote, unarchiveNote, restoreNote, deleteNote, leaveNote, currentFilter } from '$lib/stores/notes.js'; +``` + +- [ ] **Step 2: Update favorite indicator (lines 110-118)** + +Replace the pinned indicator block: +```svelte +{#if note.pinned} + +{/if} +``` + +- [ ] **Step 3: Update favorite button (lines 170-178)** + +Replace the pin button block: +```svelte +{#if !note.pinned} + +{/if} +``` + +- [ ] **Step 4: Commit** + +```bash +git add src/lib/components/NoteCard.svelte +git commit -m "refactor: rename pin to favorite in NoteCard" +``` + +--- + +### Task 3: Favorites Rename — NotesView Component + +**Files:** +- Modify: `src/lib/components/NotesView.svelte:5,89-104` + +- [ ] **Step 1: Update imports (line 5)** + +```typescript +import { favoriteNotes, unfavoritedNotes, selectedTag, currentFilter, notes, notesLoaded, loadNotes, updateSortOrders } from '$lib/stores/notes.js'; +``` + +- [ ] **Step 2: Update template references** + +Replace all `$pinnedNotes` with `$favoriteNotes`, `$unpinnedNotes` with `$unfavoritedNotes`, and label `"Pinned"` with `"Favorites"`: + +Line 89: `{#if $favoriteNotes.length > 0}` +Line 91: `` +Line 96: `notes={$unfavoritedNotes}` +Line 97: `label={$favoriteNotes.length > 0 ? 'Others' : ''}` +Line 104: `{#if $notesLoaded && $favoriteNotes.length === 0 && $unfavoritedNotes.length === 0}` + +Note: Keep `dndType="pinned-notes"` unchanged — it's an internal DnD identifier, not user-facing. + +- [ ] **Step 3: Commit** + +```bash +git add src/lib/components/NotesView.svelte +git commit -m "refactor: rename pinned to favorites in NotesView" +``` + +--- + +### Task 4: Favorites Rename — MCP Server + +**Files:** +- Modify: `src/lib/server/mcp/server.ts:241-265` + +- [ ] **Step 1: Rename MCP tool** + +Replace the `pin_note` tool definition (lines 241-265): +```typescript +server.tool( + 'favorite_note', + 'Favorite or unfavorite a note', + { + id: z.string().describe('Note ID'), + pinned: z.boolean().describe('Whether to favorite (true) or unfavorite (false)') + }, + async ({ id, pinned }: { id: string; pinned: boolean }) => { + const result = updateNote(db, userId, id, { pinned }); + if (!result) { + return { + content: [{ type: 'text' as const, text: 'Note not found' }], + isError: true + }; + } + return { + content: [ + { + type: 'text' as const, + text: `Note "${result.title}" ${pinned ? 'favorited' : 'unfavorited'}` + } + ] + }; + } +); +``` + +Note: The `pinned` parameter name stays since it maps to the DB column. + +- [ ] **Step 2: Commit** + +```bash +git add src/lib/server/mcp/server.ts +git commit -m "refactor: rename pin_note MCP tool to favorite_note" +``` + +--- + +### Task 5: Favorites Rename — E2E Test + +**Files:** +- Modify: `tests/e2e/organization.spec.ts:4-15` + +- [ ] **Step 1: Update test scenario** + +Replace lines 4-15: +```typescript +test('Scenario: Favorited note appears under the Favorites section', async ({ authenticatedPage: page }) => { + // Given a note titled "Favorite Me" exists + await createNote(page, 'Favorite Me'); + + // When the user favorites the note + const favCard = noteCard(page, 'Favorite Me'); + await favCard.hover(); + await favCard.getByTestId('favorite-btn').first().click({ force: true }); + + // Then the "Favorites" section is visible + await expect(page.getByText('Favorites')).toBeVisible(); +}); +``` + +- [ ] **Step 2: Run check to verify favorites rename is complete** + +Run: `pnpm check 2>&1 | head -20` +Expected: PASS (no errors related to old pin names) + +- [ ] **Step 3: Commit** + +```bash +git add tests/e2e/organization.spec.ts +git commit -m "test: update pin test to favorites" +``` + +--- + +### Task 6: Icon Migration — Header + SearchBar + +**Files:** +- Modify: `src/lib/components/Layout/Header.svelte:2-5` +- Modify: `src/lib/components/SearchBar.svelte:4-6` + +- [ ] **Step 1: Migrate Header.svelte** + +Replace imports (lines 2-5): +```typescript +import SearchBar from '../SearchBar.svelte'; +import SyncIndicator from '../SyncIndicator.svelte'; +import Icon from '@iconify/svelte'; +``` + +Replace icon usage in template: +- `` → `` +- `` → `` + +- [ ] **Step 2: Migrate SearchBar.svelte** + +Replace imports (lines 4-6): +```typescript +import Icon from '@iconify/svelte'; +``` + +Replace icon usage: +- `` → `` +- `` → `` +- `` → `` + +Match existing `class` attributes exactly — just change the component and add the `icon` prop. + +- [ ] **Step 3: Commit** + +```bash +git add src/lib/components/Layout/Header.svelte src/lib/components/SearchBar.svelte +git commit -m "feat: migrate Header and SearchBar to pixelarticons" +``` + +--- + +### Task 7: Icon Migration — Sidebar + +**Files:** +- Modify: `src/lib/components/Layout/Sidebar.svelte:2-4,19-23,47,65,81` + +- [ ] **Step 1: Replace imports and nav items** + +Replace the import (line 4): +```typescript +import Icon from '@iconify/svelte'; +``` + +Replace navItems array (lines 19-23): +```typescript +const navItems = [ + { href: '/', label: 'Crumbs', icon: 'pixelarticons:sticky-note', match: (p: string) => p === '/' }, + { href: '/archive', label: 'Archive', icon: 'pixelarticons:archive', match: (p: string) => p === '/archive' }, + { href: '/trash', label: 'Trash', icon: 'pixelarticons:trash', match: (p: string) => p === '/trash' } +]; +``` + +- [ ] **Step 2: Update template icon usage** + +Line 47: `` → `` +Line 65: `` → `` +Line 81: `` → `` + +- [ ] **Step 3: Commit** + +```bash +git add src/lib/components/Layout/Sidebar.svelte +git commit -m "feat: migrate Sidebar to pixelarticons" +``` + +--- + +### Task 8: Icon Migration — NoteCard + +**Files:** +- Modify: `src/lib/components/NoteCard.svelte:5-13,117,159,167,177,187,196,206,215` + +- [ ] **Step 1: Replace imports** + +Replace lines 5-13: +```typescript +import Icon from '@iconify/svelte'; +``` + +Remove all individual Lucide imports (Undo2, Trash2, Bookmark, Archive, ArchiveRestore, UserMinus). + +- [ ] **Step 2: Replace all icon usages in template** + +- `` (favorite indicator) → `` +- `` (favorite button) → `` +- `` (restore) → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` + +- [ ] **Step 3: Commit** + +```bash +git add src/lib/components/NoteCard.svelte +git commit -m "feat: migrate NoteCard to pixelarticons" +``` + +--- + +### Task 9: Icon Migration — NoteEditor + +**Files:** +- Modify: `src/lib/components/NoteEditor.svelte:16-24` + +- [ ] **Step 1: Replace imports** + +Replace lines 16-24: +```typescript +import Icon from '@iconify/svelte'; +``` + +- [ ] **Step 2: Replace all icon usages** + +Search the file for each Lucide component and replace: +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` + +For each, keep the existing `size` prop but rename to `width`. Keep `class` as-is. + +- [ ] **Step 3: Commit** + +```bash +git add src/lib/components/NoteEditor.svelte +git commit -m "feat: migrate NoteEditor to pixelarticons" +``` + +--- + +### Task 10: Icon Migration — FormattingToolbar + +This is the largest file. Bold, Italic, Strikethrough, Underline stay as Lucide. Everything else migrates. + +**Files:** +- Modify: `src/lib/components/FormattingToolbar.svelte:2-31,131-482` + +- [ ] **Step 1: Replace imports** + +Replace the import block (lines 3-31): +```typescript +import { + Bold, + Italic, + Strikethrough, + Underline +} from 'lucide-svelte'; +import Icon from '@iconify/svelte'; +``` + +- [ ] **Step 2: Replace icon usages in template** + +Replace every non-B/I/S/U icon. The pattern: `` → ``. Full mapping: + +- `` → `` +- `` → `` +- `` → `` +- `` (appears 3x) → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` (appears 2x) → `` +- `` (appears 4x) → `` +- `` → `` +- `` → `` +- `` (appears 3x) → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` (2x) → `` +- `` (2x) → `` +- `` (2x) → `` +- `` (2x) → `` + +Leave these unchanged: ``, ``, ``, `` + +- [ ] **Step 3: Commit** + +```bash +git add src/lib/components/FormattingToolbar.svelte +git commit -m "feat: migrate FormattingToolbar to pixelarticons (keep B/I/S/U as Lucide)" +``` + +--- + +### Task 11: Icon Migration — SyncIndicator + +**Files:** +- Modify: `src/lib/components/SyncIndicator.svelte:4-7,54-61` + +- [ ] **Step 1: Replace imports** + +Replace lines 4-7: +```typescript +import Icon from '@iconify/svelte'; +``` + +- [ ] **Step 2: Replace icon usages** + +Replace the status icon block (lines 53-61): +```svelte +{#if displayStatus === 'synced'} + +{:else if displayStatus === 'syncing'} + +{:else if displayStatus === 'offline'} + +{:else} + +{/if} +``` + +- [ ] **Step 3: Commit** + +```bash +git add src/lib/components/SyncIndicator.svelte +git commit -m "feat: migrate SyncIndicator to pixelarticons" +``` + +--- + +### Task 12: Icon Migration — Remaining Small Components + +**Files:** +- Modify: `src/lib/components/NoteHistory.svelte:3-5` +- Modify: `src/lib/components/ShareDialog.svelte:3-5` +- Modify: `src/lib/components/Checklist.svelte:2-5` +- Modify: `src/lib/components/CollaboratorPopover.svelte:3` +- Modify: `src/lib/components/ImageLightbox.svelte:2` +- Modify: `src/lib/components/ImageUpload.svelte:2-4` +- Modify: `src/lib/components/NotesView.svelte:8` + +- [ ] **Step 1: Migrate NoteHistory.svelte** + +Replace imports: +```typescript +import Icon from '@iconify/svelte'; +``` +Replace usages: +- `` → `` +- `` → `` +- `` → `` + +- [ ] **Step 2: Migrate ShareDialog.svelte** + +Replace imports: +```typescript +import Icon from '@iconify/svelte'; +``` +Replace usages: +- `` → `` +- `` → `` +- `` → `` + +- [ ] **Step 3: Migrate Checklist.svelte** + +Replace imports: +```typescript +import Icon from '@iconify/svelte'; +``` +Replace usages: +- `` → `` +- `` → `` +- `` → `` +- `` → `` + +- [ ] **Step 4: Migrate CollaboratorPopover.svelte** + +Replace import: +```typescript +import Icon from '@iconify/svelte'; +``` +Replace: `` → `` + +- [ ] **Step 5: Migrate ImageLightbox.svelte** + +Replace import: +```typescript +import Icon from '@iconify/svelte'; +``` +Replace: `` → `` + +- [ ] **Step 6: Migrate ImageUpload.svelte** + +Replace imports: +```typescript +import Icon from '@iconify/svelte'; +``` +Replace usages: +- `` → `` +- `` → `` +- `` → `` + +- [ ] **Step 7: Migrate NotesView.svelte (Plus icon)** + +Replace import (line 8): +```typescript +import Icon from '@iconify/svelte'; +``` +Replace usages: +- `` → `` +- `` → `` + +- [ ] **Step 8: Commit** + +```bash +git add src/lib/components/NoteHistory.svelte src/lib/components/ShareDialog.svelte src/lib/components/Checklist.svelte src/lib/components/CollaboratorPopover.svelte src/lib/components/ImageLightbox.svelte src/lib/components/ImageUpload.svelte src/lib/components/NotesView.svelte +git commit -m "feat: migrate remaining components to pixelarticons" +``` + +--- + +### Task 13: Icon Migration — Settings Pages + +**Files:** +- Modify: `src/routes/(app)/settings/+layout.svelte:3` +- Modify: `src/routes/(app)/settings/mcp/+page.svelte:2` + +- [ ] **Step 1: Migrate settings layout** + +Replace import (line 3): +```typescript +import Icon from '@iconify/svelte'; +``` + +Replace usages: +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` + +- [ ] **Step 2: Migrate MCP settings page** + +Replace import (line 2): +```typescript +import Icon from '@iconify/svelte'; +``` + +Replace usages: +- `` → `` +- `` → `` +- `` → `` +- `` → `` +- `` → `` + +- [ ] **Step 3: Commit** + +```bash +git add src/routes/(app)/settings/+layout.svelte src/routes/(app)/settings/mcp/+page.svelte +git commit -m "feat: migrate settings pages to pixelarticons" +``` + +--- + +### Task 14: Update docs/FEATURES.md + +**Files:** +- Modify: `docs/FEATURES.md:67-70,141` + +- [ ] **Step 1: Rename "Pin Notes" section to "Favorite Notes"** + +Replace lines 67-70: +```markdown +### Favorite Notes +- Favorite important notes to always appear at top +- Favorites section separated from other notes +- Toggle favorite from note card hover actions +``` + +- [ ] **Step 2: Update MCP tools description** + +Line 141: replace `pin` with `favorite` in the tools list: +```markdown +- 14 tools: list, get, create, update, trash, restore, archive, unarchive, delete, search notes; list tags; favorite, reorder notes; upload images +``` + +- [ ] **Step 3: Commit** + +```bash +git add docs/FEATURES.md +git commit -m "docs: rename pin to favorites in FEATURES.md" +``` + +--- + +### Task 15: Verification + +- [ ] **Step 1: Run type check** + +Run: `pnpm check` +Expected: PASS with no errors + +- [ ] **Step 2: Run unit tests** + +Run: `pnpm test:unit` +Expected: All tests pass (DB/CRDT tests use `pinned` field which is unchanged) + +- [ ] **Step 3: Run e2e tests** + +Run: `pnpm test:e2e` +Expected: All tests pass including the updated organization spec + +- [ ] **Step 4: Update CLAUDE.md icons section** + +Add to the "Visual rules" section in CLAUDE.md after the "Icons" line: + +```markdown +- **Icons**: Pixelarticons via `@iconify/svelte` — use ``. Exception: Bold, Italic, Strikethrough, Underline stay as Lucide (`lucide-svelte`). See full mapping in `docs/superpowers/specs/2026-03-20-pixelarticons-migration-design.md`. +``` + +- [ ] **Step 5: Commit docs update** + +```bash +git add CLAUDE.md +git commit -m "docs: update CLAUDE.md with pixelarticons icon usage" +``` diff --git a/docs/superpowers/specs/2026-03-20-pixelarticons-migration-design.md b/docs/superpowers/specs/2026-03-20-pixelarticons-migration-design.md new file mode 100644 index 0000000..94df2b1 --- /dev/null +++ b/docs/superpowers/specs/2026-03-20-pixelarticons-migration-design.md @@ -0,0 +1,182 @@ +# Icon Migration: Lucide → Pixelarticons + "Pinned" → "Favorites" Rename + +**Date:** 2026-03-20 +**Status:** Approved + +## Summary + +Replace Lucide icons with pixelarticons (via `@iconify/svelte`) across the app to match the retro parchment aesthetic. Keep Lucide only for 4 text-formatting letterform icons (Bold, Italic, Strikethrough, Underline). Additionally, rename the user-facing "pinned" concept to "favorites" with a heart icon, while keeping the `pinned` database column unchanged. + +## Motivation + +The current Lucide icons have smooth, modern strokes that clash with the 8-bit retro parchment design system. Pixelarticons are drawn on a strict 24×24 pixel grid with no anti-aliasing — a natural fit for the `Press Start 2P` pixel font and hard-offset shadow aesthetic already in use. + +## Technical Approach + +### Icon Library + +- **Package:** `@iconify/svelte` (v5.2.1, already installed) + `@iconify-json/pixelarticons` (v1.2.4, already installed) +- **Usage:** `` +- **Tree-shaking:** Iconify handles this automatically — only icons used in code are bundled + +### Icon Mapping + +56 icons migrated to pixelarticons, 4 kept as Lucide: + +#### Navigation & UI +| Lucide | Pixelarticons | +|--------|--------------| +| Menu | `menu` | +| Search | `search` | +| X / XIcon | `close` | +| Plus | `plus` | +| Check | `check` | +| ArrowLeft | `arrow-left` | +| ChevronRight | `chevron-right` | +| ChevronDown | `chevron-down` | +| Settings | `settings-cog` | +| ExternalLink | `external-link` | + +#### Notes & Content +| Lucide | Pixelarticons | Notes | +|--------|--------------|-------| +| StickyNote | `sticky-note` | | +| Archive | `archive` | | +| ArchiveRestore | `archive` | Context makes it clear | +| Trash2 | `trash` | | +| Bookmark | `heart` | Renamed to "favorite" | +| Clock | `clock` | | +| History | `timeline` | | +| FileText | `file-text` | | +| FileCode | `script` | | +| ImageIcon | `image` | | +| Palette | `colors-swatch` | | +| GripVertical | `drag-and-drop` | | +| Star | `pin` | Used in ImageUpload for "featured image" toggle — not related to favorites | +| SquareCheck | `checkbox-on` | | +| Type | `art-text` | | + +#### Text Formatting (toolbar) +| Lucide | Pixelarticons | Notes | +|--------|--------------|-------| +| **Bold** | **Keep Lucide** | Letterform | +| **Italic** | **Keep Lucide** | Letterform | +| **Strikethrough** | **Keep Lucide** | Letterform | +| **Underline** | **Keep Lucide** | Letterform | +| Code | `braces` | | +| CodeXml | `braces` | | +| Heading | `heading` | | +| Link | `link` | | +| TextQuote | `quote-text-inline` | | +| List | `list` | | +| ListOrdered | `bulletlist` | | +| ListChecks | `checklist` | | +| AlignLeft | `text-align-left` | | +| AlignCenter | `text-align-center` | | +| AlignRight | `text-align-right` | | +| AlignJustify | `text-align-justify` | | +| Table2 | `table` | | +| Minus | `minus` | | +| RemoveFormatting | `remove-box` | | +| CornerDownLeft | `corner-down-left` | | +| BetweenHorizontalEnd | `add-row` | | +| BetweenVerticalEnd | `add-col` | | + +#### Undo/Redo +| Lucide | Pixelarticons | +|--------|--------------| +| Undo2 | `undo` | +| Redo2 | `redo` | +| RotateCcw | `undo` | +| RefreshCw | `reload` | + +#### Sync Status +| Lucide | Pixelarticons | Notes | +|--------|--------------|-------| +| CloudCheck | `cloud-done` | | +| CloudSync | `sync` | | +| CloudOff | `cloud` | Color conveys offline state | +| CloudAlert | `cloud` | Color conveys error state | + +#### Users & Admin +| Lucide | Pixelarticons | +|--------|--------------| +| User | `user` | +| Users | `users` | +| UserPlus | `user-plus` | +| UserMinus | `user-minus` | +| Cpu | `cpu` | +| ShieldCheck | `shield` | +| SlidersHorizontal | `sliders` | +| Info | `info-box` | +| Key | `lock` | +| Copy | `copy` | +| Tag | `label` | + +### "Pinned" → "Favorites" Rename + +**Scope:** User-facing labels, function names, store names, MCP tool names, test IDs. The database column `pinned` stays unchanged to avoid a migration. + +**Renames:** +| Current | New | +|---------|-----| +| `pinnedNotes` (store) | `favoriteNotes` | +| `unpinnedNotes` (store) | `unfavoritedNotes` | +| `togglePin()` | `toggleFavorite()` | +| `"Pinned"` label in NotesView | `"Favorites"` | +| `"Pin"` / `"Unpin"` tooltips in NoteCard | `"Favorite"` / `"Unfavorite"` | +| `pin_note` MCP tool | `favorite_note` | +| `pin-btn` / `pin-indicator` test IDs | `favorite-btn` / `favorite-indicator` | + +**Not renamed (internal/DB):** +- `pinned` column in `notes` and `noteUserState` tables +- `pinned` field in TypeScript types (`Note`, `NoteUpdate`, `NoteChange`) +- `pinned` references in CRDT sync logic +- `pinned` in server-side sync overlay + +## Files to Modify + +### Icon migration (16 files) +1. `src/lib/components/Layout/Sidebar.svelte` +2. `src/lib/components/Layout/Header.svelte` +3. `src/lib/components/FormattingToolbar.svelte` +4. `src/lib/components/NoteCard.svelte` +5. `src/lib/components/NoteEditor.svelte` +6. `src/lib/components/NoteHistory.svelte` +7. `src/lib/components/SyncIndicator.svelte` +8. `src/lib/components/SearchBar.svelte` +9. `src/lib/components/ShareDialog.svelte` +10. `src/lib/components/Checklist.svelte` +11. `src/lib/components/CollaboratorPopover.svelte` +12. `src/lib/components/ImageLightbox.svelte` +13. `src/lib/components/ImageUpload.svelte` +14. `src/lib/components/NotesView.svelte` +15. `src/routes/(app)/settings/+layout.svelte` +16. `src/routes/(app)/settings/mcp/+page.svelte` + +### Favorites rename (7 files) +1. `src/lib/stores/notes.ts` — store names + `toggleFavorite` +2. `src/lib/components/NoteCard.svelte` — tooltips, test IDs, icon +3. `src/lib/components/NotesView.svelte` — label, store imports +4. `src/lib/server/mcp/server.ts` — tool name + description +5. `docs/FEATURES.md` — update feature description +6. `tests/e2e/organization.spec.ts` — `pin-btn` test ID + `getByText('Pinned')` → `getByText('Favorites')` + scenario names/comments +7. Note: `tests/e2e/sharing.spec.ts` references `pinned` as a data field — does NOT need renaming (DB field stays `pinned`) + +### Cleanup +- Remove `lucide-svelte` from `package.json` once only 4 icons remain — or keep it as a dependency for those 4. Decision: keep it, the 4 formatting icons are deeply integrated. + +### Documentation +- Update `CLAUDE.md` "Icons" section to document pixelarticons usage +- Update `docs/FEATURES.md` if it mentions pinning + +## Testing Strategy + +- Run `pnpm check` after migration to catch type errors +- Run `pnpm test:unit` to verify sync/CRDT tests still pass (they use `pinned` field which is unchanged) +- Run `pnpm test:e2e` to verify UI still works — tests referencing `pin-btn`/`pin-indicator` will need updating +- Visual verification: icons render correctly at all sizes (12-20px) + +## Rendering Note + +Pixelarticons are designed for the 24×24 grid and render sharpest at multiples of 24px. At the sizes used in this app (12-20px), they will still look good because `@iconify/svelte` renders them as SVG (vector), but the pixel-art crispness is maximized at 24px. Consider using `image-rendering: pixelated` on icon SVGs if sub-24px rendering looks blurry, though SVG scaling typically handles this well. diff --git a/package.json b/package.json index 5b305e0..096691f 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,8 @@ "docs:api": "tsx scripts/generate-api-docs.ts" }, "dependencies": { + "@iconify-json/pixelarticons": "^1.2.4", + "@iconify/svelte": "^5.2.1", "@modelcontextprotocol/sdk": "^1.27.1", "@sveltejs/adapter-node": "^5.5.4", "@tiptap/core": "^3.20.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c97d4ee..31a67c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,12 @@ importers: .: dependencies: + '@iconify-json/pixelarticons': + specifier: ^1.2.4 + version: 1.2.4 + '@iconify/svelte': + specifier: ^5.2.1 + version: 5.2.1(svelte@5.53.7) '@modelcontextprotocol/sdk': specifier: ^1.27.1 version: 1.27.1(zod@4.3.6) @@ -1018,6 +1024,17 @@ packages: peerDependencies: hono: '>=4.12.7' + '@iconify-json/pixelarticons@1.2.4': + resolution: {integrity: sha512-nADJKEI3mlxDSmJMLqGvNuvNl1TGa+VbFJIwrtj/8vUA4m15qPNiwxMyw8YxW3gVokuO9MNU462B8uK1hb4rqw==} + + '@iconify/svelte@5.2.1': + resolution: {integrity: sha512-zHmsIPmnIhGd5gc95bNN5FL+GifwMZv7M2rlZEpa7IXYGFJm/XGHdWf6PWQa6OBoC+R69WyiPO9NAj5wjfjbow==} + peerDependencies: + svelte: '>5.0.0' + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -4851,6 +4868,17 @@ snapshots: dependencies: hono: 4.12.7 + '@iconify-json/pixelarticons@1.2.4': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/svelte@5.2.1(svelte@5.53.7)': + dependencies: + '@iconify/types': 2.0.0 + svelte: 5.53.7 + + '@iconify/types@2.0.0': {} + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 diff --git a/static/api/openapi.json b/static/api/openapi.json index 4be26d7..a455f32 100644 --- a/static/api/openapi.json +++ b/static/api/openapi.json @@ -3,7 +3,7 @@ "info": { "title": "Crumbs API", "description": "Auto-generated API spec for crumbs", - "version": "0.21.9", + "version": "0.22.3", "contact": { "name": "Bretzel", "url": "https://bretzel.app"