Skip to content

Commit 96f850b

Browse files
authored
fix(desktop): align chrome header rows (#522)
## Summary - Sidebar / note-list / editor chrome now share `--chrome-header-height` and `--chrome-header-padding`, so the gear cluster sits on the same row as All Notes. - Sync indicator is 28px (same as `IconButton`) so it does not stretch that row. - Settings uses the same 44px header and traffic lights (`8, 8`) instead of a 52px spacer. ## Test plan - [ ] Open the main window: sync / graph / settings sit on the same baseline as **All Notes** - [ ] Collapse/expand the sidebar; the note-list header does not jump - [ ] Open Settings: traffic lights and empty header match the main chrome height <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added reusable settings controls and cards for a more consistent settings experience. * Added animated icon hover states and improved visual feedback when items are moved to Trash. * **Style** * Improved desktop window header alignment and spacing. * Standardized note, sidebar, sync, and settings layouts with refined borders, sizing, colors, focus states, and scrolling. * Updated settings pages, navigation, groups, rows, disclosures, themes, integrations, devices, and plugins for a more consistent appearance. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent f54aeb8 commit 96f850b

99 files changed

Lines changed: 1338 additions & 1090 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/desktop/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@
3535
"@codemirror/autocomplete": "^6.20.3",
3636
"@codemirror/commands": "^6.10.3",
3737
"@codemirror/lang-markdown": "^6.5.0",
38-
"@codemirror/search": "^6.7.1",
3938
"@codemirror/language": "^6.12.3",
4039
"@codemirror/language-data": "^6.5.2",
40+
"@codemirror/search": "^6.7.1",
4141
"@codemirror/state": "^6.6.0",
4242
"@codemirror/view": "^6.43.0",
4343
"@lezer/common": "1.5.2",
@@ -53,8 +53,10 @@
5353
"electron-updater": "^6.8.9",
5454
"isomorphic-git": "^1.38.4",
5555
"katex": "^0.18.4",
56+
"lucide": "^1.17.0",
5657
"lucide-react": "^1.17.0",
5758
"mermaid": "^11.16.1",
59+
"morphicons": "^1.7.0",
5860
"pino": "^10.3.1",
5961
"react-markdown": "^10.1.0",
6062
"rehype-highlight": "^7.0.2",
@@ -72,8 +74,8 @@
7274
"@dripnex/commands": "workspace:*",
7375
"@dripnex/core": "workspace:*",
7476
"@dripnex/embeds": "workspace:*",
75-
"@dripnex/markdown": "workspace:*",
7677
"@dripnex/licensing": "workspace:*",
78+
"@dripnex/markdown": "workspace:*",
7779
"@dripnex/plugin-api": "workspace:*",
7880
"@dripnex/product-config": "workspace:*",
7981
"@dripnex/storage-core": "workspace:*",

apps/desktop/src/main/windows/settingsWindow.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function createSettingsWindow(): BrowserWindow {
2020
show: false,
2121
icon: resolveAppIconPath(),
2222
titleBarStyle: 'hiddenInset',
23-
trafficLightPosition: { x: 16, y: 18 },
23+
trafficLightPosition: { x: 8, y: 8 },
2424
backgroundColor: '#0a0b0d',
2525
title: 'Settings',
2626
webPreferences: {

apps/desktop/src/renderer/components/CommandPalette.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ import {
3434
SquareArrowOutUpRight,
3535
Sparkles,
3636
PenLine,
37-
} from 'lucide-react';
38-
import type { LucideIcon } from 'lucide-react';
37+
} from 'lucide';
3938
import type { CommandCategory } from '@dripnex/command-registry';
4039
import { LayoutZone } from '@dripnex/plugin-api';
40+
import { Icon, type IconInput } from '../ui/icons/Icon';
4141
import {
4242
useCommandRegistry,
4343
dispatchCommand,
@@ -75,7 +75,7 @@ interface NoteHit {
7575
title: string;
7676
}
7777

78-
const ICON_MAP: Record<string, LucideIcon> = {
78+
const ICON_MAP: Record<string, IconInput> = {
7979
Bold,
8080
Italic,
8181
Strikethrough,
@@ -375,7 +375,7 @@ export function CommandPalette({
375375
}}
376376
>
377377
<div className={sc('command-palette-input-wrapper')}>
378-
<Search size={16} />
378+
<Icon icon={Search} size={16} />
379379
<input
380380
ref={inputRef}
381381
className={sc('command-palette-input')}
@@ -429,7 +429,7 @@ export function CommandPalette({
429429
onMouseEnter={() => setSelectedIndex(index)}
430430
>
431431
<span className={sc('command-palette-item-icon')}>
432-
{IconComponent ? <IconComponent size={14} /> : null}
432+
{IconComponent ? <Icon icon={IconComponent} size={14} /> : null}
433433
</span>
434434
<span className={sc('command-palette-item-name')}>{cmd.name}</span>
435435
<span className={sc('command-palette-item-category')}>{group.label}</span>
@@ -448,7 +448,7 @@ export function CommandPalette({
448448
) : null}
449449
{flatItems.map((item, index) => {
450450
const isActive = index === selectedIndex;
451-
const Icon =
451+
const itemIcon =
452452
item.type === 'notebook'
453453
? BookMarked
454454
: item.type === 'tag' || item.type === 'heading'
@@ -477,7 +477,7 @@ export function CommandPalette({
477477
onMouseEnter={() => setSelectedIndex(index)}
478478
>
479479
<span className={sc('command-palette-item-icon')}>
480-
<Icon size={14} />
480+
<Icon icon={itemIcon} size={14} />
481481
</span>
482482
<span className={sc('command-palette-item-name')}>
483483
{item.type === 'command' ? item.id : item.title}

apps/desktop/src/renderer/components/GraphInspector.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
* Knowledge inspector — select a node, read it, walk relationships.
33
*/
44

5-
import { Activity, ArrowUpRight, Hash, Sparkles, X } from 'lucide-react';
5+
import { Activity, ArrowUpRight, Hash, Sparkles, X } from 'lucide';
6+
import { Icon } from '../ui/icons/Icon';
67
import { Button } from '../ui/primitives';
78
import { extractExcerpt, useNote } from '../hooks/useNotes';
89
import { useBacklinks, useOutgoingLinks } from '../hooks/useLinks';
@@ -68,7 +69,7 @@ export function GraphInspector({
6869
{!noteId ? (
6970
<div className={styles.inspectorEmpty}>
7071
<div className={styles.emptyIcon}>
71-
<Hash size={18} />
72+
<Icon icon={Hash} size={18} />
7273
</div>
7374
<p className={styles.inspectorEmptyTitle}>Select a node</p>
7475
<p className={styles.inspectorEmptyHint}>
@@ -91,7 +92,7 @@ export function GraphInspector({
9192
title="Deselect"
9293
aria-label="Deselect note"
9394
>
94-
<X size={14} />
95+
<Icon icon={X} size={14} />
9596
</button>
9697
</header>
9798

@@ -113,7 +114,7 @@ export function GraphInspector({
113114
className={styles.askBtn}
114115
variant="primary"
115116
size="md"
116-
icon={<Sparkles size={13} />}
117+
icon={<Icon icon={Sparkles} size={13} />}
117118
onClick={() => onAsk(note.id)}
118119
>
119120
Ask Dripnex
@@ -145,7 +146,7 @@ export function GraphInspector({
145146
inferred {Math.round(rel.score * 100)}%
146147
</span>
147148
) : null}
148-
<ArrowUpRight size={12} />
149+
<Icon icon={ArrowUpRight} size={12} />
149150
</span>
150151
</button>
151152
</li>
@@ -170,7 +171,7 @@ export function GraphInspector({
170171
<section className={styles.activity} aria-label="Ask activity">
171172
<div className={styles.activityHead}>
172173
<span className={styles.activityTitle}>
173-
<Activity size={13} />
174+
<Icon icon={Activity} size={13} />
174175
Activity
175176
</span>
176177
<span className={`${styles.idle} ${activityState === 'running' ? styles.idleLive : ''}`}>
@@ -185,7 +186,7 @@ export function GraphInspector({
185186
activity.map(event => (
186187
<div key={event.id} className={styles.event}>
187188
<div className={styles.eventHead}>
188-
<Sparkles size={11} />
189+
<Icon icon={Sparkles} size={11} />
189190
<code>{event.title}</code>
190191
</div>
191192
<p className={styles.eventBody}>{event.detail}</p>

apps/desktop/src/renderer/components/GraphView.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';
77
import { useQuery, useQueryClient } from '@tanstack/react-query';
88
import ForceGraph2D from 'react-force-graph-2d';
9-
import { X } from 'lucide-react';
9+
import { X } from 'lucide';
10+
import { Icon } from '../ui/icons/Icon';
1011
import { useGraphData } from '../hooks/useLinks';
1112
import { noteKeys } from '../hooks/useNotes';
1213
import { Input } from '../ui/primitives';
@@ -494,7 +495,7 @@ export function GraphView({ selectedNoteId, onOpenNote, onAskNote, onClose }: Gr
494495
</div>
495496
{onClose ? (
496497
<button type="button" className={styles.iconBtn} onClick={onClose} title="Close graph">
497-
<X size={14} />
498+
<Icon icon={X} size={14} />
498499
</button>
499500
) : null}
500501
</div>

apps/desktop/src/renderer/components/ImageLightbox.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
*/
77

88
import { useCallback, useEffect, useState } from 'react';
9-
import { X, ZoomIn, ZoomOut, RotateCw } from 'lucide-react';
9+
import { X, ZoomIn, ZoomOut, RotateCw } from 'lucide';
10+
import { Icon } from '../ui/icons/Icon';
1011
import { cssm } from '../lib/cssm';
1112
import styles from './ImageLightbox.module.css';
1213

@@ -75,7 +76,7 @@ export function ImageLightbox({ src, alt, onClose }: ImageLightboxProps) {
7576
aria-label="Zoom out"
7677
title="Zoom out (-)"
7778
>
78-
<ZoomOut size={20} />
79+
<Icon icon={ZoomOut} size={20} />
7980
</button>
8081
<span className={sc('lightbox-zoom-level')}>{Math.round(scale * 100)}%</span>
8182
<button
@@ -85,7 +86,7 @@ export function ImageLightbox({ src, alt, onClose }: ImageLightboxProps) {
8586
aria-label="Zoom in"
8687
title="Zoom in (+)"
8788
>
88-
<ZoomIn size={20} />
89+
<Icon icon={ZoomIn} size={20} />
8990
</button>
9091
<button
9192
type="button"
@@ -94,7 +95,7 @@ export function ImageLightbox({ src, alt, onClose }: ImageLightboxProps) {
9495
aria-label="Rotate"
9596
title="Rotate (R)"
9697
>
97-
<RotateCw size={20} />
98+
<Icon icon={RotateCw} size={20} />
9899
</button>
99100
<button
100101
type="button"
@@ -103,7 +104,7 @@ export function ImageLightbox({ src, alt, onClose }: ImageLightboxProps) {
103104
aria-label="Close"
104105
title="Close (Esc)"
105106
>
106-
<X size={20} />
107+
<Icon icon={X} size={20} />
107108
</button>
108109
</div>
109110

apps/desktop/src/renderer/components/NoteEditor.module.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@
6868
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
6969
align-items: center;
7070
column-gap: 8px;
71-
padding: 8px 10px;
72-
min-height: 44px;
71+
padding: var(--chrome-header-padding);
72+
height: var(--chrome-header-height);
73+
min-height: var(--chrome-header-height);
7374
border-bottom: 1px solid var(--border-subtle);
7475
-webkit-app-region: drag;
7576
}

apps/desktop/src/renderer/components/NoteEditor.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useRef, useCallback, useState, useEffect, useMemo, lazy, Suspense } from 'react';
2-
import { FileText, MoreVertical, Link2, Hash } from 'lucide-react';
2+
import { FileText, MoreVertical, Link2, Hash } from 'lucide';
33
import { LayoutZone } from '@dripnex/plugin-api';
44
import { toggleNthGfmTask, type MarkdownHeading } from '@dripnex/markdown';
5+
import { Icon } from '../ui/icons/Icon';
56
import { getEditorView } from '../hooks/useCommandRegistry';
67
import type { NoteSnapshot, NoteStatus } from '../../preload/index';
78
import { useEditorPreferencesStore } from '../stores/editorPreferencesStore';
@@ -456,7 +457,7 @@ export function NoteEditor({
456457
<main className={sc('note-editor')} aria-label="Note editor">
457458
<div className={sc('note-editor-empty')} role="status">
458459
<span className={sc('empty-icon')} aria-hidden="true">
459-
<FileText size={48} />
460+
<Icon icon={FileText} size={48} />
460461
</span>
461462
<p className={sc('empty-title')}>Select a note to edit</p>
462463
<p className={sc('empty-hint')}>Or press ⌘N to create a new one</p>
@@ -492,7 +493,7 @@ export function NoteEditor({
492493
aria-label="Toggle outline"
493494
aria-pressed={outlineOpen}
494495
>
495-
<Hash size={16} />
496+
<Icon icon={Hash} size={16} />
496497
</button>
497498
</div>
498499
}
@@ -523,7 +524,7 @@ export function NoteEditor({
523524
title={`Backlinks${backlinksCount > 0 ? ` (${backlinksCount})` : ''}`}
524525
aria-label="Open backlinks panel"
525526
>
526-
<Link2 size={18} />
527+
<Icon icon={Link2} size={18} />
527528
{backlinksCount > 0 && <span className={sc('badge')}>{backlinksCount}</span>}
528529
</button>
529530
<button
@@ -533,7 +534,7 @@ export function NoteEditor({
533534
title="More actions"
534535
aria-label="Open actions panel"
535536
>
536-
<MoreVertical size={18} />
537+
<Icon icon={MoreVertical} size={18} />
537538
</button>
538539
<LayoutZone name="editor-header-actions" />
539540
</>

apps/desktop/src/renderer/components/NoteList.module.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@
2323
display: flex;
2424
align-items: center;
2525
gap: 6px;
26-
padding: 8px 10px;
27-
min-height: 44px;
26+
padding: var(--chrome-header-padding);
27+
height: var(--chrome-header-height);
28+
min-height: var(--chrome-header-height);
2829
border-bottom: 1px solid var(--border-subtle);
2930
-webkit-app-region: drag;
3031
}

apps/desktop/src/renderer/components/NoteList.tsx

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ import {
77
X,
88
SquarePen,
99
FileStack,
10+
Files,
1011
PanelLeft,
12+
PanelLeftClose,
13+
Plus,
1114
Pin,
1215
PinOff,
1316
Globe,
14-
} from 'lucide-react';
17+
} from 'lucide';
1518
import { LayoutZone } from '@dripnex/plugin-api';
19+
import { Icon } from '../ui/icons/Icon';
1620
import { useNotebookList, useNotebook } from '../hooks/useNotebooks';
1721
import type { NoteWithExcerpt, SortBy, SortOrder } from '../hooks/useNavigation';
1822
import type { NoteStatus } from '../../preload/index';
@@ -85,17 +89,17 @@ function NoteListSkeleton() {
8589
function EmptyState({ variant }: { variant: 'no-notes' | 'no-archived' | 'no-results' }) {
8690
const content = {
8791
'no-notes': {
88-
icon: <Sparkles size={32} />,
92+
icon: <Icon icon={Sparkles} size={32} />,
8993
title: 'No notes yet',
9094
hint: 'Press ⌘N to create your first note',
9195
},
9296
'no-archived': {
93-
icon: <Archive size={32} />,
97+
icon: <Icon icon={Archive} size={32} />,
9498
title: 'Trash is empty',
9599
hint: 'Deleted notes will appear here',
96100
},
97101
'no-results': {
98-
icon: <Search size={32} />,
102+
icon: <Icon icon={Search} size={32} />,
99103
title: 'No matches found',
100104
hint: 'Try a different search term',
101105
},
@@ -272,25 +276,25 @@ export function NoteList({
272276
pressed={!sidebarCollapsed}
273277
onClick={onToggleSidebar}
274278
>
275-
<PanelLeft size={16} aria-hidden="true" />
279+
<Icon icon={sidebarCollapsed ? PanelLeft : PanelLeftClose} size={16} />
276280
</IconButton>
277281
) : null}
278282
<span className={sc('header-title')}>{getHeaderTitle()}</span>
279283
<LayoutZone name="note-list-header" />
280284
{onCreateFromTemplate && selectedNotebookId !== 'templates' ? (
281285
<IconButton label="New from template" onClick={() => setTemplatePickerOpen(true)}>
282-
<FileStack size={16} aria-hidden="true" />
286+
<Icon icon={FileStack} hoverIcon={Files} size={16} />
283287
</IconButton>
284288
) : null}
285289
<IconButton label="Create new note" onClick={onNewNote}>
286-
<SquarePen size={16} aria-hidden="true" />
290+
<Icon icon={SquarePen} hoverIcon={Plus} size={16} />
287291
</IconButton>
288292
</div>
289293

290294
{/* Search bar with icon + filter toggle */}
291295
<div className={sc('note-list-search')}>
292296
<div className={sc('search-input-wrapper')}>
293-
<Filter size={14} className={sc('search-icon')} aria-hidden="true" />
297+
<Icon icon={Filter} hoverIcon={Search} size={14} className={sc('search-icon')} />
294298
<label htmlFor="note-search" className="visually-hidden">
295299
Filter notes
296300
</label>
@@ -310,7 +314,7 @@ export function NoteList({
310314
aria-label="Clear filter"
311315
type="button"
312316
>
313-
<X size={14} />
317+
<Icon icon={X} size={14} />
314318
</button>
315319
)}
316320
</div>
@@ -452,9 +456,15 @@ function NoteListItem({
452456
>
453457
<div className={sc('note-list-item-title')}>
454458
<span className={sc('kind-dot')} style={{ background: kind.color }} title={kind.label} />
455-
{note.isPinned && <Pin size={12} className={sc('pin-icon')} aria-label="Pinned" />}
456-
{showUnpinEffect && <PinOff size={12} className={sc('unpin-icon')} aria-hidden="true" />}
457-
{isShared && <Globe size={12} className={sc('share-icon')} aria-label="Shared" />}
459+
{note.isPinned && (
460+
<Icon icon={Pin} size={12} className={sc('pin-icon')} aria-label="Pinned" />
461+
)}
462+
{showUnpinEffect && (
463+
<Icon icon={PinOff} size={12} className={sc('unpin-icon')} aria-hidden="true" />
464+
)}
465+
{isShared && (
466+
<Icon icon={Globe} size={12} className={sc('share-icon')} aria-label="Shared" />
467+
)}
458468
{note.title || 'Untitled'}
459469
</div>
460470
<div className={sc('note-list-item-meta')}>

0 commit comments

Comments
 (0)