Merge desktop memory theme polish into main

The detached worktree contains the verified desktop memory activity styling fix. Merge it into local main while preserving the existing main-line desktop changes and keeping the worktree commit as a separate decision record.

Constraint: Local main already diverged from the detached worktree and is ahead of origin
Rejected: Cherry-pick the worktree commit | would lose the explicit worktree merge topology the user requested
Confidence: high
Scope-risk: narrow
Directive: Preserve main-line desktop changes when resolving future memory-theme edits
Tested: cd desktop && bun run test src/components/chat/MessageList.test.tsx --run
Tested: cd desktop && bun run test src/components/layout/Sidebar.test.tsx --run
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
This commit is contained in:
程序员阿江(Relakkes) 2026-05-14 23:13:38 +08:00
commit 36b86343d5
5 changed files with 42 additions and 5 deletions

View File

@ -366,6 +366,9 @@ describe('MessageList nested tool calls', () => {
expect(screen.getByText('Saved 1 memory item(s)')).toBeTruthy()
expect(screen.getByText('preferences.md')).toBeTruthy()
expect(screen.getByText('Tool details')).toBeTruthy()
const memoryCardClassName = screen.getByTestId('memory-tool-activity-card').className
expect(memoryCardClassName).toContain('border-[var(--color-memory-border)]')
expect(memoryCardClassName).toContain('bg-[var(--color-memory-surface)]')
})
it('promotes memory file reads into collapsible memory references', () => {

View File

@ -195,7 +195,10 @@ function MemoryToolActivityGroup({
return (
<div className="mb-2">
<div className="overflow-hidden rounded-lg border border-[color-mix(in_srgb,var(--color-brand)_22%,var(--color-border))] bg-[color-mix(in_srgb,var(--color-brand)_6%,var(--color-surface-container-lowest))]">
<div
data-testid="memory-tool-activity-card"
className="overflow-hidden rounded-lg border border-[var(--color-memory-border)] bg-[var(--color-memory-surface)]"
>
<button
type="button"
onClick={() => setExpanded((value) => !value)}
@ -206,12 +209,12 @@ function MemoryToolActivityGroup({
) : (
<ChevronRight size={15} className="shrink-0 text-[var(--color-text-tertiary)]" aria-hidden="true" />
)}
<BookMarked size={15} className="shrink-0 text-[var(--color-brand)]" aria-hidden="true" />
<BookMarked size={15} className="shrink-0 text-[var(--color-memory-accent)]" aria-hidden="true" />
<span className="min-w-0 flex-1 truncate text-[13px] font-medium text-[var(--color-text-primary)]">
{t(titleKey, { count: activity.files.length })}
</span>
{isStreaming ? (
<span className="h-1.5 w-1.5 rounded-full bg-[var(--color-brand)] animate-pulse-dot" />
<span className="h-1.5 w-1.5 rounded-full bg-[var(--color-memory-accent)] animate-pulse-dot" />
) : null}
</button>
@ -226,7 +229,7 @@ function MemoryToolActivityGroup({
onClick={() => openMemorySettings(file.path)}
className="group flex w-full items-start gap-2 rounded-md px-2 py-1.5 text-left transition-colors hover:bg-[var(--color-surface-hover)] focus:outline-none focus-visible:shadow-[var(--shadow-focus-ring)]"
>
<span className="mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-sm border border-[var(--color-border)] bg-[var(--color-surface)] text-[var(--color-text-tertiary)] group-hover:text-[var(--color-brand)]">
<span className="mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-sm border border-[var(--color-memory-border)] bg-[var(--color-memory-icon-bg)] text-[var(--color-text-tertiary)] group-hover:text-[var(--color-memory-accent)]">
<Settings size={12} aria-hidden="true" />
</span>
<span className="min-w-0 flex-1">

View File

@ -348,6 +348,13 @@ describe('Sidebar', () => {
expect(screen.getByTestId('sidebar-session-list-section')).toHaveClass('flex', 'flex-1', 'min-h-0', 'flex-col')
})
it('keeps the settings dock opaque above the scrolling session list', () => {
render(<Sidebar />)
expect(screen.getByTestId('sidebar-settings-dock')).toHaveClass('sidebar-settings-dock')
expect(screen.getByTestId('sidebar-settings-dock')).toHaveClass('absolute', 'bottom-0')
})
it('keeps mobile navigation focused on chat sessions', async () => {
const onRequestClose = vi.fn()
createSession.mockResolvedValue('session-mobile-new')

View File

@ -593,7 +593,10 @@ export function Sidebar({ isMobile = false, onRequestClose }: SidebarProps) {
)}
{!isMobile && (
<div className={`absolute bottom-0 left-0 right-0 border-t border-[var(--color-border)] p-3 ${expanded ? '' : 'flex justify-center'}`}>
<div
data-testid="sidebar-settings-dock"
className={`sidebar-settings-dock absolute bottom-0 left-0 right-0 border-t border-[var(--color-border)] p-3 ${expanded ? '' : 'flex justify-center'}`}
>
<NavItem
active={activeTabId === SETTINGS_TAB_ID}
collapsed={!expanded}

View File

@ -177,6 +177,10 @@
--color-surface-sidebar: var(--color-surface-container-low);
--color-surface-hover: var(--color-surface-container-high);
--color-surface-selected: var(--color-surface-container);
--color-memory-accent: #3B7068;
--color-memory-surface: color-mix(in srgb, var(--color-memory-accent) 7%, var(--color-surface-container-lowest));
--color-memory-border: color-mix(in srgb, var(--color-memory-accent) 26%, var(--color-border));
--color-memory-icon-bg: color-mix(in srgb, var(--color-memory-accent) 10%, var(--color-surface-container-lowest));
--color-model-option-selected-bg: var(--color-primary-fixed);
--color-model-option-selected-border: rgba(143, 72, 47, 0.2);
--color-activity-heat-0: var(--color-surface-container);
@ -374,6 +378,10 @@
--color-surface-sidebar: #F1F4F7;
--color-surface-hover: #F2F5F8;
--color-surface-selected: #E9EEF3;
--color-memory-accent: #0F766E;
--color-memory-surface: color-mix(in srgb, var(--color-memory-accent) 5%, #FFFFFF);
--color-memory-border: color-mix(in srgb, var(--color-memory-accent) 24%, var(--color-border));
--color-memory-icon-bg: color-mix(in srgb, var(--color-memory-accent) 8%, #FFFFFF);
--color-model-option-selected-bg: #FFF0EA;
--color-model-option-selected-border: rgba(143, 72, 47, 0.2);
--color-activity-heat-0: #EEF2F6;
@ -548,6 +556,10 @@
--color-surface-sidebar: #171615;
--color-surface-hover: var(--color-surface-container-highest);
--color-surface-selected: var(--color-surface-container);
--color-memory-accent: #7DD3C7;
--color-memory-surface: color-mix(in srgb, var(--color-memory-accent) 9%, var(--color-surface-container-lowest));
--color-memory-border: color-mix(in srgb, var(--color-memory-accent) 26%, var(--color-border));
--color-memory-icon-bg: color-mix(in srgb, var(--color-memory-accent) 12%, var(--color-surface-container-lowest));
--color-model-option-selected-bg: rgba(255, 181, 159, 0.13);
--color-model-option-selected-border: rgba(255, 181, 159, 0.34);
--color-activity-heat-0: #242322;
@ -967,10 +979,19 @@ button, input, textarea, select, a, [role="button"] {
::-webkit-scrollbar-thumb:hover { opacity: 0.6; }
.sidebar-scroll-area {
padding-bottom: 72px;
scrollbar-width: thin;
scrollbar-color: var(--color-outline-a72) transparent;
}
.sidebar-settings-dock {
z-index: 30;
background-color: var(--color-surface-sidebar);
background-image: var(--sidebar-panel-bg-image);
background-repeat: no-repeat;
background-position: left bottom;
}
.sidebar-scroll-area::-webkit-scrollbar {
width: 4px;
}