Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 32 additions & 30 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,34 +52,34 @@ conversation with the agent. Every pixel must earn its place.

### Typography

| Role | Size | Weight | Tracking | Font Stack |
|------|------|--------|----------|------------|
| Thread title (sidebar) | `text-xs` (0.75rem) | `font-normal` | default | Inter, system-ui, sans-serif |
| Thread subtitle / metadata | `text-[10px]` | `font-normal` | default | Inter, system-ui, sans-serif |
| Badge text | `text-[10px]` | `font-medium` | default | Inter, system-ui, sans-serif |
| Button text | `text-sm` (0.875rem) | `font-medium` | default | Inter, system-ui, sans-serif |
| Heading / dialog title | `text-lg` (1.125rem) | `font-semibold` | `-0.01em` | Inter, system-ui, sans-serif |
| Code / terminal | `text-sm` | `font-normal` | default | SF Mono, Consolas, monospace |
| Project name | `text-xs` | `font-semibold` | default | Inter, system-ui, sans-serif |
| Role | Size | Weight | Tracking | Font Stack |
| -------------------------- | -------------------- | --------------- | --------- | ---------------------------- |
| Thread title (sidebar) | `text-xs` (0.75rem) | `font-normal` | default | Inter, system-ui, sans-serif |
| Thread subtitle / metadata | `text-[10px]` | `font-normal` | default | Inter, system-ui, sans-serif |
| Badge text | `text-[10px]` | `font-medium` | default | Inter, system-ui, sans-serif |
| Button text | `text-sm` (0.875rem) | `font-medium` | default | Inter, system-ui, sans-serif |
| Heading / dialog title | `text-lg` (1.125rem) | `font-semibold` | `-0.01em` | Inter, system-ui, sans-serif |
| Code / terminal | `text-sm` | `font-normal` | default | SF Mono, Consolas, monospace |
| Project name | `text-xs` | `font-semibold` | default | Inter, system-ui, sans-serif |

### Color Semantics

Colors are referenced through CSS custom properties, never hardcoded hex values.

| Token | Usage |
|-------|-------|
| `text-foreground` | Primary text |
| `text-muted-foreground` | Secondary/deemphasized text |
| Token | Usage |
| -------------------------- | ------------------------------------------------- |
| `text-foreground` | Primary text |
| `text-muted-foreground` | Secondary/deemphasized text |
| `text-muted-foreground/50` | Tertiary/metadata text (branch names, timestamps) |
| `bg-background` | Page background |
| `bg-accent` | Hover state, active row highlight |
| `bg-accent/60` | Active sidebar item |
| `bg-accent/40` | Selected sidebar item |
| `text-emerald-600` | Additions / success (green) |
| `text-rose-500` | Deletions / error (red) |
| `text-warning` | Warning states, behind-upstream |
| `text-destructive` | Destructive actions (delete) |
| `border-border/60` | Subtle badge borders |
| `bg-background` | Page background |
| `bg-accent` | Hover state, active row highlight |
| `bg-accent/60` | Active sidebar item |
| `bg-accent/40` | Selected sidebar item |
| `text-emerald-600` | Additions / success (green) |
| `text-rose-500` | Deletions / error (red) |
| `text-warning` | Warning states, behind-upstream |
| `text-destructive` | Destructive actions (delete) |
| `border-border/60` | Subtle badge borders |

### Spacing Rules

Expand All @@ -95,14 +95,14 @@ Colors are referenced through CSS custom properties, never hardcoded hex values.

Six premium themes, each with light and dark variants:

| Theme | Vibe |
|-------|------|
| **Iridescent Void** | Futuristic, expensive, slightly alien |
| **Solar Witch** | Magical, cozy, ritualistic |
| **Carbon** | Stark, modern, performance-focused |
| **Vapor** | Refined, fluid, purposeful |
| **Cotton Candy** | Sweet, dreamy, pink and blue |
| **Cathedral Circuit** | Sacred machine, techno-gothic |
| Theme | Vibe |
| --------------------- | ------------------------------------- |
| **Iridescent Void** | Futuristic, expensive, slightly alien |
| **Solar Witch** | Magical, cozy, ritualistic |
| **Carbon** | Stark, modern, performance-focused |
| **Vapor** | Refined, fluid, purposeful |
| **Cotton Candy** | Sweet, dreamy, pink and blue |
| **Cathedral Circuit** | Sacred machine, techno-gothic |

All themes define the same set of CSS custom properties. Components must use semantic
tokens (`bg-accent`, `text-muted-foreground`) — never theme-specific values.
Expand Down Expand Up @@ -142,6 +142,7 @@ const buttonVariants = cva("base classes", {
### Focus States

All interactive elements use the same focus ring:

```
focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]
```
Expand Down Expand Up @@ -249,6 +250,7 @@ a single flow:
```

Quick action resolves automatically based on git state:

- Has changes + no PR → "Commit, push & PR"
- Has changes + existing PR → "Commit & push"
- No changes + ahead → "Push & create PR"
Expand Down
28 changes: 26 additions & 2 deletions apps/web/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import {
ChevronsDownUpIcon,
ChevronsUpDownIcon,
CircleDotIcon,
CloudUploadIcon,
ExternalLinkIcon,
FolderIcon,
GitBranchIcon,
Expand All @@ -46,6 +45,7 @@ import {
SettingsIcon,
TriangleAlertIcon,
UserIcon,
XIcon,
XCircleIcon,
} from "lucide-react";
import { type MouseEvent, memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
Expand Down Expand Up @@ -319,6 +319,7 @@ interface MemoizedThreadRowProps {
position: { x: number; y: number },
) => Promise<void>;
handleMultiSelectContextMenu: (position: { x: number; y: number }) => Promise<void>;
closeDraftThread: (threadId: ThreadIdType) => void;
}

const MemoizedThreadRow = memo(
Expand All @@ -343,6 +344,7 @@ const MemoizedThreadRow = memo(
handleThreadClick,
handleThreadContextMenu,
handleMultiSelectContextMenu,
closeDraftThread,
}: MemoizedThreadRowProps) {
const threadStatus = resolveThreadStatusPill({
thread,
Expand Down Expand Up @@ -441,7 +443,21 @@ const MemoizedThreadRow = memo(
onCancel={cancelEditing}
/>
</div>
<CloudUploadIcon className="size-3.5 shrink-0 text-muted-foreground/30" />
{isDraft ? (
<button
type="button"
aria-label="Close draft thread"
title="Close draft thread"
className="inline-flex size-5 shrink-0 items-center justify-center rounded-sm text-muted-foreground/40 transition-colors hover:bg-accent hover:text-foreground"
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
closeDraftThread(thread.id);
}}
>
<XIcon className="size-3" />
</button>
) : null}
</SidebarMenuSubButton>
</SidebarMenuSubItem>
);
Expand Down Expand Up @@ -944,6 +960,13 @@ export default function Sidebar() {
],
);

const closeDraftThread = useCallback(
(threadId: ThreadId) => {
void deleteThread(threadId);
},
[deleteThread],
);

const { copyToClipboard: copyThreadIdToClipboard } = useCopyToClipboard<{
threadId: ThreadId;
}>({
Expand Down Expand Up @@ -1453,6 +1476,7 @@ export default function Sidebar() {
handleThreadClick={handleThreadClick}
handleThreadContextMenu={handleThreadContextMenu}
handleMultiSelectContextMenu={handleMultiSelectContextMenu}
closeDraftThread={closeDraftThread}
/>
))}

Expand Down
Loading