Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f7cb0d9
Clarify edge and elevation guidance
tonyfresher Sep 15, 2026
2a2aed5
Document applet intent APIs
tonyfresher Sep 15, 2026
6d087d0
Support structured context attachments in chat messages
tonyfresher Sep 15, 2026
14c4222
Add reusable attachment chip components
tonyfresher Sep 15, 2026
0a80a31
Remove redundant attachment chip tooltip
tonyfresher Sep 15, 2026
d9629e9
refactor: organize chat files by responsibility
tonyfresher Sep 16, 2026
9c7a9c9
refactor: clarify chat folder ownership
tonyfresher Sep 16, 2026
d6f8993
Update chat formatting paths in harness documentation
tonyfresher Sep 16, 2026
e592b0e
Improve workspace UI and interaction flows
tonyfresher Sep 16, 2026
5a08e05
Preserve staged context across new chat session IDs
tonyfresher Sep 16, 2026
1dfb540
Improve workspace UI and applet tooling
tonyfresher Sep 16, 2026
ab254a3
Validate applet chat attachments before sending
tonyfresher Sep 16, 2026
0bf42dc
Fix attachment formatting
tonyfresher Sep 16, 2026
a103183
Remove failed attachments and show error toasts
tonyfresher Sep 16, 2026
5a88632
Update attachment preparation test expectations
tonyfresher Sep 16, 2026
47361ee
Unify chat attachment preparation and uploads
tonyfresher Sep 16, 2026
895d15d
Clarify view parameter serialization guidance
tonyfresher Sep 21, 2026
06701bf
Clarify applet intent usage
tonyfresher Sep 21, 2026
81e8e9f
Clarify applet intent usage
tonyfresher Sep 21, 2026
72c77cf
Reorganize workspace skill guidance
tonyfresher Sep 21, 2026
418434a
Refine app behavior and UI flows
tonyfresher Sep 21, 2026
b6b6df5
Remove obsolete agent tab from scaffold documentation
tonyfresher Sep 21, 2026
307e0e6
Limit chat attachments and rate-limit staging
tonyfresher Sep 21, 2026
20f200d
Merge branch 'main' into tinkering/chat-context
tonyfresher Sep 21, 2026
55bbcfd
Simplify applet attachment staging and errors
tonyfresher Sep 21, 2026
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
18 changes: 15 additions & 3 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,28 @@ Use `font-sans` for UI, including paths, ids, and numbers. Reserve `font-mono` f

## Layout and Hierarchy

Build hierarchy with type weight, spacing, tonal surfaces, and subtle shadow-defined edges. Use the Tailwind scale and component sizes instead of copying numeric geometry into feature code.

Use subtle shadows instead of borders for standalone contained blocks and outline-style controls. Keep nested elements flat unless they represent a separate contained object. For interactive elements, let the shadow become one step darker or deeper on hover using the existing shadow scale. Use CSS borders only for separators and hard structural boundaries, and keep them subtle with the semantic `border` token. Do not use black or high-contrast 1px outlines around containers, including dashed outlines.
Build hierarchy with type weight, spacing, and tonal surfaces. Use the Tailwind scale and component sizes instead of copying numeric geometry into feature code.

Respect the layout variables in `client/index.css`; do not hardcode equivalent page or chat dimensions. Make layouts work at narrow and wide widths without clipped controls, overlapping text, or large dead areas.

Repeated rows must form stable lanes. Give leading icons, status markers, counters, and trailing actions fixed slots so changing content does not shift alignment. Keep component trees shallow and split components for state, data flow, repeated structure, or meaningful sub-surfaces.

Use container borders sparingly. Avoid cards inside cards and chains of bordered, padded wrappers. A section should usually have at most one framed surface. Inside it, create hierarchy with spacing, typography, tonal surfaces, dividers, or flat rows. Add another frame only when it contains a genuinely separate object, preview, dialog, or tool.

## Edges and Elevation

Start with no outline or shadow. Add an edge when a boundary needs to be visible. For installed components, keep the treatment built into the chosen variant. For new custom surfaces, use these rules:

