Skip to content

Commit bd8cfc3

Browse files
feat: UI/UX improvements — dark mode, help dialog, settings, cards
- Upgrade dark mode palette to GitHub Dark (better layer separation) - Remove duplicate Export/Import from HomeScreen footer - Simplify ARIA modes: remove 'blacklist' as approval mode, keep block patterns as always-on safety guard - Redesign WelcomeScreen with timeline steps and hero glow - Redesign HomeScreen HostCard with accent bar, port, tags, hover CTA - Improve SettingsDialog: wider (max-w-3xl), better section headers, fix leftover blacklist option - Replace ShortcutsDialog + Welcome modal with unified HelpDialog (Getting Started / ARIA Guide / Shortcuts tabs) - Add help dropdown in TitleBar with Getting Started and Keyboard Shortcuts options
1 parent 2d19ef9 commit bd8cfc3

9 files changed

Lines changed: 673 additions & 236 deletions

File tree

src/renderer/src/App.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { WelcomeScreen } from './components/WelcomeScreen'
99
import { ConnectionDialog } from './components/dialogs/ConnectionDialog'
1010
import { QuickConnect } from './components/dialogs/QuickConnect'
1111
import { SettingsDialog } from './components/dialogs/SettingsDialog'
12-
import { ShortcutsDialog } from './components/dialogs/ShortcutsDialog'
12+
import { HelpDialog } from './components/dialogs/HelpDialog'
1313
import { TitleBar } from './components/TitleBar'
1414
import { MasterPasswordLock } from './components/MasterPasswordLock'
1515
import { cn } from './lib/utils'
@@ -24,7 +24,8 @@ export default function App(): JSX.Element {
2424
} = useAppStore()
2525
const [masterLocked, setMasterLocked] = useState<boolean | null>(null)
2626
const [locked, setLocked] = useState(false)
27-
const [shortcutsOpen, setShortcutsOpen] = useState(false)
27+
const [helpOpen, setHelpOpen] = useState(false)
28+
const [helpTab, setHelpTab] = useState<'start' | 'aria' | 'shortcuts'>('start')
2829
const lastActivityRef = useRef(Date.now())
2930
const autoLockMinsRef = useRef(0)
3031
const [updateBanner, setUpdateBanner] = useState<{
@@ -93,11 +94,12 @@ export default function App(): JSX.Element {
9394
(e: KeyboardEvent) => {
9495
const mod = e.metaKey || e.ctrlKey
9596

96-
// ? — Keyboard shortcuts (only when not typing in an input)
97+
// ? — Help dialog (only when not typing in an input)
9798
if (e.key === '?' && !mod) {
9899
const tag = (e.target as HTMLElement).tagName
99100
if (tag !== 'INPUT' && tag !== 'TEXTAREA') {
100-
setShortcutsOpen(true)
101+
setHelpTab('shortcuts')
102+
setHelpOpen(true)
101103
}
102104
return
103105
}
@@ -192,7 +194,10 @@ export default function App(): JSX.Element {
192194
return (
193195
<div className="flex flex-col h-screen w-screen bg-background text-foreground select-none overflow-hidden">
194196
<Toaster position="bottom-right" theme="dark" richColors closeButton />
195-
<TitleBar onShortcuts={() => setShortcutsOpen(true)} />
197+
<TitleBar
198+
onShortcuts={() => { setHelpTab('shortcuts'); setHelpOpen(true) }}
199+
onWelcome={() => { setHelpTab('start'); setHelpOpen(true) }}
200+
/>
196201

197202
<div className="flex flex-1 overflow-hidden min-h-0">
198203
<Sidebar />
@@ -210,7 +215,11 @@ export default function App(): JSX.Element {
210215
<ConnectionDialog />
211216
<QuickConnect />
212217
<SettingsDialog />
213-
<ShortcutsDialog open={shortcutsOpen} onClose={() => setShortcutsOpen(false)} />
218+
<HelpDialog
219+
open={helpOpen}
220+
initialTab={helpTab}
221+
onClose={() => setHelpOpen(false)}
222+
/>
214223

215224
{/* Update notification banner */}
216225
{updateBanner && (

src/renderer/src/assets/globals.css

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,46 @@
77

88
@layer base {
99
:root {
10-
/* ── 80% neutral dark — easy on the eyes ──────── */
11-
--background: 240 10% 7%; /* #101014near-black, no purple fatigue */
12-
--foreground: 240 10% 93%; /* #ECEDF2soft white */
10+
/* ── GitHub-Dark inspired — proven readability for devs ─── */
11+
--background: 220 20% 9%; /* #0D1117deep navy-black */
12+
--foreground: 210 18% 92%; /* #E6EDF3warm off-white */
1313

14-
--card: 240 10% 11%; /* #18181Eelevated surface */
15-
--card-foreground: 240 10% 93%;
14+
--card: 220 18% 14%; /* #161B22clearly lifted surface */
15+
--card-foreground: 210 18% 92%;
1616

17-
--popover: 240 10% 11%;
18-
--popover-foreground: 240 10% 93%;
17+
--popover: 220 18% 14%;
18+
--popover-foreground: 210 18% 92%;
1919

20-
/* ── 15% purpleaccent only ──────────────────── */
20+
/* ── Purple accentkept for brand ────────────── */
2121
--primary: 258 90% 66%; /* #8B5CF6 */
2222
--primary-foreground: 0 0% 100%;
2323

24-
--secondary: 240 8% 15%; /* #222228 */
25-
--secondary-foreground: 240 8% 85%;
24+
--secondary: 220 16% 18%; /* #1C2130 — visible step above card */
25+
--secondary-foreground: 210 14% 82%;
2626

27-
--muted: 240 8% 15%;
28-
--muted-foreground: 240 8% 56%; /* #8B8B98readable neutral */
27+
--muted: 220 16% 18%; /* #1C2130 */
28+
--muted-foreground: 215 14% 58%; /* #8B949Ecomfortable gray */
2929

30-
--accent: 240 8% 18%; /* #28282F */
31-
--accent-foreground: 240 10% 93%;
30+
--accent: 220 16% 22%; /* #222C3A — hover/active state */
31+
--accent-foreground: 210 18% 92%;
3232

33-
--destructive: 0 62% 48%;
33+
--destructive: 0 62% 50%;
3434
--destructive-foreground: 0 0% 100%;
3535

36-
--border: 240 8% 20%; /* #2E2E36 */
37-
--input: 240 8% 20%;
36+
--border: 220 14% 26%; /* #30363D — visible, not harsh */
37+
--input: 220 14% 26%;
3838
--ring: 258 90% 66%;
3939

4040
--radius: 0.5rem;
4141

42-
/* ── Sidebar — slightly deeper than background ─── */
43-
--sidebar-background: 240 10% 5%; /* #0C0C0F */
44-
--sidebar-foreground: 240 8% 80%; /* #C8C8D0clear, comfortable */
42+
/* ── Sidebar — clearly distinct from main area ─── */
43+
--sidebar-background: 220 22% 7%; /* #0A0D14 — deeper than bg */
44+
--sidebar-foreground: 210 14% 75%; /* #B4BCC8readable */
4545
--sidebar-primary: 258 90% 66%;
4646
--sidebar-primary-foreground: 0 0% 100%;
47-
--sidebar-accent: 240 8% 13%; /* #1E1E24 */
48-
--sidebar-accent-foreground: 240 10% 93%;
49-
--sidebar-border: 240 8% 16%; /* #242429 */
47+
--sidebar-accent: 220 18% 14%; /* #161B22 — matches card */
48+
--sidebar-accent-foreground: 210 18% 92%;
49+
--sidebar-border: 220 16% 20%; /* #222B38 */
5050
--sidebar-ring: 258 90% 66%;
5151
}
5252
}
@@ -75,25 +75,25 @@
7575

7676
/* Light mode — applied via JS when theme = light */
7777
html.light {
78-
--background: 0 0% 98%;
79-
--foreground: 222 20% 10%;
80-
--card: 0 0% 100%;
81-
--card-foreground: 222 20% 10%;
78+
--background: 0 0% 97%; /* #F7F7F7 — warm near-white */
79+
--foreground: 222 25% 12%; /* #141822 — deep navy-black text */
80+
--card: 0 0% 100%; /* pure white cards */
81+
--card-foreground: 222 25% 12%;
8282
--popover: 0 0% 100%;
83-
--popover-foreground: 222 20% 10%;
84-
--secondary: 220 14% 93%;
85-
--secondary-foreground: 222 20% 20%;
86-
--muted: 220 14% 93%;
87-
--muted-foreground: 215 16% 40%;
88-
--accent: 220 14% 90%;
89-
--accent-foreground: 222 20% 10%;
90-
--border: 220 14% 85%;
91-
--input: 220 14% 85%;
92-
--sidebar-background: 220 14% 95%;
93-
--sidebar-foreground: 222 20% 25%;
94-
--sidebar-accent: 220 14% 88%;
95-
--sidebar-accent-foreground: 222 20% 10%;
96-
--sidebar-border: 220 14% 82%;
83+
--popover-foreground: 222 25% 12%;
84+
--secondary: 220 16% 92%; /* #E5E8F0 */
85+
--secondary-foreground: 222 22% 22%;
86+
--muted: 220 16% 92%;
87+
--muted-foreground: 220 14% 38%; /* #4D5568 — readable medium gray */
88+
--accent: 220 18% 88%; /* #DBE1EF — visible hover */
89+
--accent-foreground: 222 25% 12%;
90+
--border: 220 16% 82%; /* #C8CEDD — clear borders */
91+
--input: 220 16% 82%;
92+
--sidebar-background: 220 20% 94%; /* #EDF0F7 */
93+
--sidebar-foreground: 222 22% 22%; /* #2A3347 */
94+
--sidebar-accent: 220 18% 88%;
95+
--sidebar-accent-foreground: 222 25% 12%;
96+
--sidebar-border: 220 16% 78%; /* #C0C8DA */
9797
}
9898

9999
/* ── Base fonts ────────────────────────────────────── */

src/renderer/src/components/TitleBar.tsx

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
1-
import { Settings, Zap, Network, HelpCircle } from 'lucide-react'
1+
import { Settings, Zap, Network, HelpCircle, BookOpen, Keyboard } from 'lucide-react'
2+
import { useState, useRef, useEffect } from 'react'
23
import { useAppStore } from '../store'
34

45
interface Props {
56
onShortcuts: () => void
7+
onWelcome: () => void
68
}
79

8-
export function TitleBar({ onShortcuts }: Props): JSX.Element {
10+
export function TitleBar({ onShortcuts, onWelcome }: Props): JSX.Element {
911
const { setSettingsOpen, setQuickConnectOpen, sessions } = useAppStore()
1012
const isMac = navigator.userAgent.includes('Mac')
1113
const activeSessions = sessions.filter(s => s.status === 'connected').length
14+
const [helpOpen, setHelpOpen] = useState(false)
15+
const helpRef = useRef<HTMLDivElement>(null)
16+
17+
useEffect(() => {
18+
if (!helpOpen) return
19+
const handler = (e: MouseEvent) => {
20+
if (helpRef.current && !helpRef.current.contains(e.target as Node)) setHelpOpen(false)
21+
}
22+
document.addEventListener('mousedown', handler)
23+
return () => document.removeEventListener('mousedown', handler)
24+
}, [helpOpen])
1225

1326
return (
1427
<div
@@ -42,13 +55,42 @@ export function TitleBar({ onShortcuts }: Props): JSX.Element {
4255
<span>{isMac ? '⌘K' : 'Ctrl+K'}</span>
4356
</button>
4457

45-
<button
46-
onClick={onShortcuts}
47-
className="p-1.5 rounded-md hover:bg-accent text-muted-foreground hover:text-foreground transition-colors"
48-
title="Keyboard Shortcuts (?)"
49-
>
50-
<HelpCircle className="w-4 h-4" />
51-
</button>
58+
{/* Help dropdown */}
59+
<div ref={helpRef} className="relative">
60+
<button
61+
onClick={() => setHelpOpen(v => !v)}
62+
className={`p-1.5 rounded-md transition-colors ${helpOpen ? 'bg-accent text-foreground' : 'hover:bg-accent text-muted-foreground hover:text-foreground'}`}
63+
title="Help"
64+
>
65+
<HelpCircle className="w-4 h-4" />
66+
</button>
67+
68+
{helpOpen && (
69+
<div className="absolute right-0 top-full mt-1.5 w-52 bg-popover border border-border rounded-xl shadow-xl z-50 overflow-hidden py-1">
70+
<button
71+
onClick={() => { onWelcome(); setHelpOpen(false) }}
72+
className="w-full flex items-center gap-3 px-4 py-2.5 text-sm text-foreground hover:bg-accent transition-colors text-left cursor-pointer"
73+
>
74+
<BookOpen className="w-4 h-4 text-primary shrink-0" />
75+
<div>
76+
<p className="font-medium">Getting Started</p>
77+
<p className="text-[11px] text-muted-foreground">Welcome &amp; onboarding</p>
78+
</div>
79+
</button>
80+
<div className="h-px bg-border mx-2 my-1" />
81+
<button
82+
onClick={() => { onShortcuts(); setHelpOpen(false) }}
83+
className="w-full flex items-center gap-3 px-4 py-2.5 text-sm text-foreground hover:bg-accent transition-colors text-left cursor-pointer"
84+
>
85+
<Keyboard className="w-4 h-4 text-muted-foreground shrink-0" />
86+
<div>
87+
<p className="font-medium">Keyboard Shortcuts</p>
88+
<p className="text-[11px] text-muted-foreground">Press ? anywhere</p>
89+
</div>
90+
</button>
91+
</div>
92+
)}
93+
</div>
5294

5395
<button
5496
onClick={() => setSettingsOpen(true)}

0 commit comments

Comments
 (0)