Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
7.0 KiB
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:
<Icon icon="pixelarticons:icon-name" width={size} class="..." /> - 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):
pinnedcolumn innotesandnoteUserStatetablespinnedfield in TypeScript types (Note,NoteUpdate,NoteChange)pinnedreferences in CRDT sync logicpinnedin server-side sync overlay
Files to Modify
Icon migration (16 files)
src/lib/components/Layout/Sidebar.sveltesrc/lib/components/Layout/Header.sveltesrc/lib/components/FormattingToolbar.sveltesrc/lib/components/NoteCard.sveltesrc/lib/components/NoteEditor.sveltesrc/lib/components/NoteHistory.sveltesrc/lib/components/SyncIndicator.sveltesrc/lib/components/SearchBar.sveltesrc/lib/components/ShareDialog.sveltesrc/lib/components/Checklist.sveltesrc/lib/components/CollaboratorPopover.sveltesrc/lib/components/ImageLightbox.sveltesrc/lib/components/ImageUpload.sveltesrc/lib/components/NotesView.sveltesrc/routes/(app)/settings/+layout.sveltesrc/routes/(app)/settings/mcp/+page.svelte
Favorites rename (7 files)
src/lib/stores/notes.ts— store names +toggleFavoritesrc/lib/components/NoteCard.svelte— tooltips, test IDs, iconsrc/lib/components/NotesView.svelte— label, store importssrc/lib/server/mcp/server.ts— tool name + descriptiondocs/FEATURES.md— update feature descriptiontests/e2e/organization.spec.ts—pin-btntest ID +getByText('Pinned')→getByText('Favorites')+ scenario names/comments- Note:
tests/e2e/sharing.spec.tsreferencespinnedas a data field — does NOT need renaming (DB field stayspinned)
Cleanup
- Remove
lucide-sveltefrompackage.jsononce 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.mdif it mentions pinning
Testing Strategy
- Run
pnpm checkafter migration to catch type errors - Run
pnpm test:unitto verify sync/CRDT tests still pass (they usepinnedfield which is unchanged) - Run
pnpm test:e2eto verify UI still works — tests referencingpin-btn/pin-indicatorwill 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.