- **Flat, self-contained surface:** use `ring-1 ring-border`. This is the default for a complete outline around an object that sits in the normal layout. The ring follows the radius without taking space from the content or changing its dimensions.
- **Structural edge:** use `border` with the `border` color token. Use side-specific borders for dividers and shared edges, and a full border for dashed boundaries or an edge that must stay inside the element's box. Adjacent regions should share one dividing line. Keep the built-in borders on form controls.
Comment thread
tonyfresher marked this conversation as resolved.
- **Raised surface:** use `shadow-xs` for a slight lift and `shadow-sm` for a more pronounced lift. Use this only when the surface is meant to sit above its surroundings. An ordinary outlined object defaults to `ring-1 ring-border`.
- **Floating surface:** use `shadow-md` for a local overlay, `shadow-lg` for a higher overlay layer, and `shadow-xl` for a modal layer. Follow the installed overlay primitive's level. Size or importance alone does not justify a stronger shadow.
- **Keyboard focus:** preserve the component's focus treatment. For custom controls, use `focus-visible:ring-3 focus-visible:ring-ring/50`. `ring-border` is a quiet resting outline; `ring-ring` uses the focus color. A resting outline does not replace a visible focus state.

moi's `shadow-*` tokens already include a thin edge as well as blur and offset. Adding a shadow therefore adds elevation even at `shadow-xs`. Do not use shadows just to make an outline visible, or stack a border and resting ring on the same edge. A raised surface normally needs only its shadow; retain combinations already defined by installed primitives.

Use the same edge treatment for elements with the same role. Isolated existing usages, custom shadows, and decorative inset effects are exceptions, not defaults for new UI. Keep token values in the theme and avoid custom shadow formulas in feature code.

## Components and Accessibility

Check `client/components/ui` and existing feature components before writing styled native markup. Use installed primitives and their built-in variants. Component source is the authority for APIs, sizes, and composition.
Expand Down
2 changes: 1 addition & 1 deletion client/app/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Suspense, lazy, useEffect } from 'react'

import { Redirect, Route, Switch, useLocation } from 'wouter'

import { setWorkspaceSwitchHandler } from '@/client/features/chat/chat-connection'
import { setWorkspaceSwitchHandler } from '@/client/features/chat/connection/chat-connection'

import { HomeRoute } from './routes/HomeRoute'
import { WorkspaceRoute } from './routes/WorkspaceRoute'
Expand Down
2 changes: 1 addition & 1 deletion client/app/routes/WorkspaceRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useQueryClient } from '@tanstack/react-query'
import { workspaceKeys } from '@/client/api/workspace-keys'
import { LedLogo } from '@/client/components/shared/LedLogo'
import { SidebarLayout } from '@/client/app/shell/SidebarLayout'
import { useSelectedSession } from '@/client/features/chat/useSelectedSession'
import { useSelectedSession } from '@/client/features/chat/sessions/useSelectedSession'
import { useAppletCacheInvalidation } from '@/client/features/applets/useApplet'
import { Workspace } from '@/client/features/workspace/WorkspaceContext'
import {
Expand Down
2 changes: 1 addition & 1 deletion client/components/TurnParts.render.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
AssistantTurnParts,
TurnParts,
splitCompletedAssistantParts
} from '@/client/features/chat/TurnView'
} from '@/client/features/chat/messages/TurnView'
import type { Part } from '@/lib/types'

const render = (parts: Part[], processing: boolean) =>
Expand Down
4 changes: 2 additions & 2 deletions client/components/ui/toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function Toast({ className, ...props }: ToastPrimitive.Root.Props) {
<ToastPrimitive.Root
data-slot="toast"
className={cn(
'group/toast pointer-events-auto absolute right-0 bottom-0 z-[calc(1000-var(--toast-index))] w-full origin-bottom rounded-2xl border bg-popover text-popover-foreground shadow-lg will-change-transform outline-none select-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50',
'group/toast pointer-events-auto absolute right-0 bottom-0 z-[calc(1000-var(--toast-index))] w-full origin-bottom rounded-xl bg-popover text-popover-foreground shadow-lg will-change-transform outline-none select-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50',
'[--gap:0.75rem] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))]',
'h-(--height) [transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] [transition:transform_500ms_cubic-bezier(0.22,1,0.36,1),opacity_500ms,height_150ms]',
"after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-['']",
Expand All @@ -67,7 +67,7 @@ function ToastContent({ className, ...props }: ToastPrimitive.Content.Props) {
<ToastPrimitive.Content
data-slot="toast-content"
className={cn(
'flex h-full items-center gap-3 overflow-hidden p-4 transition-opacity duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] data-behind:opacity-0 data-expanded:opacity-100',
'flex items-center gap-3 overflow-hidden p-4 transition-opacity duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] data-behind:opacity-0 data-expanded:opacity-100',
className
)}
{...props}
Expand Down
Loading
Loading