From ac393bbe38b1e054f1059454e78faecc15d8aee3 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 13 Oct 2026 21:39:16 +0700 Subject: [PATCH 1/6] feat: polish the side panel and options UI Give the transcript the full height of the panel and keep the composer compact and auto-growing. Replace text glyphs with a small inline SVG icon set, fold the conversation controls into the header, and refresh the theme tokens, cards, markdown, picker and options page for both light and dark themes. Closes #8 Co-Authored-By: Claude Opus 5.5 --- src/credentials/ActionCard.tsx | 7 +- src/credentials/CredentialsForm.tsx | 3 +- src/options/Settings.tsx | 29 +- src/options/options.css | 111 ++++- src/shared/ConnectForm.tsx | 2 +- src/shared/components.css | 95 +++- src/shared/icons.tsx | 67 +++ src/shared/theme.css | 211 +++++--- src/sidepanel/App.tsx | 10 +- src/sidepanel/ChatShell.tsx | 40 +- src/sidepanel/components/AgentPicker.tsx | 23 +- src/sidepanel/components/Composer.tsx | 74 +-- src/sidepanel/components/MessageList.tsx | 17 +- src/sidepanel/components/SessionList.tsx | 9 +- src/sidepanel/sidepanel.css | 581 +++++++++++++++++++---- 15 files changed, 1006 insertions(+), 273 deletions(-) create mode 100644 src/shared/icons.tsx diff --git a/src/credentials/ActionCard.tsx b/src/credentials/ActionCard.tsx index 893ce8d..d0f263c 100644 --- a/src/credentials/ActionCard.tsx +++ b/src/credentials/ActionCard.tsx @@ -6,6 +6,7 @@ import { useState } from 'react'; import { isUiActionOpen, type UiActionCard, type UiActionPayloadByKind } from '@/protocol/ui-action'; import { errorText, useI18n } from '@/shared/i18n'; +import { IconExternal } from '@/shared/icons'; import { CredentialsForm } from './CredentialsForm'; import type { RespondFn } from './respond-types'; @@ -112,7 +113,7 @@ function OAuthCard({ card, respond, deweeUrl }: CardProps & { card: Extract {deweeUrl ? ( - {t('oauth.openDewee')} + {t('oauth.openDewee')} ) : null} {adding ? ( @@ -110,7 +118,7 @@ export function Settings() {

{t('settings.preferences')}

-
+
-

{t('settings.privacy')}

+

+ + {t('settings.privacy')} +

diff --git a/src/options/options.css b/src/options/options.css index 660b5e3..ea6547b 100644 --- a/src/options/options.css +++ b/src/options/options.css @@ -1,54 +1,135 @@ @import '../shared/components.css'; .options { - max-width: 720px; + max-width: 680px; margin: 0 auto; - padding: 24px 16px 48px; + padding: 40px 20px 64px; display: grid; - gap: 24px; + gap: 32px; +} +.options-head { + display: flex; + align-items: center; + gap: 12px; +} +.options-head .brand-mark { + border-radius: 8px; + box-shadow: var(--shadow-sm); } .options h1 { margin: 0; - font-size: 22px; + font-size: 20px; + font-weight: 650; + letter-spacing: -0.015em; } .options h2 { - margin: 0 0 10px; - font-size: 16px; + margin: 0 0 12px; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--ink-soft); +} +.options section { + display: grid; } .section-head { display: flex; justify-content: space-between; align-items: center; + margin-bottom: 12px; +} +.section-head h2 { + margin: 0; } .panel { - padding: 14px; + padding: 16px; margin-bottom: 12px; border: 1px solid var(--hairline); border-radius: var(--radius); background: var(--paper-2); + box-shadow: var(--shadow-sm); } .profile-list { list-style: none; margin: 0; padding: 0; - display: grid; - gap: 8px; -} -.profile-row { - display: grid; - gap: 10px; - padding: 12px; border: 1px solid var(--hairline); border-radius: var(--radius); background: var(--paper-2); + box-shadow: var(--shadow-sm); + overflow: hidden; +} +.profile-list:empty { + display: none; +} +.profile-row { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + align-items: center; + gap: 12px 16px; + padding: 14px 16px; +} +.profile-row + .profile-row { + border-top: 1px solid var(--hairline); +} +.profile-row > .connect-form { + grid-column: 1 / -1; + padding-top: 12px; + border-top: 1px dashed var(--hairline); +} +.profile-main { + display: grid; + gap: 2px; + min-width: 0; +} +.profile-title { + display: flex; + align-items: center; + gap: 8px; + min-width: 0; +} +.profile-title .badge { + margin-left: 0; +} +.conn-dot { + width: 7px; + height: 7px; + flex: none; + border-radius: 50%; + background: var(--hairline-strong); +} +.conn-dot.on { + background: var(--verdigris); + box-shadow: 0 0 0 3px var(--verdigris-soft); } .profile-actions { display: flex; flex-wrap: wrap; + justify-content: flex-end; gap: 6px; } .prefs { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 12px; + gap: 14px; +} +.privacy { + display: flex; + align-items: flex-start; + gap: 8px; + margin: 4px 2px 0; +} +.privacy svg { + flex: none; + margin-top: 3px; +} + +@media (max-width: 520px) { + .profile-row { + grid-template-columns: minmax(0, 1fr); + } + .profile-actions { + justify-content: flex-start; + } } diff --git a/src/shared/ConnectForm.tsx b/src/shared/ConnectForm.tsx index cd046e6..87b793b 100644 --- a/src/shared/ConnectForm.tsx +++ b/src/shared/ConnectForm.tsx @@ -74,7 +74,7 @@ export function ConnectForm({ reconnect, onDone }: { reconnect?: Profile; onDone ))} )} -

{mode === 'cloud' ? t('connect.cloudHint') : t('connect.selfHostedHint')}

+

{mode === 'cloud' ? t('connect.cloudHint') : t('connect.selfHostedHint')}

{reconnect ? null : (