From f72b2cd4e40a176bc0e8e0d052955960363fd4a1 Mon Sep 17 00:00:00 2001 From: Rasmus Viloma Date: Tue, 15 Sep 2026 00:24:11 +0300 Subject: [PATCH 01/20] docs(primitives): rewrite the remaining seven pages to the house format --- content/docs/handbook/accessibility.mdx | 105 ++++++++++-- content/docs/primitives/attachments.mdx | 53 +++--- .../primitives/attachments/demos/basic.tsx | 40 +---- .../primitives/attachments/demos/dropzone.tsx | 147 +++++++++++++++++ content/docs/primitives/chip.mdx | 42 ++--- content/docs/primitives/chip/demos/basic.tsx | 21 +-- .../docs/primitives/chip/demos/preview.tsx | 97 +++++++++++ content/docs/primitives/composer.mdx | 116 +++---------- .../composer/demos/ask-user-flow.tsx | 22 +-- .../primitives/composer/demos/attachments.tsx | 58 +------ .../docs/primitives/composer/demos/basic.tsx | 21 +-- .../primitives/composer/demos/commands.tsx | 21 +-- .../primitives/composer/demos/controlled.tsx | 24 +-- .../primitives/composer/demos/popover.tsx | 21 +-- .../docs/primitives/composer/demos/store.tsx | 21 +-- content/docs/primitives/message.mdx | 52 +++--- .../docs/primitives/message/demos/basic.tsx | 39 +---- .../docs/primitives/message/demos/chips.tsx | 72 +++++++++ .../primitives/message/demos/selection.tsx | 64 ++++++++ content/docs/primitives/nav.mdx | 2 +- content/docs/primitives/nav/demos/basic.tsx | 91 ++--------- .../docs/primitives/nav/demos/collapse.tsx | 19 +-- .../docs/primitives/nav/demos/external.tsx | 20 +-- content/docs/primitives/nav/demos/guides.tsx | 49 +----- content/docs/primitives/reasoning.mdx | 54 ++++--- .../docs/primitives/reasoning/demos/basic.tsx | 40 +---- .../primitives/reasoning/demos/streaming.tsx | 114 +++++++++++++ content/docs/primitives/shell.mdx | 2 +- content/docs/primitives/shell/demos/basic.tsx | 94 ++--------- content/docs/primitives/steps.mdx | 82 ++++------ content/docs/primitives/steps/demos/basic.tsx | 52 +----- .../docs/primitives/steps/demos/status.tsx | 113 +++++++++++++ content/docs/primitives/tabs.mdx | 1 + .../docs/primitives/tabs/demos/anchored.tsx | 111 +++---------- content/docs/primitives/tabs/demos/basic.tsx | 53 +----- .../docs/primitives/tabs/demos/closing.tsx | 103 ++---------- .../docs/primitives/tabs/demos/external.tsx | 105 ++---------- content/docs/primitives/thread.mdx | 125 +++++++------- .../primitives/thread/demos/autoscroll.tsx | 152 ++++++++++++++++++ .../docs/primitives/thread/demos/basic.tsx | 41 +---- content/docs/primitives/thread/demos/jump.tsx | 86 ++++++++++ packages/chat/src/attachments/attachments.tsx | 31 ++++ packages/chat/src/chip/chip.tsx | 22 ++- packages/chat/src/message/message.tsx | 15 ++ packages/chat/src/reasoning/reasoning.tsx | 18 +++ packages/chat/src/steps/steps.tsx | 37 +++++ 46 files changed, 1426 insertions(+), 1242 deletions(-) create mode 100644 content/docs/primitives/attachments/demos/dropzone.tsx create mode 100644 content/docs/primitives/chip/demos/preview.tsx create mode 100644 content/docs/primitives/message/demos/chips.tsx create mode 100644 content/docs/primitives/message/demos/selection.tsx create mode 100644 content/docs/primitives/reasoning/demos/streaming.tsx create mode 100644 content/docs/primitives/steps/demos/status.tsx create mode 100644 content/docs/primitives/thread/demos/autoscroll.tsx create mode 100644 content/docs/primitives/thread/demos/jump.tsx diff --git a/content/docs/handbook/accessibility.mdx b/content/docs/handbook/accessibility.mdx index a818779..802f858 100644 --- a/content/docs/handbook/accessibility.mdx +++ b/content/docs/handbook/accessibility.mdx @@ -28,6 +28,23 @@ active row carries the tab stop, which keeps a row rendered as a real anchor reachable without JavaScript. A field inside the tree keeps its own arrow keys, or its caret could never move. +A scroll surface has to be reachable before it can be scrolled. The thread's +viewport is a focusable `role="region"` named "Messages" by default, so a +keyboard user can Tab to it and use the usual keys. Only the upward keys — +`ArrowUp`, `PageUp` and `Home` — are intercepted, to release auto-follow; +scrolling down never does, because releasing it at the bottom would leave the +view unfollowed while pinned there. + +Announce additions, not mutations. The thread's content column is a `role="log"` +with `aria-relevant="additions"`, so a turn announces when its row is added and +tokens streaming into an existing row deliberately do not re-announce. +Token-by-token narration is noise. If an end-of-response announcement is wanted, +add your own `role="status"` region that flips on completion. + +Motion preferences are honoured for programmatic scrolls. Anything the thread +requests as smooth, including auto-follow, downgrades to instant when the +operating system asks for reduced motion. + Command lists and ask-user options move a highlight rather than DOM focus, so the caret stays in the editor while you navigate. Arrowing past the end of a list keeps focus in place; arrowing up past the first ask-user option returns to the @@ -45,14 +62,42 @@ removes the focus indicator rather than softening a hover effect. ## Roles and relationships -The composer's editor is wired to its command list as a combobox: `aria-expanded`, -`aria-controls`, and `aria-activedescendant` reference a `listbox`, and the active -row carries `aria-selected`. Ask-user renders a labelled `radiogroup`, or -checkboxes with `aria-checked` for multi-select questions. Disabled options are -announced but skipped by highlight and selection. - -`Steps` marks the active item with `aria-current="step"`. `Reasoning.Root` carries -`aria-busy` while streaming. +The composer's editor is wired to its command list as a combobox: +`aria-autocomplete="list"` and `aria-haspopup="listbox"`, plus `aria-controls` +and `aria-activedescendant` while a popup is open. The popup is a `listbox` +named "Suggestions" whose rows carry stable ids and `aria-selected`; selection +stays in the editor, so rows are never tab stops. Grouped lists wrap in +`role="group"` named by their label, async resolution sets `aria-busy`, and the +empty state is a `role="status"` region. + +That pattern deviates from the APG combobox in one place, deliberately. +`aria-expanded` is omitted because ARIA 1.2 forbids it on `textbox`, and moving +to `role="combobox"` would forbid `aria-multiline`, which matters more for a +chat field that wraps. The popup announces through `aria-haspopup` and live +`aria-activedescendant` narration instead, and Tab selects the highlighted +option rather than moving focus. + +Ask-user renders a labelled `radiogroup`, or `role="group"` with checkboxes for +multi-select. Each option is the real control, holding the group's single tab +stop through roving `tabindex`, so never nest an interactive control inside one: +the option *is* the control, and the composer's question mode treats native +inputs as foreign editables. Disabled options are announced but skipped by +highlight and selection. + +A placeholder overlay is decoration. The composer's is `aria-hidden`, and the +string reaches assistive technology through `aria-placeholder` instead — so when +rich `children` replace the string visually, keep the `placeholder` string +alongside or the hint stops announcing. + +Clicking chrome should not create a tab stop. The composer's container is a +mouse-only focus passthrough: clicking it focuses the editor, clicks on nested +buttons and links pass through, and it carries no role, so keyboard users tab +straight to the editor. + +`Steps` marks the active item with `aria-current="step"`. A disclosure built for +streaming says so while it runs: `Reasoning.Root` carries `aria-busy` until +`isStreaming` flips false, so assistive technology knows the text underneath is +still arriving rather than finished. Disclosure controls announce both their state and what they govern: the shell's trigger is a ` + + + {preview} + + + ); +}; + +const chipClass = + "mx-0.5 inline-flex items-center gap-1 rounded-md border border-[#f0f0f0] bg-[#f4f4f4] px-1.5 py-0.5 align-baseline font-medium text-xs data-[variant=accent]:border-blue-200 data-[variant=accent]:bg-blue-50 data-[variant=accent]:text-blue-700 dark:border-[#2d2d2d] dark:bg-[#232323] dark:data-[variant=accent]:border-blue-900 dark:data-[variant=accent]:bg-blue-950 dark:data-[variant=accent]:text-blue-300"; diff --git a/content/docs/primitives/composer.mdx b/content/docs/primitives/composer.mdx index 4bdf2e4..5121024 100644 --- a/content/docs/primitives/composer.mdx +++ b/content/docs/primitives/composer.mdx @@ -20,6 +20,7 @@ import { Store } from './composer/demos/store'; - **Prefix commands** — type `/`, `@`, or other prefixes to open command lists. - **Panel** — hosts command results, live steps, or an ask-user prompt above the field. - **Headless** — behavior lives in `@intentface/chat`; the demos below show one way to style it, and every class in them is yours to change. +- **Isolate it from your stream** — see [Why the composer needs isolating](#why-the-composer-needs-isolating). The editor is the most expensive thing on the page to re-render per token. - **Get started** — see [Quick start](/quick-start) to add the package. ## Anatomy @@ -59,7 +60,7 @@ The bare nesting — every part is optional except `Composer` and `Container`: `Composer.Panel` takes plain children or a callback receiving the composer state, and shows only while its resolved content is non-empty. Gate each part on the state it belongs to (`commands.active`, `askUser.active`, …) and the panel -opens and closes to match — priority is just the order of your branches. +opens and closes to match — priority is the order of your branches. ## Examples @@ -111,24 +112,18 @@ back. } file="primitives/composer/demos/controlled.tsx" /> -### External store +### Reaching a composer from outside -`Composer.createStore()` returns a handle you own. Pass it via `store` and -drive the composer from anywhere — a toolbar, a shortcut — through -`store.controller`, with no context or ref threading. +Every `Composer.Root` creates its own isolated store, so several composers can +share a page with no wiring at all. Reaching into one from outside its tree is +the case that needs a handle: `Composer.createStore()` returns one you own, and +passing it as `store` lets a toolbar, a shortcut or a status bar drive the +composer through `store.controller` or `useComposerStore`, with no context or +ref threading. } file="primitives/composer/demos/store.tsx" /> -## Multiple instances - -Every `` creates its own isolated store, so several composers can -live on one page with no wiring. To reach a composer from outside its tree — -toolbars, keyboard shortcuts, status bars — create an explicit handle with -`Composer.createStore()`, pass it via the `store` prop, and use -`store.controller` (imperative) or `useComposerStore(store, selector)` -(reactive). - -## Performance +## Why the composer needs isolating Typing costs nothing outside the composer: editor state lives in the store and parts subscribe by slice with `useComposer(selector)`, so a keystroke @@ -166,35 +161,35 @@ ask-user being active, takes priority over normal typing. **Normal typing** export const normalKeys = [ - { attribute: "Enter", description: "Submit the form (requestSubmit)." }, - { attribute: "Shift + Enter", description: "Insert a soft line break." }, - { attribute: "Backspace", description: "When the editor is empty and attachments exist, remove the last attachment." }, + { keys: "Enter", description: "Submit the form (requestSubmit)." }, + { keys: "Shift + Enter", description: "Insert a soft line break." }, + { keys: "Backspace", description: "When the editor is empty and attachments exist, remove the last attachment." }, ]; - + **Command list open** export const commandKeys = [ - { attribute: "ArrowUp / ArrowDown", description: "Move the highlight through the items." }, - { attribute: "ArrowLeft / ArrowRight", description: "Move the caret within the trigger token." }, - { attribute: "Enter / Tab", description: "Select the highlighted item." }, - { attribute: "Escape", description: "Close the command list." }, + { keys: "ArrowUp / ArrowDown", description: "Move the highlight through the items." }, + { keys: "ArrowLeft / ArrowRight", description: "Move the caret within the trigger token." }, + { keys: "Enter / Tab", description: "Select the highlighted item." }, + { keys: "Escape", description: "Close the command list." }, ]; - + **Ask-user active** export const askUserKeys = [ - { attribute: "ArrowUp / ArrowDown", description: "Navigate options; up past the first refocuses the editor." }, - { attribute: "ArrowLeft / ArrowRight", description: "Go to the previous / next question." }, - { attribute: "Enter", description: "Select the highlighted option." }, - { attribute: "Escape", description: "Dismiss the current step." }, - { attribute: "Any character", description: "Focus the editor and start typing a free-text answer." }, + { keys: "ArrowUp / ArrowDown", description: "Navigate options; up past the first refocuses the editor." }, + { keys: "ArrowLeft / ArrowRight", description: "Go to the previous / next question." }, + { keys: "Enter", description: "Select the highlighted option." }, + { keys: "Escape", description: "Dismiss the current step." }, + { keys: "Any character", description: "Focus the editor and start typing a free-text answer." }, ]; - + While `isGenerating`, `Escape` inside the composer calls `Submit`'s `onStop` (via `useComposerSubmit`): from the editor, a button, or a part a positioned `Panel` @@ -207,65 +202,6 @@ To keep Escape for something else, call `event.preventPrimitiveHandler()` in `Composer.Root`'s `onKeyDown`. To stop from anywhere in the chat, handle Escape on its container — the floating dock on the Tabs page does this on `Thread.Root`. -## Accessibility - -### Command popup (combobox) - -The editor is a `role="textbox"` with combobox wiring: `aria-autocomplete="list"`, -`aria-haspopup="listbox"`, plus `aria-controls` and `aria-activedescendant` -while a trigger popup is open. The popup renders `role="listbox"` (labelled -"Suggestions", overridable) with `role="option"` rows carrying stable ids and -`aria-selected` on the highlight — keyboard selection stays in the editor, so -rows are never tab stops. Grouped lists wrap in `role="group"` labelled by -their `CommandGroupLabel`. Async resolution sets `aria-busy` on the listbox and -the empty state is a `role="status"` region. Committed mention chips announce -as atomic tokens ("Label, @ mention"). - -One deliberate deviation from the strict APG combobox pattern: `aria-expanded` -is omitted — ARIA 1.2 forbids it on `textbox`, and switching to -`role="combobox"` would forbid `aria-multiline`, which matters more for a -multiline chat field. The popup announces through `aria-haspopup` and live -`aria-activedescendant` narration instead. Tab selects the highlighted option -while the popup is open (Linear-style) rather than moving focus. - -The placeholder overlay is `aria-hidden` — assistive tech hears the string -`placeholder` prop via `aria-placeholder`. When rich `children` replace the -string, keep a `placeholder` string alongside (children win visually) so the -hint still announces. - -### Ask-user questions - -While `questions` are active, the options form a labelled group: `AskUser.Options` -renders `role="radiogroup"` (single-select) or `role="group"` (multi-select), -named by `AskUser.Label` and described by `AskUser.StepLabel` automatically. -Each `AskUser.Option` is the real control — `role="radio"` / `role="checkbox"` -with `aria-checked` — and holds the group's single tab stop via roving -`tabindex`: DOM focus follows the highlight, entering the group on arrival and -moving with ArrowUp/ArrowDown. Enter and Space select; Escape dismisses the -step (from the options or the editor); typing any character returns focus to -the editor as a free-text answer. Never nest an interactive control inside an -option — the option itself is the control, and the composer's question-mode -key handling treats native inputs as foreign editables. - -- **Form semantics.** The root renders a `
`; `Enter` submits and - `Submit` is a real submit button, so the composer works with standard form - and assistive-tech expectations. -- **Click-to-focus.** `Container` is a mouse-only focus passthrough: clicking - its chrome focuses the editor, but clicks on nested buttons, links, and - inputs pass through. It carries no role and no tab stop — keyboard users tab - straight to the editor. -- **Ask-user focus.** Activating `questions` moves focus into the options - group; typing any character returns focus to the editor for a free-text - answer. -- **Default names.** `Submit` is named "Send message", flipping to - "Stop generating" while generating so the morphed control announces - correctly; `AttachmentTrigger` is named "Add attachment". Both are - overridable via `aria-label`. -- **Busy states.** Submitting/generating are exposed as `data-submitting` on - the root and the `Submit` label flip — the package emits no live-region copy; - add a consumer-owned `role="status"` region if you want in-flight - announcements beyond the button state. - ## API reference Every part accepts `className`, `style`, and `render` (see @@ -424,7 +360,7 @@ export const attachmentsProps = [ { name: "maxFiles", type: "number", default: "unlimited", description: "Maximum file count." }, { name: "maxFileSize", type: "number", default: "unlimited", description: "Maximum size per file." }, { name: "multiple", type: "boolean", default: "true", description: "Allow selecting multiple files." }, - { name: "globalDrop", type: "boolean", default: "false", description: "Accept drops anywhere in the document, not just over the composer." }, + { name: "globalDrop", type: "boolean", default: "false", description: "Accept drops anywhere in the document, not only over the composer." }, { name: "children", type: "ReactNode", description: "The visible strip / drop zone." }, ]; diff --git a/content/docs/primitives/composer/demos/ask-user-flow.tsx b/content/docs/primitives/composer/demos/ask-user-flow.tsx index 34cc75f..670fe45 100644 --- a/content/docs/primitives/composer/demos/ask-user-flow.tsx +++ b/content/docs/primitives/composer/demos/ask-user-flow.tsx @@ -7,7 +7,8 @@ import { type ComposerSubmitData, useComposer, } from "@intentface/chat/composer"; -import { type ComponentProps, useState } from "react"; +import { IconArrowUp } from "@tabler/icons-react"; +import { useState } from "react"; // Setting `questions` arms the flow and flips askUser.active. Answering or // skipping the last one fires onSubmit with { kind: "answers" }. @@ -78,7 +79,7 @@ export const AskUserFlow = () => { {done ? ( - + ) : ( @@ -204,20 +205,3 @@ const Controls = () => { ); }; - -const SendIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/composer/demos/attachments.tsx b/content/docs/primitives/composer/demos/attachments.tsx index 3fe732c..8e608f2 100644 --- a/content/docs/primitives/composer/demos/attachments.tsx +++ b/content/docs/primitives/composer/demos/attachments.tsx @@ -2,7 +2,7 @@ import { Attachments } from "@intentface/chat/attachments"; import { Composer, type ComposerSubmitData, useComposer } from "@intentface/chat/composer"; -import type { ComponentProps } from "react"; +import { IconArrowUp, IconPaperclip, IconX } from "@tabler/icons-react"; // Composer.Attachments carries the policy and the hidden file input; the strip // itself is yours. Files can be picked with the trigger or dropped on the composer. @@ -32,10 +32,10 @@ export const AttachmentsDemo = () => { aria-label="Attach a file" className="flex size-8 cursor-pointer items-center justify-center rounded-full text-[#949494] transition-colors hover:bg-[#f4f4f4] hover:text-[#1a1a1a] dark:text-[#6f6f6f] dark:hover:bg-[#232323] dark:hover:text-[#fcfcfc]" > - + - + @@ -67,7 +67,7 @@ const Strip = () => { filename={item.filename} className="flex size-5 cursor-pointer items-center justify-center rounded-full text-[#949494] transition-colors hover:bg-[#ececec] hover:text-[#1a1a1a] dark:hover:bg-[#2d2d2d] dark:hover:text-[#fcfcfc]" > - + ))} @@ -81,53 +81,3 @@ const formatFileSize = (bytes?: number) => { if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; }; - -const PaperclipIcon = (props: ComponentProps<"svg">) => ( - -); - -const CrossIcon = (props: ComponentProps<"svg">) => ( - -); - -const SendIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/composer/demos/basic.tsx b/content/docs/primitives/composer/demos/basic.tsx index a5571d0..bda6e7c 100644 --- a/content/docs/primitives/composer/demos/basic.tsx +++ b/content/docs/primitives/composer/demos/basic.tsx @@ -1,7 +1,7 @@ "use client"; import { Composer, type ComposerSubmitData } from "@intentface/chat/composer"; -import type { ComponentProps } from "react"; +import { IconArrowUp } from "@tabler/icons-react"; // Every owns an isolated store, so a bare composer needs no // setup beyond an onSubmit handler. @@ -25,27 +25,10 @@ export const Basic = () => { - + ); }; - -const SendIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/composer/demos/commands.tsx b/content/docs/primitives/composer/demos/commands.tsx index ac2ca46..7af54e9 100644 --- a/content/docs/primitives/composer/demos/commands.tsx +++ b/content/docs/primitives/composer/demos/commands.tsx @@ -1,7 +1,7 @@ "use client"; import { type CommandItemData, Composer, type ComposerSubmitData } from "@intentface/chat/composer"; -import type { ComponentProps } from "react"; +import { IconArrowUp } from "@tabler/icons-react"; const MENTIONS: CommandItemData[] = [ { value: "readme", label: "README.md", description: "Project overview" }, @@ -71,7 +71,7 @@ export const Commands = () => { - + @@ -79,20 +79,3 @@ export const Commands = () => { ); }; - -const SendIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/composer/demos/controlled.tsx b/content/docs/primitives/composer/demos/controlled.tsx index 12c8acf..5ed5ad8 100644 --- a/content/docs/primitives/composer/demos/controlled.tsx +++ b/content/docs/primitives/composer/demos/controlled.tsx @@ -1,7 +1,8 @@ "use client"; import { Composer, type ComposerSubmitData } from "@intentface/chat/composer"; -import { type ComponentProps, useState } from "react"; +import { IconArrowUp } from "@tabler/icons-react"; +import { useState } from "react"; // The Textarea's plain-text value is controlled by the parent: the buttons // drive it, and typing reports back through onValueChange. @@ -30,12 +31,12 @@ export const Controlled = () => { - + -
+
); }; - -const SendIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/composer/demos/popover.tsx b/content/docs/primitives/composer/demos/popover.tsx index 1dc6ac3..533646d 100644 --- a/content/docs/primitives/composer/demos/popover.tsx +++ b/content/docs/primitives/composer/demos/popover.tsx @@ -1,7 +1,7 @@ "use client"; import { type CommandItemData, Composer, type ComposerSubmitData } from "@intentface/chat/composer"; -import type { ComponentProps } from "react"; +import { IconArrowUp } from "@tabler/icons-react"; const MENTIONS: CommandItemData[] = [ { value: "readme", label: "README.md", description: "Project overview" }, @@ -65,27 +65,10 @@ export const Popover = () => { - + ); }; - -const SendIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/composer/demos/store.tsx b/content/docs/primitives/composer/demos/store.tsx index dff3e5e..1daf852 100644 --- a/content/docs/primitives/composer/demos/store.tsx +++ b/content/docs/primitives/composer/demos/store.tsx @@ -1,7 +1,7 @@ "use client"; import { Composer, type ComposerSubmitData } from "@intentface/chat/composer"; -import type { ComponentProps } from "react"; +import { IconArrowUp } from "@tabler/icons-react"; // A store handle created outside the tree. The button drives the composer // through store.controller — no context, no hook, no ref threading. @@ -26,7 +26,7 @@ export const Store = () => { - + @@ -41,20 +41,3 @@ export const Store = () => {
); }; - -const SendIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/message.mdx b/content/docs/primitives/message.mdx index d1bbc7a..2accd09 100644 --- a/content/docs/primitives/message.mdx +++ b/content/docs/primitives/message.mdx @@ -5,6 +5,8 @@ source: message --- import { Basic } from './message/demos/basic'; +import { Chips } from './message/demos/chips'; +import { Selection } from './message/demos/selection'; } file="primitives/message/demos/basic.tsx" /> @@ -13,6 +15,7 @@ import { Basic } from './message/demos/basic'; - **One turn's container** — `Message.Root` reports the role and position as data attributes and renders no layout of its own. - **Segmented text** — `Message.Text` reconstructs inline chips from the wire format and takes render callbacks for both runs and chips. - **Everything else is yours** — bubbles, avatars, copy buttons, source pills, attachment previews and markdown rendering are composed by you around these parts. +- **Memoise your row, not ours** — see [Why the memo boundary is yours](#why-the-memo-boundary-is-yours). Getting this wrong re-renders every message on every stream chunk. - **Get started** — see [Quick start](/quick-start) to add the package. ## Anatomy @@ -42,7 +45,27 @@ attributes: ``` -## Performance +## Examples + +### Reconstructing chips from the text + +The wire format is a markdown-shaped link, `[Label](chip:prefix:value)`, with +everything the chip needs inside the token. A stored message therefore rebuilds +its own chips from its text alone, with no sidecar metadata to keep in sync. +`renderChip` decides what one looks like at render time. + +} file="primitives/message/demos/chips.tsx" /> + +### Acting on a text selection + +Selection is a hook rather than a part, so the toolbar it drives stays yours. +`useMessageSelection` takes the element to scope to and reports the settled +selection inside it. Scoping is the point: a drag across two messages, or +anywhere else on the page, reports nothing. + +} file="primitives/message/demos/selection.tsx" /> + +## Why the memo boundary is yours Message is compositional — you pass its parts as children — which means the package cannot memoize rows for you: a parent re-render re-creates the children @@ -81,20 +104,6 @@ Three rules keep the memo effective while a reply streams: Done right, a stream chunk re-renders exactly one row. See [Composer performance](/primitives/composer#performance) for the full render model. -## Accessibility - -- **Role** drives `data-role`, and error/last state drive `data-error`/`data-last` - on the root, so styling and assistive context stay in sync. -- **Speaker identity is yours to announce.** `role` is an opaque string the - package only surfaces as `data-role` — alignment and colour are invisible to - assistive tech. Give each message a visually-hidden `{role} said` prefix, or - an `aria-label` on the root, so a transcript read top-to-bottom attributes - its turns. -- **Error, stopped and loading markers** are your markup: give an inline failure - marker `role="alert"` so it announces immediately, and quieter states - ("stopped", "generating…") `role="status"`. -- **Actions** you add should be real buttons with accessible names. - ## API reference All three parts accept `className`, `style`, and `render` @@ -102,7 +111,9 @@ All three parts accept `className`, `style`, and `render` ### Message.Root -The container. Renders `data-message`. +One turn's container. Reports the role and position as data attributes and +renders no layout of its own, so the bubble, avatar and actions around it stay +yours. Renders a `
` element. export const rootProps = [ { name: "role", type: "string", default: "(required)", description: "Opaque role string surfaced as data-role; you own the set (commonly system / user / assistant)." }, @@ -123,13 +134,14 @@ export const rootAttrs = [ ### Message.Turn -Groups consecutive messages from one role into a single visual turn. Renders -`data-message-turn` and takes no props of its own beyond the shared ones. +Groups consecutive messages from one role into a single visual turn. Renders a +`
` element, and takes no props of its own beyond the shared ones. ### Message.Text -Plain text with inline chips reconstructed from the wire format. Renders -`data-message-text`. +Message text with inline chips reconstructed from the wire format, so a stored +message rebuilds its own chips with no sidecar metadata. Renders a `` +element. export const textProps = [ { name: "children", type: "string", default: "(required)", description: "The message text; chip tokens are parsed out and rendered." }, diff --git a/content/docs/primitives/message/demos/basic.tsx b/content/docs/primitives/message/demos/basic.tsx index 9c499fc..f473111 100644 --- a/content/docs/primitives/message/demos/basic.tsx +++ b/content/docs/primitives/message/demos/basic.tsx @@ -1,7 +1,8 @@ "use client"; import { Message } from "@intentface/chat/message"; -import { type ComponentProps, useState } from "react"; +import { IconCheck, IconCopy } from "@tabler/icons-react"; +import { useState } from "react"; // Message.Root stamps data-role / data-last / data-error and imposes no layout; // the bubble, alignment, and actions are all yours. @@ -49,41 +50,7 @@ const CopyButton = ({ value }: { value: string }) => { aria-label="Copy message" className="flex size-7 cursor-pointer items-center justify-center rounded-md text-[#949494] transition-colors hover:bg-[#f4f4f4] hover:text-[#1a1a1a] dark:text-[#6f6f6f] dark:hover:bg-[#232323] dark:hover:text-[#fcfcfc]" > - {copied ? : } + {copied ? : } ); }; - -const CopyIcon = (props: ComponentProps<"svg">) => ( - -); - -const CheckIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/message/demos/chips.tsx b/content/docs/primitives/message/demos/chips.tsx new file mode 100644 index 0000000..73cb966 --- /dev/null +++ b/content/docs/primitives/message/demos/chips.tsx @@ -0,0 +1,72 @@ +"use client"; + +import { Chip } from "@intentface/chat/chip"; +import { Message, type MessageChipSegment } from "@intentface/chat/message"; +import { IconFile, IconFileText, IconTool } from "@tabler/icons-react"; +import type { ComponentProps } from "react"; + +/* + * A message whose text carries inline chip references, and the renderers that + * turn them back into chips. + * + * The wire format is a markdown-shaped link: `[Label](chip:prefix:value)`, with + * everything the chip needs riding along inside the token. That is the point — + * a stored message reconstructs its own chips from its text alone, with no + * sidecar array of metadata to keep in sync or migrate. + * + * `Message.Text` parses the tokens and calls `renderChip` for each one. What a + * chip looks like, and whether a prefix earns a different variant, is decided + * here at render time rather than baked into the stored text. + */ +const TEXT = + "I compared [pricing.tsx](chip:file:src/app/pricing.tsx) against " + + "[the Q3 brief](chip:doc:q3-brief) and pulled figures from " + + "[web-search](chip:tool:web-search). The deprecated rate in " + + "[legacy.ts](chip:file:src/legacy.ts) is the only mismatch."; + +export const Chips = () => ( +
+ {/* biome-ignore lint/a11y/useValidAriaRole: `role` is the message's author, not an ARIA role */} + + + {TEXT} + + +
+); + +/** The prefix decides the variant and the icon; neither is stored in the text. */ +const renderChip = (chip: MessageChipSegment, index: number) => ( + + + {chip.prefix === "file" ? ( + + ) : chip.prefix === "doc" ? ( + + ) : ( + + )} + + {chip.label} + +); + +const chipClass = + "mx-0.5 inline-flex items-center gap-1 rounded-md border border-[#f0f0f0] bg-[#f4f4f4] px-1.5 py-0.5 align-baseline font-medium text-xs data-[variant=accent]:border-blue-200 data-[variant=accent]:bg-blue-50 data-[variant=accent]:text-blue-700 dark:border-[#2d2d2d] dark:bg-[#232323] dark:data-[variant=accent]:border-blue-900 dark:data-[variant=accent]:bg-blue-950 dark:data-[variant=accent]:text-blue-300"; + +const _icon = (props: ComponentProps<"svg">) => ({ + viewBox: "0 0 16 16", + fill: "none", + stroke: "currentColor", + strokeWidth: 1.3, + className: "size-3", + "aria-hidden": true, + ...props, +}); diff --git a/content/docs/primitives/message/demos/selection.tsx b/content/docs/primitives/message/demos/selection.tsx new file mode 100644 index 0000000..b05f82a --- /dev/null +++ b/content/docs/primitives/message/demos/selection.tsx @@ -0,0 +1,64 @@ +"use client"; + +import { Message, useMessageSelection } from "@intentface/chat/message"; +import { useState } from "react"; + +/* + * Selection is exposed as a hook rather than a part, so the toolbar it drives + * stays entirely yours — this one is a small bar, but a popover anchored to the + * range would read the same value. + * + * `useMessageSelection` takes the element to scope to and returns the settled + * selection inside it, or null. Scoping is the whole point: dragging across two + * messages, or selecting in the page around them, reports nothing here. + */ +export const Selection = () => { + const [scope, setScope] = useState(null); + const selection = useMessageSelection(scope); + const [quoted, setQuoted] = useState(null); + + return ( +
+ {/* biome-ignore lint/a11y/useValidAriaRole: `role` is the message's author, not an ARIA role */} + + + useMemo caches a computed value and useCallback caches a function reference. Reach for + either only when something downstream is memoised, because the comparison itself is not + free. Select any of this sentence. + + + + {/* Rendered outside the message, and still scoped to it. */} +
+ {selection ? ( + <> + + “{selection.text}” + + + + ) : ( + + Nothing selected in this message. + + )} +
+ + {quoted && ( +
+ {quoted} +
+ )} +
+ ); +}; diff --git a/content/docs/primitives/nav.mdx b/content/docs/primitives/nav.mdx index 213bebd..75933a8 100644 --- a/content/docs/primitives/nav.mdx +++ b/content/docs/primitives/nav.mdx @@ -260,7 +260,7 @@ These are the widget's own keys, not global ones: the handler sits on `Nav.Root`, so nothing fires unless focus is already inside the tree. export const keys = [ - { keys: "Arrow up / down", description: "Move focus to the previous or next visible row. Collapsed lists are unmounted, so their rows are simply not there to land on." }, + { keys: "Arrow up / down", description: "Move focus to the previous or next visible row. Collapsed lists are unmounted, so their rows are not there to land on." }, { keys: "Arrow right", description: "On a closed group, open it; on an open one, step into it. On a leaf, nothing." }, { keys: "Arrow left", description: "On an open group, close it; otherwise step out to the parent group's trigger — which is where the row came from." }, { keys: "Enter / Space", description: "Activate the focused row: toggle a group, or go to its page when the trigger holds a Nav.Toggle." }, diff --git a/content/docs/primitives/nav/demos/basic.tsx b/content/docs/primitives/nav/demos/basic.tsx index e93a9ab..b1ab475 100644 --- a/content/docs/primitives/nav/demos/basic.tsx +++ b/content/docs/primitives/nav/demos/basic.tsx @@ -1,6 +1,7 @@ "use client"; import { Nav } from "@intentface/chat/nav"; +import { IconBox, IconChevronDown, IconHome, IconInbox, IconMessage } from "@tabler/icons-react"; import { type ComponentProps, useState } from "react"; /* @@ -45,7 +46,7 @@ export const Basic = () => { render={link("/overview", () => setCurrent("overview"))} > - + Overview @@ -57,7 +58,7 @@ export const Basic = () => { render={link("/inbox", () => setCurrent("inbox"))} > - + Inbox @@ -75,7 +76,7 @@ export const Basic = () => { - + Intentface @@ -91,7 +92,7 @@ export const Basic = () => { render={link("/intentface/home", () => setCurrent("team-home"))} > - + Home @@ -103,7 +104,7 @@ export const Basic = () => { render={link("/intentface/issues", () => setCurrent("team-issues"))} > - + Issues @@ -114,7 +115,7 @@ export const Basic = () => { - + Chat @@ -145,7 +146,7 @@ export const Basic = () => { - + Website @@ -220,7 +221,7 @@ const rowClass = [ * reading `data-closed` off the enclosing trigger, so nothing is threaded down. */ const Chevron = () => ( - + ); /* @@ -282,77 +283,3 @@ const RailRecipe = () => ( } `} ); - -const HomeIcon = (props: ComponentProps<"svg">) => ( - -); - -const InboxIcon = (props: ComponentProps<"svg">) => ( - -); - -const BoxIcon = (props: ComponentProps<"svg">) => ( - -); - -const ChatIcon = (props: ComponentProps<"svg">) => ( - -); - -const ChevronIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/nav/demos/collapse.tsx b/content/docs/primitives/nav/demos/collapse.tsx index c9c550c..354f893 100644 --- a/content/docs/primitives/nav/demos/collapse.tsx +++ b/content/docs/primitives/nav/demos/collapse.tsx @@ -1,7 +1,7 @@ "use client"; import { Nav } from "@intentface/chat/nav"; -import type { ComponentProps } from "react"; +import { IconChevronDown } from "@tabler/icons-react"; /* * The collapse, slowed to 500ms so the mechanism is visible. @@ -75,7 +75,7 @@ const rowClass = [ ].join(" "); const Chevron = () => ( - + ); /* @@ -98,18 +98,3 @@ const CollapseRecipe = () => ( .collapse-demo [data-nav-list][data-indent] { margin-left: 15px; padding-left: 7px; } `} ); - -const ChevronIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/nav/demos/external.tsx b/content/docs/primitives/nav/demos/external.tsx index f53bad6..5de0255 100644 --- a/content/docs/primitives/nav/demos/external.tsx +++ b/content/docs/primitives/nav/demos/external.tsx @@ -1,7 +1,8 @@ "use client"; import { Nav, type NavStore, useNavStore } from "@intentface/chat/nav"; -import { type ComponentProps, useState } from "react"; +import { IconChevronDown } from "@tabler/icons-react"; +import { useState } from "react"; const GROUPS = ["workspace", "projects", "archive"]; @@ -97,7 +98,7 @@ const rowClass = [ ].join(" "); const Chevron = () => ( - + ); const CollapseRecipe = () => ( @@ -114,18 +115,3 @@ const CollapseRecipe = () => ( .external-nav-demo [data-nav-list][data-indent] { margin-left: 15px; padding-left: 7px; } `} ); - -const ChevronIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/nav/demos/guides.tsx b/content/docs/primitives/nav/demos/guides.tsx index 6180c23..f242621 100644 --- a/content/docs/primitives/nav/demos/guides.tsx +++ b/content/docs/primitives/nav/demos/guides.tsx @@ -1,7 +1,7 @@ "use client"; import { Nav } from "@intentface/chat/nav"; -import type { ComponentProps } from "react"; +import { IconBox, IconChevronDown, IconHome } from "@tabler/icons-react"; /* * The same tree four times, once per `guide` value, so the rungs can be @@ -44,7 +44,7 @@ const GuideTree = ({ guide, caption }: { guide: GuideValue; caption: string }) = - + Overview @@ -52,7 +52,7 @@ const GuideTree = ({ guide, caption }: { guide: GuideValue; caption: string }) = - + Chat @@ -101,7 +101,7 @@ const rowClass = [ ].join(" "); const Chevron = () => ( - + ); /* @@ -151,44 +151,3 @@ const RailRecipe = () => ( } `} ); - -const HomeIcon = (props: ComponentProps<"svg">) => ( - -); - -const BoxIcon = (props: ComponentProps<"svg">) => ( - -); - -const ChevronIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/reasoning.mdx b/content/docs/primitives/reasoning.mdx index ed36d4c..25d8742 100644 --- a/content/docs/primitives/reasoning.mdx +++ b/content/docs/primitives/reasoning.mdx @@ -5,6 +5,7 @@ source: reasoning --- import { Basic } from './reasoning/demos/basic'; +import { Streaming } from './reasoning/demos/streaming'; } file="primitives/reasoning/demos/basic.tsx" /> @@ -34,25 +35,20 @@ Driven from a streaming message, passing the reasoning parts' text: ``` -## useReasoning - -Read the disclosure state from anywhere inside ``: +## Examples -export const hookMembers = [ - { name: "isStreaming", type: "boolean", description: "Whether reasoning is still streaming in." }, - { name: "isOpen", type: "boolean", description: "Whether the panel is open." }, - { name: "setIsOpen", type: "(open: boolean) => void", description: "Toggle the panel." }, - { name: "duration", type: "number | undefined", description: "Tracked streaming duration in seconds." }, -]; +### Tracking the streaming state - +`isStreaming` is the only input. While it is true the root carries +`data-streaming` and `aria-busy`; the moment it flips false the elapsed time is +captured and handed back as `duration`, so the trigger's label changes without +you timing anything. -## Accessibility +} file="primitives/reasoning/demos/streaming.tsx" /> -Built on a disclosure: `Reasoning.Trigger` is a ` +
+
+ ); +}; + +/** + * The trigger ships no copy. `useReasoning` is how the label learns what to + * say: `isStreaming` while it runs, then `duration` once the package has + * captured it. + */ +const TriggerLabel = () => { + const { isStreaming, duration } = useReasoning(); + + return ( + + + + {isStreaming + ? "Thinking…" + : duration === undefined + ? "Reasoning" + : `Thought for ${duration}s`} + + + + ); +}; + +/* + * `--panel-height` is published only while a transition runs, and released once + * the panel settles open. That release is what lets the open panel keep growing + * as sections stream in: with the property gone the declaration is invalid at + * computed-value time and `height` lands back on `auto`. + */ +const PanelTransition = () => ( + +); diff --git a/content/docs/primitives/shell.mdx b/content/docs/primitives/shell.mdx index d45c9cb..0514d06 100644 --- a/content/docs/primitives/shell.mdx +++ b/content/docs/primitives/shell.mdx @@ -164,7 +164,7 @@ Taking the sidebar out of flow is not a styling preference, and the primitive does not work without it. All three states are one element morphing between three positions: flush while -expanded, off-canvas while collapsed, floating just inside the edge while the +expanded, off-canvas while collapsed, floating slightly inside the edge while the hotspot holds it out. A sidebar left in flow can only animate its own width. It can never float over the content, so the hotspot has nothing to slide across and the state has nowhere to exist. diff --git a/content/docs/primitives/shell/demos/basic.tsx b/content/docs/primitives/shell/demos/basic.tsx index 267d2f3..72bd03d 100644 --- a/content/docs/primitives/shell/demos/basic.tsx +++ b/content/docs/primitives/shell/demos/basic.tsx @@ -2,7 +2,13 @@ import { Nav } from "@intentface/chat/nav"; import { Shell } from "@intentface/chat/shell"; -import type { ComponentProps } from "react"; +import { + IconBox, + IconChevronDown, + IconHome, + IconInbox, + IconLayoutSidebar, +} from "@tabler/icons-react"; /* * A shell the way it is meant to be used: a sidebar that collapses, floats out @@ -68,7 +74,7 @@ export const Basic = () => ( @intentface/chat - + @@ -84,13 +90,13 @@ export const Basic = () => ( - + Overview - + Inbox @@ -98,13 +104,13 @@ export const Basic = () => ( Workspace - + {["Initiatives", "Projects", "Views", "Loops"].map((label) => ( - + {label} @@ -144,7 +150,7 @@ export const Basic = () => (
Docs - + Overview @@ -180,77 +186,3 @@ const rowClass = [ "data-[active]:bg-[#ececec] data-[active]:text-[#1a1a1a] dark:data-[active]:bg-[#2d2d2d] dark:data-[active]:text-[#fcfcfc]", "[&_svg]:size-4 [&_svg]:shrink-0", ].join(" "); - -const PanelLeftIcon = (props: ComponentProps<"svg">) => ( - -); - -const HomeIcon = (props: ComponentProps<"svg">) => ( - -); - -const InboxIcon = (props: ComponentProps<"svg">) => ( - -); - -const BoxIcon = (props: ComponentProps<"svg">) => ( - -); - -const ChevronIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/steps.mdx b/content/docs/primitives/steps.mdx index 3c3c471..5d656bf 100644 --- a/content/docs/primitives/steps.mdx +++ b/content/docs/primitives/steps.mdx @@ -5,6 +5,7 @@ source: steps --- import { Basic } from './steps/demos/basic'; +import { Status } from './steps/demos/status'; } file="primitives/steps/demos/basic.tsx" /> @@ -12,8 +13,10 @@ import { Basic } from './steps/demos/basic'; - **Recursive disclosure tree** — every node is a `Steps.Item` with a `Trigger` and a `Panel`, and panels can hold further items, so timelines nest arbitrarily. - **Status-driven** — each item's `status` (`complete` / `active` / `pending`) flows to its `Icon` and `Label` via context; active items open by default. -- **Nesting** — a nested item surfaces `data-nested` for the indent rail; a static row is just an `Icon` + `Label` in a `
`. +- **Nesting** — a nested item surfaces `data-nested` for the indent rail; a static row is an `Icon` and a `Label` in a `
`. - **You compose the rows** — the primitive ships the disclosure + status plumbing; row content (icons, tool-call summaries) is yours to render. +- **No composite keyboard model** — each trigger is a real button, so the tree is plain sequential tab order with no roving focus to learn. +- **Panels animate from a published height** — see [Why the panel releases its height](#why-the-panel-releases-its-height), which is also why an open panel keeps growing. - **Get started** — see [Quick start](/quick-start) to add the package. ## Anatomy @@ -53,16 +56,18 @@ A timeline is a top-level item whose panel holds rows; a row is an `Icon` + ``` -## Status +## Examples -`status` is an opaque `string` — you own the set (commonly `"complete"`, -`"active"`, `"pending"`, but add `"error"`/`"skipped"`/anything). `Steps.Item` -takes a `status` and publishes it through context; `Steps.Icon` and -`Steps.Label` inherit it, or override with their own `status`. Resolution is -*own prop → inherited → `"complete"`*. Every status-aware part reflects it as -`data-status` for styling. +### Driving rows from status -## Height transitions +`status` is an opaque string. The package resolves it — own prop, then inherited +from the enclosing item, then `"complete"` — and reflects it as `data-status`. +It never decides what the set is, so the `"error"` below is a string this demo +invented and then styled. + +} file="primitives/steps/demos/status.tsx" /> + +## Why the panel releases its height The panel publishes its measured height as `--panel-height` while an open or close transition runs, and **releases it once the panel settles open**. So @@ -71,9 +76,9 @@ variable no longer written — becomes invalid at computed-value time and falls back to `auto`. That is what lets an open panel track content appearing inside it, rather than staying pinned to the height it had when it opened. -The demo at the top of this page uses it. Collapse and expand the timeline to -see the transition, then expand **Searched the web** while the timeline is -already open — the outer panel grows to fit the detail instead of clipping it. +The demo at the top of this page uses it. Collapse and expand the timeline, +then expand **Searched the web** while the timeline is already open — the outer +panel grows to fit the detail instead of clipping it. Two details in that demo are load-bearing. `data-starting-style` and `data-ending-style` clamp the height to `0` on the transitional frames, and they @@ -82,34 +87,6 @@ And `[&>*]:shrink-0` guards the measurement: a flex column clamped to `height: 0 puts every child under shrink pressure, and a child that collapses to nothing makes the panel measure itself as `0px`. -## Keyboard - -Each item is a standard disclosure: `Steps.Trigger` is a real button, so -`Tab` moves between triggers and `Enter`/`Space` toggle the nearest item. -Nested items nest their own triggers — there is no roving focus or composite -widget; the tree is plain sequential tab order. - -## Accessibility - -Disclosure semantics are inherited from the underlying Collapsible: -`aria-expanded`/`aria-controls` on the trigger, an id-linked, `hidden`-managed -panel. The item whose `status` is `"active"` additionally carries -`aria-current="step"` — the same "active" convention `defaultOpen` already -keys off. - -Status itself is invisible to assistive tech by default: `Steps.Icon` is -`aria-hidden` and color never announces. Mount `Steps.Status` inside rows -whose status matters — it renders a visually-hidden span speaking the resolved -status string, and takes `children` for localized copy: - -```tsx - - - Searching the web - - -``` - ## API reference Every part accepts `className`, `style`, and `render` (see @@ -117,11 +94,14 @@ Every part accepts `className`, `style`, and `render` (see ### Steps -The timeline root. Renders `data-steps`. No part-specific props. +The timeline container. Ships the disclosure and status plumbing and no row +content: what a tool call or a reasoning step looks like is yours. Renders a +`
` element. ### Steps.Item -One node of the tree (a disclosure). Renders `data-steps-item`, plus +One node of the tree, and the unit that nests: an item's panel may hold further +items, so a timeline goes as deep as the run did. Renders a `
` element, plus `aria-current="step"` while `status` is `"active"`. export const itemProps = [ @@ -145,14 +125,18 @@ export const itemAttrs = [ ### Steps.Trigger -Toggles the nearest item. Renders a ` +
+
+ ); +}; + +// Every rule here keys off data-status. The package supplies the attribute and +// takes no view on what the values mean. +const iconClass = + "grid size-4 shrink-0 place-items-center text-[#949494] data-[status=complete]:text-emerald-600 data-[status=active]:text-[#1a1a1a] data-[status=error]:text-red-600 dark:text-[#6f6f6f] dark:data-[status=complete]:text-emerald-400 dark:data-[status=active]:text-[#fcfcfc] dark:data-[status=error]:text-red-400"; + +const labelClass = + "text-sm text-[#949494] data-[status=complete]:text-[#686868] data-[status=active]:text-[#1a1a1a] data-[status=active]:font-medium data-[status=error]:text-red-600 dark:text-[#6f6f6f] dark:data-[status=complete]:text-[#9b9b9b] dark:data-[status=active]:text-[#fcfcfc] dark:data-[status=error]:text-red-400"; + +const _glyph = (props: ComponentProps<"svg">) => ({ + viewBox: "0 0 16 16", + fill: "none", + stroke: "currentColor", + strokeWidth: 1.6, + strokeLinecap: "round" as const, + strokeLinejoin: "round" as const, + className: "size-3.5", + "aria-hidden": true, + ...props, +}); diff --git a/content/docs/primitives/tabs.mdx b/content/docs/primitives/tabs.mdx index 7c67990..9848519 100644 --- a/content/docs/primitives/tabs.mdx +++ b/content/docs/primitives/tabs.mdx @@ -20,6 +20,7 @@ import { ConfirmClose } from './tabs/demos/confirm-close'; - **Order is data** — `items` is an ordered array on the store, not something derived from the DOM. Drag it with whatever library you like through `render`; the result is a state change like any other. - **One viewport, not a panel per tab** — switching re-renders the same box, which is what lets a floating surface move rather than tear itself down. - **In the layout or anchored** — wrapping the viewport in `Portal` › `Positioner` › `Popup` is the entire difference between the two. +- **A toolbar, not a tablist** — see [Why a toolbar and not a tablist](#why-a-toolbar-and-not-a-tablist). ARIA's tablist cannot describe a closable, open-ended strip. - **Get started** — see [Quick start](/quick-start) to add the package. ## Anatomy diff --git a/content/docs/primitives/tabs/demos/anchored.tsx b/content/docs/primitives/tabs/demos/anchored.tsx index 81d6f08..825a9bc 100644 --- a/content/docs/primitives/tabs/demos/anchored.tsx +++ b/content/docs/primitives/tabs/demos/anchored.tsx @@ -4,7 +4,15 @@ import { Composer, type ComposerSubmitData } from "@intentface/chat/composer"; import { Message } from "@intentface/chat/message"; import { Tabs, useTabs } from "@intentface/chat/tabs"; import { Thread } from "@intentface/chat/thread"; -import { type ComponentProps, type KeyboardEvent, useRef, useState } from "react"; +import { + IconArrowUp, + IconMessage, + IconMinus, + IconPlayerStop, + IconSparkles, + IconX, +} from "@tabler/icons-react"; +import { type KeyboardEvent, useRef, useState } from "react"; /* * A chat dock in the corner of a page. The same Root, List and Viewport as the @@ -187,7 +195,7 @@ export const Anchored = () => { {(id) => ( - + {title(id)} { aria-label={`Close ${title(id)}`} className="grid size-5 shrink-0 cursor-pointer select-none place-items-center rounded text-[#686868] transition-colors hover:bg-[#e4e4e4] hover:text-[#1a1a1a] dark:text-[#9b9b9b] dark:hover:bg-[#333333] dark:hover:text-[#fcfcfc]" > - + @@ -213,7 +221,7 @@ export const Anchored = () => { disclosure ARIA a tab does. */} - + Agent @@ -290,7 +298,7 @@ const DockHeader = ({ title }: { title: (id: string) => string }) => { onClick={() => select(null)} className={iconButtonClass} > - + ); @@ -377,7 +385,7 @@ const ChatThread = ({ const NewChat = ({ onStart }: { onStart: (text: string) => void }) => (
- +

Ask the agent

This is a draft — it becomes a tab once you send something. @@ -425,7 +433,11 @@ const DockComposer = ({ aria-label={generating ? "Stop" : "Send"} className="flex size-7 items-center justify-center rounded-full bg-[#1a1a1a] text-white transition-opacity disabled:opacity-30 dark:bg-[#fcfcfc] dark:text-[#111111]" > - {generating ? : } + {generating ? ( + + ) : ( + + )} @@ -443,86 +455,3 @@ const dockTabClass = [ const iconButtonClass = "grid size-6 shrink-0 cursor-pointer select-none place-items-center rounded-md text-[#949494] transition-colors hover:bg-[#f4f4f4] hover:text-[#1a1a1a] focus-visible:-outline-offset-2 focus-visible:outline-2 focus-visible:outline-[#1a1a1a] dark:text-[#6f6f6f] dark:hover:bg-[#232323] dark:hover:text-[#fcfcfc] dark:focus-visible:outline-[#fcfcfc]"; - -const ChatIcon = (props: ComponentProps<"svg">) => ( - -); - -const AgentIcon = (props: ComponentProps<"svg">) => ( - -); - -const ArrowUpIcon = (props: ComponentProps<"svg">) => ( - -); - -const StopIcon = (props: ComponentProps<"svg">) => ( - -); - -const MinusIcon = (props: ComponentProps<"svg">) => ( - -); - -const CloseIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/tabs/demos/basic.tsx b/content/docs/primitives/tabs/demos/basic.tsx index 50e352a..7add451 100644 --- a/content/docs/primitives/tabs/demos/basic.tsx +++ b/content/docs/primitives/tabs/demos/basic.tsx @@ -1,7 +1,8 @@ "use client"; import { Tabs, useTabs } from "@intentface/chat/tabs"; -import { type ComponentProps, Fragment, type ReactNode, useEffect, useRef, useState } from "react"; +import { IconFile, IconPlus, IconX } from "@tabler/icons-react"; +import { Fragment, type ReactNode, useEffect, useRef, useState } from "react"; /* * Document tabs across the window chrome, with the content in a card beneath. @@ -80,7 +81,7 @@ export const Basic = () => { className={tabClass} > - + {documents[id]?.name ?? id} @@ -99,7 +100,7 @@ export const Basic = () => { aria-label={`Close ${documents[id]?.name ?? id}`} className="grid size-5 shrink-0 cursor-pointer select-none place-items-center rounded-md text-[#686868] transition-colors hover:bg-[#e4e4e4] hover:text-[#1a1a1a] dark:text-[#9b9b9b] dark:hover:bg-[#333333] dark:hover:text-[#fcfcfc]" > - + @@ -203,7 +204,7 @@ const NewDocument = ({ onCreate }: { onCreate: (id: string, document: Document) }} className="grid size-7 shrink-0 cursor-pointer select-none place-items-center rounded-md text-[#686868] transition-colors hover:bg-[#f4f4f4] hover:text-[#1a1a1a] focus-visible:-outline-offset-2 focus-visible:outline-2 focus-visible:outline-[#1a1a1a] dark:text-[#9b9b9b] dark:hover:bg-[#232323] dark:hover:text-[#fcfcfc] dark:focus-visible:outline-[#fcfcfc]" > - + ); }; @@ -255,47 +256,3 @@ const tabClass = [ "border border-transparent data-[selected]:border-[#f0f0f0] data-[selected]:bg-white data-[selected]:text-[#1a1a1a]", "dark:data-[selected]:border-[#262626] dark:data-[selected]:bg-[#181818] dark:data-[selected]:text-[#fcfcfc]", ].join(" "); - -const FileIcon = (props: ComponentProps<"svg">) => ( - -); - -const PlusIcon = (props: ComponentProps<"svg">) => ( - -); - -const CloseIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/tabs/demos/closing.tsx b/content/docs/primitives/tabs/demos/closing.tsx index 7c8f07e..98fa374 100644 --- a/content/docs/primitives/tabs/demos/closing.tsx +++ b/content/docs/primitives/tabs/demos/closing.tsx @@ -1,7 +1,8 @@ "use client"; import { Tabs } from "@intentface/chat/tabs"; -import { type ComponentProps, createElement, type ReactElement } from "react"; +import { IconArchive, IconInbox, IconPencil, IconSend, IconX } from "@tabler/icons-react"; +import { createElement } from "react"; /* * The three close policies side by side. Close the open tab in each strip and @@ -53,7 +54,7 @@ const Strip = ({ {(id) => ( - {createElement(TAB_ICONS[id] ?? InboxIcon)} + {createElement(TAB_ICONS[id] ?? IconInbox)} {id} @@ -62,7 +63,7 @@ const Strip = ({ aria-label={`Close ${id}`} className="grid size-5 shrink-0 cursor-pointer place-items-center rounded text-[#949494] transition-colors hover:bg-[#dcdcdc] hover:text-[#1a1a1a] dark:text-[#6f6f6f] dark:hover:bg-[#3d3d3d] dark:hover:text-[#fcfcfc]" > - + @@ -93,98 +94,12 @@ const tabClass = [ "dark:data-[selected]:bg-[#2d2d2d] dark:data-[selected]:text-[#fcfcfc]", ].join(" "); -const CloseIcon = (props: ComponentProps<"svg">) => ( - -); - /* Per-tab icons rather than one generic page glyph — a strip of identical icons carries no information, and the whole point of a tab icon is telling the tabs apart at a glance. */ -const TAB_ICONS: Record) => ReactElement> = { - Inbox: InboxIcon, - Drafts: PencilIcon, - Sent: SendIcon, - Archive: ArchiveIcon, +const TAB_ICONS: Record = { + Inbox: IconInbox, + Drafts: IconPencil, + Sent: IconSend, + Archive: IconArchive, }; - -function InboxIcon(props: ComponentProps<"svg">) { - return ( - - ); -} - -function PencilIcon(props: ComponentProps<"svg">) { - return ( - - ); -} - -function SendIcon(props: ComponentProps<"svg">) { - return ( - - ); -} - -function ArchiveIcon(props: ComponentProps<"svg">) { - return ( - - ); -} diff --git a/content/docs/primitives/tabs/demos/external.tsx b/content/docs/primitives/tabs/demos/external.tsx index 9a6ceb9..e4db5f0 100644 --- a/content/docs/primitives/tabs/demos/external.tsx +++ b/content/docs/primitives/tabs/demos/external.tsx @@ -1,7 +1,8 @@ "use client"; import { Tabs, type TabsStore, useTabsStore } from "@intentface/chat/tabs"; -import { type ComponentProps, createElement, type ReactElement, useState } from "react"; +import { IconArchive, IconInbox, IconPencil, IconSend, IconX } from "@tabler/icons-react"; +import { createElement, useState } from "react"; /* * Opening a tab from somewhere else in the app. @@ -30,7 +31,7 @@ export const ExternalTabs = () => { {(id) => ( - {createElement(TAB_ICONS[id] ?? InboxIcon)} + {createElement(TAB_ICONS[id] ?? IconInbox)} {id} @@ -38,7 +39,7 @@ export const ExternalTabs = () => { aria-label={`Close ${id}`} className="grid size-5 shrink-0 cursor-pointer place-items-center rounded text-[#949494] transition-colors hover:bg-[#dcdcdc] hover:text-[#1a1a1a] dark:text-[#6f6f6f] dark:hover:bg-[#3d3d3d] dark:hover:text-[#fcfcfc]" > - + @@ -62,7 +63,7 @@ const Launcher = ({ store }: { store: TabsStore }) => { const items = useTabsStore(store, (tabs) => tabs.items); return ( -

+
{DOCUMENTS.map((id) => ( + ))} +
+ +
+ + +
+ {/* The reserve the primitive publishes lands on the last child. */} + + {turns.map((turn, index) => ( + + + {turn.text} + + + ))} + +
+
+
+
+ +
+

{CAPTIONS[mode]}

+ +
+
+ ); +}; diff --git a/content/docs/primitives/thread/demos/basic.tsx b/content/docs/primitives/thread/demos/basic.tsx index 82e44f9..6e8b4ea 100644 --- a/content/docs/primitives/thread/demos/basic.tsx +++ b/content/docs/primitives/thread/demos/basic.tsx @@ -3,7 +3,8 @@ import { Composer, type ComposerSubmitData } from "@intentface/chat/composer"; import { Message } from "@intentface/chat/message"; import { Thread, useThread } from "@intentface/chat/thread"; -import { type ComponentProps, useState } from "react"; +import { IconArrowDown, IconArrowUp } from "@tabler/icons-react"; +import { useState } from "react"; type DemoMessage = { id: string; role: "user" | "assistant"; text: string }; @@ -73,7 +74,7 @@ export const Basic = () => { - + @@ -98,41 +99,7 @@ const ScrollButton = () => { aria-label="Scroll to latest" className="absolute -top-10 z-10 flex size-8 cursor-pointer items-center justify-center rounded-full border border-[#f0f0f0] bg-white text-[#686868] shadow-xs transition-colors hover:text-[#1a1a1a] dark:border-[#262626] dark:bg-[#181818] dark:text-[#9b9b9b] dark:hover:text-[#fcfcfc]" > - + ); }; - -const ArrowDownIcon = (props: ComponentProps<"svg">) => ( - -); - -const SendIcon = (props: ComponentProps<"svg">) => ( - -); diff --git a/content/docs/primitives/thread/demos/jump.tsx b/content/docs/primitives/thread/demos/jump.tsx new file mode 100644 index 0000000..17deadd --- /dev/null +++ b/content/docs/primitives/thread/demos/jump.tsx @@ -0,0 +1,86 @@ +"use client"; + +import { Message } from "@intentface/chat/message"; +import { Thread, useThread, useThreadVisibility } from "@intentface/chat/thread"; + +const TURNS = Array.from({ length: 14 }, (_, index) => ({ + id: `turn-${index + 1}`, + role: index % 2 === 0 ? ("user" as const) : ("assistant" as const), + title: `Turn ${index + 1}`, + text: + index % 2 === 0 + ? `Question ${index / 2 + 1}: how does this behave when the transcript is long?` + : "It resolves the row lazily by its attribute, so nothing is registered up front and a long transcript costs no more than a short one.", +})); + +/* + * Addressing a row without registering it. + * + * `scrollToMessage` finds a row by the `data-message-id` attribute you put on + * it. There is no wrapper part and no registry: rows are resolved lazily at + * call time, so a transcript of ten thousand turns costs the same as this one. + * + * `useThreadVisibility` is the other half. It reads the same attribute to + * report which rows are on screen, and it creates its observers on the first + * subscriber — a thread that never calls it pays nothing. + */ +export const Jump = () => ( +
+
+ + + + {TURNS.map((turn) => ( + + + {turn.title} + + + {turn.text} + + + ))} + + + + {/* Both panels live inside the Root, which is how they reach the + scroll context; neither is a part of the package. */} + + +
+
+); + +/** An outline that jumps, and highlights whichever row is being read. */ +const Outline = () => { + const { scrollToMessage } = useThread(); + const { currentMessageId } = useThreadVisibility(); + + return ( + + ); +}; diff --git a/packages/chat/src/attachments/attachments.tsx b/packages/chat/src/attachments/attachments.tsx index aad5f9b..e81bdad 100644 --- a/packages/chat/src/attachments/attachments.tsx +++ b/packages/chat/src/attachments/attachments.tsx @@ -86,6 +86,11 @@ export const matchesAccept = (file: File, accept: string): boolean => { export type AttachmentsRootProps = PrimitiveProps<"div">; +/** + * The tray container. Mount it only when there are items to show; it renders + * no layout of its own. + * Renders a `
` element. + */ export const AttachmentsRoot = ({ className, render, @@ -103,6 +108,11 @@ export type AttachmentsItemProps = PrimitiveProps<"div">; // Generic structural slot for one attachment. It carries no media taxonomy — // categorization (image/pdf/file, icons, thumbnails) belongs to the styled // layer, which reads the item's raw mediaType however it wants. +/** + * One attachment, as a structural slot with no media taxonomy of its own. + * Read the item's `mediaType` and decide what an image or a PDF looks like. + * Renders a `
` element. + */ export const AttachmentsItem = ({ className, render, @@ -121,6 +131,12 @@ export type AttachmentsRemoveProps = PrimitiveProps<"button"> & { filename?: string; }; +/** + * The removal affordance. Named "Remove attachment" by default, or + * "Remove {filename}" when `filename` is set, so a row of them does not + * announce identically. + * Renders a ` diff --git a/components/ai/reasoning.tsx b/components/ai/reasoning.tsx index 11eba2b..06c6425 100644 --- a/components/ai/reasoning.tsx +++ b/components/ai/reasoning.tsx @@ -1,13 +1,12 @@ "use client"; import { Reasoning as ReasoningPrimitive, useReasoning } from "@intentface/chat/reasoning"; +import { IconBrain, IconChevronDown } from "@tabler/icons-react"; import { AnimatePresence, motion } from "motion/react"; import { type ComponentProps, memo, type ReactNode } from "react"; -import { ChevronDownIcon } from "@/components/icons/chevron-down"; import { Markdown } from "@/components/ui/markdown"; import { splitReasoningByHeaders } from "@/lib/ai/message-info"; import { cn } from "@/lib/utils"; -import { BrainIcon } from "../icons/brain"; import { TextShimmer } from "../ui/text-shimmer"; export { useReasoning }; @@ -76,7 +75,7 @@ const ReasoningTrigger = memo( {children ?? ( <>
- +
- diff --git a/components/ai/thread.tsx b/components/ai/thread.tsx index a5915b8..7a5e4fc 100644 --- a/components/ai/thread.tsx +++ b/components/ai/thread.tsx @@ -7,13 +7,13 @@ import { useThread, useThreadVisibility, } from "@intentface/chat/thread"; +import { IconArrowDown } from "@tabler/icons-react"; import { AnimatePresence, motion } from "motion/react"; import type { ComponentProps } from "react"; import { memo, useCallback } from "react"; import Button from "@/components/ui/button"; import { ProgressiveBlur } from "@/components/ui/progressive-blur"; import { cn } from "@/lib/utils"; -import { ArrowDownIcon } from "../icons/arrow-down"; export { useThread, useThreadVisibility }; export type { ThreadAutoScrollMode, ThreadVisibilityState }; @@ -148,7 +148,7 @@ const ThreadScrollButton = ({ className, ...props }: ThreadScrollButtonProps) => onClick={handleScrollToBottom} className="rounded-full shadow-xs" > - + Latest diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx index 00fc546..4806273 100644 --- a/components/app-sidebar.tsx +++ b/components/app-sidebar.tsx @@ -1,17 +1,18 @@ "use client"; - +import { + IconBookFilled, + IconDotsVerticalFilled, + IconPlus, + IconTrashFilled, +} from "@tabler/icons-react"; import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; +import { GitHubIcon } from "@/components/icons/github"; import { IntentfaceLogo } from "@/components/icons/intentface-logo"; -import { PlusMediumIcon } from "@/components/icons/plus-medium"; -import { TrashIcon } from "@/components/icons/trash"; +import { NpmIcon } from "@/components/icons/npm"; import { Sidebar } from "@/components/ui/sidebar"; import { deleteChatInstance } from "@/lib/chat-instance"; import { useChatStore } from "@/lib/store/chat"; -import { BookIcon } from "./icons/book"; -import { DotGrid1x3VerticalTightIcon } from "./icons/dot-grid-1x3-vertical-tight"; -import { GitHubIcon } from "./icons/github"; -import { NpmIcon } from "./icons/npm"; import DropdownMenu from "./ui/dropdown-menu"; export const AppSidebar = () => { @@ -43,7 +44,7 @@ export const AppSidebar = () => { isActive={pathname === "/playground"} render={ - + New Chat } @@ -66,7 +67,7 @@ export const AppSidebar = () => { - + Delete } @@ -76,7 +77,7 @@ export const AppSidebar = () => { onClick={() => handleDelete(chat.id)} aria-label="Delete" > - + Delete Delete @@ -97,7 +98,7 @@ export const AppSidebar = () => { - + Docs } diff --git a/components/chat.tsx b/components/chat.tsx index 1aa1243..7fead9a 100644 --- a/components/chat.tsx +++ b/components/chat.tsx @@ -9,8 +9,19 @@ import { type MessageSegment, } from "@intentface/chat/message-utils"; import { isToolPart, type ToolPart, type UnknownPart } from "@intentface/chat/types"; +import { + IconAlertTriangleFilled, + IconBrain, + IconCheck, + IconChevronDown, + IconCircleFilled, + IconHelpCircleFilled, + IconQuoteFilled, + IconRefresh, + IconSandbox, + IconX, +} from "@tabler/icons-react"; import type { ChatStatus } from "ai"; -import { CircleIcon } from "lucide-react"; import { AnimatePresence, motion, stagger } from "motion/react"; import { useRouter } from "next/navigation"; import { @@ -37,15 +48,6 @@ import { Steps } from "@/components/ai/steps"; import { Thread } from "@/components/ai/thread"; import { ActiveTools, ToolsMenu } from "@/components/composer-tools"; import { Header } from "@/components/header"; -import { BrainIcon } from "@/components/icons/brain"; -import { CheckMarkMediumIcon } from "@/components/icons/check-mark-medium"; -import { ChevronDownIcon } from "@/components/icons/chevron-down"; -import { CircleQuestionmarkIcon } from "@/components/icons/circle-questionmark"; -import { CrossMediumIcon } from "@/components/icons/cross-medium"; -import { ExclamationTriangleIcon } from "@/components/icons/exclamation-triangle"; -import { OpenQuote2Icon } from "@/components/icons/open-quote-2"; -import { PlaygroundIcon } from "@/components/icons/playground"; -import { RefreshIcon } from "@/components/icons/refresh"; import { ModelSelector } from "@/components/model-selector"; import { PlaygroundSettings } from "@/components/playground-settings"; import { Markdown } from "@/components/ui/markdown"; @@ -128,10 +130,10 @@ export const useChatMessages = (): ChatMessagesValue => { type IconComponent = React.ComponentType<{ className?: string }>; const statusIcons: Record = { - complete: CheckMarkMediumIcon, - active: CircleIcon, - pending: CircleIcon, - error: ExclamationTriangleIcon, + complete: IconCheck, + active: IconCircleFilled, + pending: IconCircleFilled, + error: IconAlertTriangleFilled, }; // A timeline row: static when it has no detail, collapsible (icon morphs to a @@ -186,7 +188,7 @@ const TimelineStep = ({ - + {label} @@ -222,7 +224,7 @@ const TimelineAskUser = ({ part }: { part: ToolPart }) => { const { label, status, questions, answers, isComplete } = getAskUserStepInfo(part); return ( - +
{questions.map((q) => (
@@ -358,7 +360,7 @@ const InterleavedSteps = ({ {header} - + {segments.map((seg, i) => { @@ -374,7 +376,7 @@ const InterleavedSteps = ({ key={`r-${i}-${j}`} label={section.header ?? "Thinking"} status={streaming && j === sections.length - 1 ? "active" : "complete"} - icon={BrainIcon} + icon={IconBrain} > {section.body && ( @@ -523,7 +525,7 @@ const ChatMessageItem = memo( onClick={() => regenerate({ messageId: message.id })} tooltip="Regenerate" > - + )} @@ -966,13 +968,13 @@ const ChatInputInner = memo(({ panelState, status }: ChatInputInnerProps) => { "inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-ink-secondary", )} > - + Playground )} {selections.length > 0 && (
- + {selections.length} selection{selections.length === 1 ? "" : "s"} @@ -982,7 +984,7 @@ const ChatInputInner = memo(({ panelState, status }: ChatInputInnerProps) => { className="cursor-pointer rounded-full p-0.5 hover:bg-primary-bg-hover hover:text-ink-primary" onClick={clearSelections} > - +
)} diff --git a/components/composer-tools.tsx b/components/composer-tools.tsx index 25ed054..829f4f6 100644 --- a/components/composer-tools.tsx +++ b/components/composer-tools.tsx @@ -1,11 +1,7 @@ "use client"; +import { IconBrain, IconPaperclip, IconPlus, IconWorldFilled, IconX } from "@tabler/icons-react"; import { useComposer } from "@/components/ai/composer"; -import { BrainIcon } from "@/components/icons/brain"; -import { CrossMediumIcon } from "@/components/icons/cross-medium"; -import { GlobeIcon } from "@/components/icons/globe"; -import { PaperClipIcon } from "@/components/icons/paperclip"; -import { PlusMediumIcon } from "@/components/icons/plus-medium"; import Button from "@/components/ui/button"; import DropdownMenu from "@/components/ui/dropdown-menu"; import { IconButton } from "@/components/ui/icon-button"; @@ -28,8 +24,8 @@ export const ActiveTools = ({ tools, onToolsChange }: ToolToggleProps) => { onClick={() => onToolsChange({ ...tools, webSearch: false })} > - - + + Web Search @@ -43,8 +39,8 @@ export const ActiveTools = ({ tools, onToolsChange }: ToolToggleProps) => { onClick={() => onToolsChange({ ...tools, thinking: false })} > - - + + Thinking @@ -61,13 +57,13 @@ export const ToolsMenu = ({ tools, onToolsChange }: ToolToggleProps) => { - + } /> attachments.openFileDialog()}> - + Attach files @@ -75,13 +71,13 @@ export const ToolsMenu = ({ tools, onToolsChange }: ToolToggleProps) => { checked={tools.webSearch ?? false} onCheckedChange={(checked) => onToolsChange({ ...tools, webSearch: checked })} > - Web Search + Web Search onToolsChange({ ...tools, thinking: checked })} > - Thinking + Thinking diff --git a/components/docs/docs-search.tsx b/components/docs/docs-search.tsx index 03bb80d..baeabc6 100644 --- a/components/docs/docs-search.tsx +++ b/components/docs/docs-search.tsx @@ -1,7 +1,7 @@ "use client"; +import { IconSearch } from "@tabler/icons-react"; import { useDocsSearch } from "fumadocs-core/search/client"; -import { SearchIcon } from "lucide-react"; import Link from "next/link"; import { useEffect, useState } from "react"; import { Dialog } from "@/components/ui/dialog"; @@ -36,14 +36,14 @@ export const DocsSearch = () => { aria-label="Search docs (⌘K)" className="rounded-full" > - + } /> Search documentation
- + { return (
  • - + {node.name} - ( return (
  • {node.name}
  • @@ -128,7 +125,7 @@ const ExternalLink = ({ href, icon, label }: { href: string; icon: ReactNode; la href={href} target="_blank" rel="noreferrer" - className="flex h-8 items-center gap-2 rounded-md px-3 font-medium text-ink-secondary text-md transition-colors duration-0 hover:bg-secondary-bg-hover hover:text-ink-primary" + className="flex h-8 items-center gap-2 rounded-md px-2 font-medium text-ink-secondary text-md transition-colors duration-0 hover:bg-secondary-bg-hover hover:text-ink-primary" > {icon} {label} @@ -136,8 +133,8 @@ const ExternalLink = ({ href, icon, label }: { href: string; icon: ReactNode; la ); export const DocsSidebar = ({ tree }: DocsSidebarProps) => ( -
    diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx index 335b5d2..81e97d4 100644 --- a/components/ui/dropdown-menu.tsx +++ b/components/ui/dropdown-menu.tsx @@ -1,10 +1,8 @@ "use client"; import { Menu as MenuPrimitive } from "@base-ui/react/menu"; +import { IconCheck, IconChevronRight, IconCircleFilled } from "@tabler/icons-react"; import type { ComponentProps, ReactNode } from "react"; -import { ArrowTriangleRightIcon } from "@/components/icons/arrow-triangle-right"; -import { CheckMarkMediumIcon } from "@/components/icons/check-mark-medium"; -import { CircleIcon } from "@/components/icons/circle"; import { cn } from "@/lib/utils"; function DropdownMenuRoot({ ...props }: MenuPrimitive.Root.Props) { @@ -128,7 +126,7 @@ function DropdownMenuSubTrigger({ {...props} > {children} - + ); } @@ -187,7 +185,7 @@ function DropdownMenuCheckboxItem({ > - + {children} @@ -219,7 +217,7 @@ function DropdownMenuRadioItem({ > - + {children} diff --git a/components/ui/select.tsx b/components/ui/select.tsx index 930af61..9d79477 100644 --- a/components/ui/select.tsx +++ b/components/ui/select.tsx @@ -1,13 +1,10 @@ "use client"; import { Select as SelectPrimitive } from "@base-ui/react/select"; +import { IconCheck, IconChevronDown, IconChevronUp, IconSelector } from "@tabler/icons-react"; import { cva, type VariantProps } from "class-variance-authority"; import type * as React from "react"; import { cn } from "@/lib/utils"; -import { CheckMarkMediumIcon } from "../icons/check-mark-medium"; -import { ChevronDownMediumIcon } from "../icons/chevron-down-medium"; -import { ChevronGrabberVerticalIcon } from "../icons/chevron-grabber-vertical"; -import { ChevronTopMediumIcon } from "../icons/chevron-top-medium"; const selectTriggerVariants = cva( [ @@ -80,7 +77,7 @@ function SelectTrigger({ {...props} > {children} - } /> + } /> ); } @@ -196,7 +193,7 @@ const SelectItem = ({ className, children, ...props }: SelectPrimitive.Item.Prop
    - +
    @@ -234,7 +231,7 @@ const SelectScrollUpButton = ({ )} {...props} > - + ); }; @@ -259,7 +256,7 @@ const SelectScrollDownButton = ({ )} {...props} > - + ); }; diff --git a/components/ui/sidebar.tsx b/components/ui/sidebar.tsx index 39b18b1..f948daf 100644 --- a/components/ui/sidebar.tsx +++ b/components/ui/sidebar.tsx @@ -2,6 +2,7 @@ import { useRender } from "@base-ui/react/use-render"; import { SHELL_SIDEBAR_WIDTH_VAR, Shell, useShell } from "@intentface/chat/shell"; +import { IconLayoutSidebarFilled } from "@tabler/icons-react"; import { cva, type VariantProps } from "class-variance-authority"; import { type ComponentProps, @@ -12,7 +13,6 @@ import { useMemo, useState, } from "react"; -import { SidebarIcon } from "@/components/icons/sidebar"; import Drawer from "@/components/ui/drawer"; import Input from "@/components/ui/input"; import Separator from "@/components/ui/separator"; @@ -221,12 +221,11 @@ const SidebarRoot = ({ )} {...props} > -
    + {/* No right padding while flush: the viewport's own p-2 already supplies + the seam, and padding both sides of it would make that gap twice the + one at every screen edge. The floating card pads all four sides, + because then it has edges of its own. */} +
    {children}
    @@ -255,7 +254,7 @@ const SidebarTrigger = ({ className, onClick, ...props }: ComponentProps<"button className={cn("hover:bg-base-bg-hover", className)} {...props} > - + Toggle Sidebar ); @@ -274,7 +273,7 @@ const SidebarTrigger = ({ className, onClick, ...props }: ComponentProps<"button className={cn("hover:bg-base-bg-hover", className)} {...props} > - + Toggle Sidebar ) : ( @@ -332,7 +331,8 @@ const SidebarHeader = ({ className, ...props }: ComponentProps<"div">) => { return (
    ); diff --git a/lib/ai/chip-icons.tsx b/lib/ai/chip-icons.tsx index 72bcf59..1e06864 100644 --- a/lib/ai/chip-icons.tsx +++ b/lib/ai/chip-icons.tsx @@ -1,24 +1,26 @@ +import { + IconBrain, + IconBugFilled, + IconChartBar, + IconCode, + IconFileTextFilled, + IconMessageChatbotFilled, + IconPhotoFilled, + IconTableFilled, + IconWorldFilled, +} from "@tabler/icons-react"; import type { ReactNode } from "react"; -import { BrainIcon } from "@/components/icons/brain"; -import { BubbleWideSparkleIcon } from "@/components/icons/bubble-wide-sparkle"; -import { BugIcon } from "@/components/icons/bug"; -import { CodeIcon } from "@/components/icons/code"; -import { FileChartIcon } from "@/components/icons/file-chart"; -import { FileTextIcon } from "@/components/icons/file-text"; -import { GlobeIcon } from "@/components/icons/globe"; -import { ImageAltIcon } from "@/components/icons/image-alt"; -import { SpreadsheetIcon } from "@/components/icons/spreadsheet"; export const CHIP_ICONS = { - brain: , - bug: , - bubbleWideSparkle: , - code: , - fileChart: , - fileText: , - globe: , - imageAlt: , - spreadsheet: , + brain: , + bug: , + bubbleWideSparkle: , + code: , + fileChart: , + fileText: , + globe: , + imageAlt: , + spreadsheet: , } satisfies Record; export type ChipIconKey = keyof typeof CHIP_ICONS; diff --git a/package.json b/package.json index a03ea9f..2ebba3b 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@ai-sdk/react": "^3.0.220", "@base-ui/react": "^1.6.0", "@intentface/chat": "workspace:*", + "@tabler/icons-react": "^3.46.0", "ai": "^6.0.218", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", From 9f4deb3918fce6d59303d1c31d3bb0f158547d9f Mon Sep 17 00:00:00 2001 From: Rasmus Viloma Date: Tue, 15 Sep 2026 00:27:39 +0300 Subject: [PATCH 04/20] docs(handbook): cut the accessibility page back to the boundary --- content/docs/handbook/accessibility.mdx | 242 ++++++------------------ 1 file changed, 58 insertions(+), 184 deletions(-) diff --git a/content/docs/handbook/accessibility.mdx b/content/docs/handbook/accessibility.mdx index 802f858..3dc0939 100644 --- a/content/docs/handbook/accessibility.mdx +++ b/content/docs/handbook/accessibility.mdx @@ -1,195 +1,69 @@ --- title: Accessibility -description: The accessibility features the primitives provide, and what your application still has to supply. +description: What the primitives guarantee, and what your application still has to supply. --- -The primitives handle ARIA attributes, roles, keyboard navigation, and focus -management. Because the package renders no styles, anything visual — contrast, -focus indication — is your application's responsibility. - -## Keyboard navigation +The primitives own roles, relationships, keyboard behaviour and focus movement. +They render no styles, so everything visual is yours — and some of it is not +optional. + +## What you have to supply + +- **Focus indication.** Focus moves correctly; nothing paints it. Style + `:focus-visible` yourself, and remember that in command lists and ask-user + options the highlight *is* the indicator, so a faint highlight is a missing + focus ring rather than a soft hover. +- **Contrast.** No colour ships with the package. +- **Speaker identity.** A message's `role` reaches the DOM as `data-role` only. + Alignment and colour carry it to sighted readers and to nobody else, so add a + visually hidden prefix or an `aria-label`. +- **Status copy.** Validation emits a code, not a message, and nothing announces + "generating" beyond a button label. Add your own `role="status"` region where + in-flight state matters, and `role="alert"` for failures. +- **Anything you build in a seam.** A surface lifted through a render prop + inherits that pattern's obligations — a hover preview still has to open on + focus and close on Escape. + +## Keyboard The primitives follow the [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/). -The composer's editor interprets keys by mode: an open command list, or an active -ask-user flow, takes priority over normal typing. A primitive that claims keys of -its own documents them in a key table on its page; one that relies on native focus -order does not. - -Anything draggable is also operable from the keyboard. The shell's grip resizes -the sidebar with the arrow keys once focused, so no layout a visitor can reach -with a pointer is closed to them without one. - -A strip or a tree is one tab stop, not one per item. Focus follows the arrow -keys without selecting, which is manual activation; a primitive that should -select as focus moves says so through a prop rather than by default. The nav is a roving-tabindex widget: -exactly one row is tabbable and the arrow keys move focus between rows. Before -that state is seeded — a server render, or the frame before hydration — the -active row carries the tab stop, which keeps a row rendered as a real anchor -reachable without JavaScript. A field inside the tree keeps its own arrow keys, -or its caret could never move. - -A scroll surface has to be reachable before it can be scrolled. The thread's -viewport is a focusable `role="region"` named "Messages" by default, so a -keyboard user can Tab to it and use the usual keys. Only the upward keys — -`ArrowUp`, `PageUp` and `Home` — are intercepted, to release auto-follow; -scrolling down never does, because releasing it at the bottom would leave the -view unfollowed while pinned there. - -Announce additions, not mutations. The thread's content column is a `role="log"` -with `aria-relevant="additions"`, so a turn announces when its row is added and -tokens streaming into an existing row deliberately do not re-announce. -Token-by-token narration is noise. If an end-of-response announcement is wanted, -add your own `role="status"` region that flips on completion. - -Motion preferences are honoured for programmatic scrolls. Anything the thread -requests as smooth, including auto-follow, downgrades to instant when the -operating system asks for reduced motion. - -Command lists and ask-user options move a highlight rather than DOM focus, so the -caret stays in the editor while you navigate. Arrowing past the end of a list -keeps focus in place; arrowing up past the first ask-user option returns to the -editor. - -## Focus management - -Focus is managed automatically after interaction — the composer restores the -caret after selecting a command item, and ask-user recovers arrow navigation if a -click elsewhere drops focus to the body. - -In command lists and ask-user options the highlight *is* the focus indication — -focus follows it rather than moving separately, so styling the highlight faintly -removes the focus indicator rather than softening a hover effect. - -## Roles and relationships - -The composer's editor is wired to its command list as a combobox: -`aria-autocomplete="list"` and `aria-haspopup="listbox"`, plus `aria-controls` -and `aria-activedescendant` while a popup is open. The popup is a `listbox` -named "Suggestions" whose rows carry stable ids and `aria-selected`; selection -stays in the editor, so rows are never tab stops. Grouped lists wrap in -`role="group"` named by their label, async resolution sets `aria-busy`, and the -empty state is a `role="status"` region. - -That pattern deviates from the APG combobox in one place, deliberately. -`aria-expanded` is omitted because ARIA 1.2 forbids it on `textbox`, and moving -to `role="combobox"` would forbid `aria-multiline`, which matters more for a -chat field that wraps. The popup announces through `aria-haspopup` and live -`aria-activedescendant` narration instead, and Tab selects the highlighted -option rather than moving focus. - -Ask-user renders a labelled `radiogroup`, or `role="group"` with checkboxes for -multi-select. Each option is the real control, holding the group's single tab -stop through roving `tabindex`, so never nest an interactive control inside one: -the option *is* the control, and the composer's question mode treats native -inputs as foreign editables. Disabled options are announced but skipped by -highlight and selection. - -A placeholder overlay is decoration. The composer's is `aria-hidden`, and the -string reaches assistive technology through `aria-placeholder` instead — so when -rich `children` replace the string visually, keep the `placeholder` string -alongside or the hint stops announcing. - -Clicking chrome should not create a tab stop. The composer's container is a -mouse-only focus passthrough: clicking it focuses the editor, clicks on nested -buttons and links pass through, and it carries no role, so keyboard users tab -straight to the editor. - -`Steps` marks the active item with `aria-current="step"`. A disclosure built for -streaming says so while it runs: `Reasoning.Root` carries `aria-busy` until -`isStreaming` flips false, so assistive technology knows the text underneath is -still arriving rather than finished. - -Disclosure controls announce both their state and what they govern: the shell's -trigger is a ` diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx index 4806273..843b7df 100644 --- a/components/app-sidebar.tsx +++ b/components/app-sidebar.tsx @@ -1,15 +1,15 @@ "use client"; import { - IconBookFilled, - IconDotsVerticalFilled, + IconBook, + IconBrandGithub, + IconBrandNpm, + IconDotsVertical, IconPlus, - IconTrashFilled, + IconTrash, } from "@tabler/icons-react"; import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; -import { GitHubIcon } from "@/components/icons/github"; import { IntentfaceLogo } from "@/components/icons/intentface-logo"; -import { NpmIcon } from "@/components/icons/npm"; import { Sidebar } from "@/components/ui/sidebar"; import { deleteChatInstance } from "@/lib/chat-instance"; import { useChatStore } from "@/lib/store/chat"; @@ -67,7 +67,7 @@ export const AppSidebar = () => { - + Delete } @@ -77,7 +77,7 @@ export const AppSidebar = () => { onClick={() => handleDelete(chat.id)} aria-label="Delete" > - + Delete Delete @@ -98,7 +98,7 @@ export const AppSidebar = () => { - + Docs } @@ -112,7 +112,7 @@ export const AppSidebar = () => { target="_blank" rel="noreferrer" > - + GitHub } @@ -126,7 +126,7 @@ export const AppSidebar = () => { target="_blank" rel="noreferrer" > - + npm } diff --git a/components/chat.tsx b/components/chat.tsx index 7fead9a..c92c696 100644 --- a/components/chat.tsx +++ b/components/chat.tsx @@ -10,13 +10,13 @@ import { } from "@intentface/chat/message-utils"; import { isToolPart, type ToolPart, type UnknownPart } from "@intentface/chat/types"; import { - IconAlertTriangleFilled, + IconAlertTriangle, IconBrain, IconCheck, IconChevronDown, - IconCircleFilled, - IconHelpCircleFilled, - IconQuoteFilled, + IconCircle, + IconHelpCircle, + IconQuote, IconRefresh, IconSandbox, IconX, @@ -131,9 +131,9 @@ type IconComponent = React.ComponentType<{ className?: string }>; const statusIcons: Record = { complete: IconCheck, - active: IconCircleFilled, - pending: IconCircleFilled, - error: IconAlertTriangleFilled, + active: IconCircle, + pending: IconCircle, + error: IconAlertTriangle, }; // A timeline row: static when it has no detail, collapsible (icon morphs to a @@ -224,7 +224,7 @@ const TimelineAskUser = ({ part }: { part: ToolPart }) => { const { label, status, questions, answers, isComplete } = getAskUserStepInfo(part); return ( - +
    {questions.map((q) => (
    @@ -612,7 +612,7 @@ const MENTION_ITEMS: CommandItemData[] = [ { value: "quarterly-report", label: "Q4 Quarterly Report", - icon: "fileText", + icon: "fileChart", }, { value: "meeting-notes", @@ -622,7 +622,7 @@ const MENTION_ITEMS: CommandItemData[] = [ { value: "product-roadmap", label: "Product Roadmap", - icon: "spreadsheet", + icon: "map", }, { value: "brand-guidelines", @@ -632,7 +632,7 @@ const MENTION_ITEMS: CommandItemData[] = [ { value: "api-documentation", label: "API Documentation", - icon: "fileChart", + icon: "code", }, { value: "screenshot-dashboard", @@ -974,7 +974,7 @@ const ChatInputInner = memo(({ panelState, status }: ChatInputInnerProps) => { )} {selections.length > 0 && (
    - + {selections.length} selection{selections.length === 1 ? "" : "s"} diff --git a/components/composer-tools.tsx b/components/composer-tools.tsx index 829f4f6..a5ddf8c 100644 --- a/components/composer-tools.tsx +++ b/components/composer-tools.tsx @@ -1,5 +1,5 @@ "use client"; -import { IconBrain, IconPaperclip, IconPlus, IconWorldFilled, IconX } from "@tabler/icons-react"; +import { IconBrain, IconPaperclip, IconPlus, IconWorld, IconX } from "@tabler/icons-react"; import { useComposer } from "@/components/ai/composer"; import Button from "@/components/ui/button"; @@ -24,7 +24,7 @@ export const ActiveTools = ({ tools, onToolsChange }: ToolToggleProps) => { onClick={() => onToolsChange({ ...tools, webSearch: false })} > - + Web Search @@ -71,7 +71,7 @@ export const ToolsMenu = ({ tools, onToolsChange }: ToolToggleProps) => { checked={tools.webSearch ?? false} onCheckedChange={(checked) => onToolsChange({ ...tools, webSearch: checked })} > - Web Search + Web Search ) => { - return ( - - - - ); -}; diff --git a/components/icons/npm.tsx b/components/icons/npm.tsx deleted file mode 100644 index 976615e..0000000 --- a/components/icons/npm.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import type { SVGProps } from "react"; - -export const NpmIcon = (props: SVGProps) => { - return ( - - - - ); -}; diff --git a/components/playground-settings.tsx b/components/playground-settings.tsx index 580c74b..62f685c 100644 --- a/components/playground-settings.tsx +++ b/components/playground-settings.tsx @@ -1,12 +1,12 @@ "use client"; import { - IconAdjustmentsHorizontalFilled, - IconDeviceDesktopFilled, + IconAdjustmentsHorizontal, + IconDeviceDesktop, IconForms, - IconLayoutListFilled, - IconMoonFilled, - IconSettingsFilled, - IconSunFilled, + IconLayoutList, + IconMoon, + IconSettings, + IconSun, } from "@tabler/icons-react"; // Playground settings — a Linear-style display-options popover behind a single @@ -122,11 +122,11 @@ const CUSTOM_PRESET_VALUE = "__custom__"; const MODE_OPTIONS: ReadonlyArray<{ value: InterfaceThemeMode; label: string; - Icon: typeof IconSunFilled; + Icon: typeof IconSun; }> = [ - { value: "light", label: "Light", Icon: IconSunFilled }, - { value: "dark", label: "Dark", Icon: IconMoonFilled }, - { value: "system", label: "System", Icon: IconDeviceDesktopFilled }, + { value: "light", label: "Light", Icon: IconSun }, + { value: "dark", label: "Dark", Icon: IconMoon }, + { value: "system", label: "System", Icon: IconDeviceDesktop }, ]; const ThemeTab = () => { @@ -518,8 +518,8 @@ const KeyTab = () => { }; const PLAYGROUND_TABS = [ - { value: "theme", label: "Theme", Icon: IconAdjustmentsHorizontalFilled, content: }, - { value: "thread", label: "Thread", Icon: IconLayoutListFilled, content: }, + { value: "theme", label: "Theme", Icon: IconAdjustmentsHorizontal, content: }, + { value: "thread", label: "Thread", Icon: IconLayoutList, content: }, { value: "composer", label: "Composer", Icon: IconForms, content: }, { value: "key", label: "Key", Icon: OpenAIIcon, content: }, ] as const; @@ -572,7 +572,7 @@ export const PlaygroundSettings = () => { /> } > - + - + {children} diff --git a/components/ui/sidebar.tsx b/components/ui/sidebar.tsx index f948daf..52b130c 100644 --- a/components/ui/sidebar.tsx +++ b/components/ui/sidebar.tsx @@ -2,7 +2,7 @@ import { useRender } from "@base-ui/react/use-render"; import { SHELL_SIDEBAR_WIDTH_VAR, Shell, useShell } from "@intentface/chat/shell"; -import { IconLayoutSidebarFilled } from "@tabler/icons-react"; +import { IconLayoutSidebar } from "@tabler/icons-react"; import { cva, type VariantProps } from "class-variance-authority"; import { type ComponentProps, @@ -254,7 +254,7 @@ const SidebarTrigger = ({ className, onClick, ...props }: ComponentProps<"button className={cn("hover:bg-base-bg-hover", className)} {...props} > - + Toggle Sidebar ); @@ -273,7 +273,7 @@ const SidebarTrigger = ({ className, onClick, ...props }: ComponentProps<"button className={cn("hover:bg-base-bg-hover", className)} {...props} > - + Toggle Sidebar ) : ( diff --git a/lib/ai/chip-icons.tsx b/lib/ai/chip-icons.tsx index 1e06864..40c07d6 100644 --- a/lib/ai/chip-icons.tsx +++ b/lib/ai/chip-icons.tsx @@ -1,26 +1,33 @@ import { IconBrain, - IconBugFilled, + IconBug, IconChartBar, IconCode, - IconFileTextFilled, - IconMessageChatbotFilled, - IconPhotoFilled, - IconTableFilled, - IconWorldFilled, + IconFileText, + IconMap2, + IconMessageChatbot, + IconPhoto, + IconTable, + IconWorld, } from "@tabler/icons-react"; import type { ReactNode } from "react"; +/* + * Outlined throughout. Brain, code and chart have no filled variant in Tabler, + * and a set where three of ten are hollow reads as a mistake rather than a + * choice — so the whole set stays outlined. + */ export const CHIP_ICONS = { brain: , - bug: , - bubbleWideSparkle: , + bug: , + bubbleWideSparkle: , code: , fileChart: , - fileText: , - globe: , - imageAlt: , - spreadsheet: , + fileText: , + globe: , + imageAlt: , + map: , + spreadsheet: , } satisfies Record; export type ChipIconKey = keyof typeof CHIP_ICONS; From 9a6975c4ed6c1cbeabdb18c77738c37056fbf228 Mon Sep 17 00:00:00 2001 From: Rasmus Viloma Date: Tue, 15 Sep 2026 00:50:10 +0300 Subject: [PATCH 06/20] fix(docs): align the reference tables and surface tokens --- components/docs/attributes-table.tsx | 126 +++++++++++++++----- components/docs/component-preview-frame.tsx | 6 +- components/docs/installation-block-tabs.tsx | 18 +-- components/docs/keys-table.tsx | 4 +- components/docs/props-table.tsx | 14 +-- components/docs/values-table.tsx | 4 +- 6 files changed, 118 insertions(+), 54 deletions(-) diff --git a/components/docs/attributes-table.tsx b/components/docs/attributes-table.tsx index d314dc3..a6d51ab 100644 --- a/components/docs/attributes-table.tsx +++ b/components/docs/attributes-table.tsx @@ -1,4 +1,9 @@ -import type { ReactNode } from "react"; +"use client"; + +import { IconChevronDown } from "@tabler/icons-react"; +import { motion } from "motion/react"; +import { type ReactNode, useState } from "react"; +import { cn } from "@/lib/utils"; export type AttributeRow = { attribute: string; @@ -11,10 +16,9 @@ type AttributesTableProps = { }; // Hand-authored data-attribute reference — the styling hooks a part emits. -// Fixed-width columns match PropsTable so the two stay visually aligned down the -// page. Not collapsible: the description is the essential content here (no -// "default" to defer), so it stays inline. The Values column is omitted when no -// row provides one (e.g. keyboard shortcut tables). +// Built exactly like PropsTable: collapsed shows the attribute and its values, +// expanding reveals the description. The two sit next to each other in every +// API reference, so they read as one control rather than two. export const AttributesTable = ({ rows }: AttributesTableProps) => { const hasValues = rows.some((row) => row.values); @@ -23,40 +27,104 @@ export const AttributesTable = ({ rows }: AttributesTableProps) => { - {hasValues ? : null} - + + - + - {hasValues ? ( - - ) : null} - + + {rows.map((row) => ( - - - {hasValues ? ( - - ) : null} - - + ))}
    AttributeValuesDescriptionValues + Details +
    - {row.attribute} - - {row.values ? ( - - {row.values} - - ) : ( - — - )} - {row.description}
    ); }; + +const AttributeTableRow = ({ row, hasValues }: { row: AttributeRow; hasValues: boolean }) => { + const [open, setOpen] = useState(false); + + return ( + <> + setOpen((current) => !current)} + > + + {row.attribute} + + + {row.values ? ( + {row.values} + ) : ( + {hasValues ? "—" : ""} + )} + + +
    + +
    + + + + + +
    + + {row.attribute} + + + {row.description} + + + {row.values ? ( + {row.values} + ) : ( + — + )} + +
    +
    + + + + ); +}; + +// Mirrors PropsTable's detail grid, so an expanded attribute and an expanded +// prop line up with each other down the page. +const DetailRow = ({ label, children }: { label: string; children: ReactNode }) => ( +
    +
    {label}
    +
    {children}
    +
    +); diff --git a/components/docs/component-preview-frame.tsx b/components/docs/component-preview-frame.tsx index 658b68e..5b7e1e9 100644 --- a/components/docs/component-preview-frame.tsx +++ b/components/docs/component-preview-frame.tsx @@ -15,7 +15,7 @@ export const ComponentPreviewFrame = ({ preview, code }: ComponentPreviewFramePr return (
    -
    +
    {(["preview", "code"] as const).map((value) => (
    {current.code}
    diff --git a/components/docs/keys-table.tsx b/components/docs/keys-table.tsx index 1f82176..3b5ea43 100644 --- a/components/docs/keys-table.tsx +++ b/components/docs/keys-table.tsx @@ -22,7 +22,7 @@ export const KeysTable = ({ rows }: KeysTableProps) => ( - + Key Description @@ -31,7 +31,7 @@ export const KeysTable = ({ rows }: KeysTableProps) => ( {rows.map((row) => ( - + {row.keys} diff --git a/components/docs/props-table.tsx b/components/docs/props-table.tsx index 001234d..980240e 100644 --- a/components/docs/props-table.tsx +++ b/components/docs/props-table.tsx @@ -29,7 +29,7 @@ export const PropsTable = ({ rows }: PropsTableProps) => ( - + Prop Type Default @@ -97,15 +97,7 @@ const PropsRow = ({ row }: { row: PropRow }) => { }} className="overflow-hidden" > - +
    {row.name} @@ -124,7 +116,7 @@ const PropsRow = ({ row }: { row: PropRow }) => { — )} - +
    diff --git a/components/docs/values-table.tsx b/components/docs/values-table.tsx index 8b69c59..9f5fce3 100644 --- a/components/docs/values-table.tsx +++ b/components/docs/values-table.tsx @@ -22,7 +22,7 @@ export const ValuesTable = ({ rows }: ValuesTableProps) => ( - + Value Description @@ -34,7 +34,7 @@ export const ValuesTable = ({ rows }: ValuesTableProps) => (
    {row.value} {row.default ? ( - + default ) : null} From 7a79f2b727b0d8a3b644bffb3a863d4e62448ac1 Mon Sep 17 00:00:00 2001 From: Rasmus Viloma Date: Wed, 7 Oct 2026 22:32:30 +0300 Subject: [PATCH 07/20] refactor(app): swap Tabler icons for Keyline outlines --- bun.lock | 5 +++- components/ai/composer.tsx | 4 +-- components/ai/message.tsx | 17 ++++-------- components/ai/thread.tsx | 4 +-- components/app-sidebar.tsx | 19 +++++-------- components/composer-tools.tsx | 18 ++++++------- components/docs/attributes-table.tsx | 4 +-- components/docs/docs-search.tsx | 6 ++--- components/docs/docs-sidebar.tsx | 6 +++-- components/docs/docs-theme-toggle.tsx | 4 +-- components/docs/installation-block-tabs.tsx | 8 ++---- components/docs/props-table.tsx | 4 +-- components/ui/sidebar.tsx | 6 ++--- .../primitives/attachments/demos/basic.tsx | 6 ++--- .../primitives/attachments/demos/dropzone.tsx | 4 +-- content/docs/primitives/chip/demos/basic.tsx | 4 +-- .../composer/demos/ask-user-flow.tsx | 4 +-- .../primitives/composer/demos/attachments.tsx | 8 +++--- .../docs/primitives/composer/demos/basic.tsx | 4 +-- .../primitives/composer/demos/commands.tsx | 4 +-- .../primitives/composer/demos/controlled.tsx | 4 +-- .../primitives/composer/demos/popover.tsx | 4 +-- .../docs/primitives/composer/demos/store.tsx | 4 +-- .../docs/primitives/message/demos/basic.tsx | 4 +-- .../docs/primitives/message/demos/chips.tsx | 8 +++--- content/docs/primitives/nav/demos/basic.tsx | 18 ++++++------- .../docs/primitives/nav/demos/collapse.tsx | 4 +-- .../docs/primitives/nav/demos/external.tsx | 4 +-- content/docs/primitives/nav/demos/guides.tsx | 8 +++--- .../docs/primitives/reasoning/demos/basic.tsx | 6 ++--- .../primitives/reasoning/demos/streaming.tsx | 6 ++--- content/docs/primitives/shell/demos/basic.tsx | 20 +++++--------- content/docs/primitives/steps/demos/basic.tsx | 12 ++++----- .../docs/primitives/steps/demos/status.tsx | 10 +++---- .../docs/primitives/tabs/demos/anchored.tsx | 27 ++++++------------- content/docs/primitives/tabs/demos/basic.tsx | 8 +++--- .../docs/primitives/tabs/demos/closing.tsx | 16 +++++------ .../docs/primitives/tabs/demos/external.tsx | 16 +++++------ .../docs/primitives/thread/demos/basic.tsx | 6 ++--- package.json | 1 + 40 files changed, 149 insertions(+), 176 deletions(-) diff --git a/bun.lock b/bun.lock index 8fad39a..b1684a7 100644 --- a/bun.lock +++ b/bun.lock @@ -10,6 +10,7 @@ "@ai-sdk/react": "^3.0.220", "@base-ui/react": "^1.6.0", "@intentface/chat": "workspace:*", + "@keyline-icons/react": "^1.4.0", "@tabler/icons-react": "^3.46.0", "ai": "^6.0.218", "class-variance-authority": "^0.7.1", @@ -47,7 +48,7 @@ }, "packages/chat": { "name": "@intentface/chat", - "version": "0.3.0", + "version": "0.5.0", "dependencies": { "@floating-ui/dom": "^1.7.6", "nanoid": "^5.1.11", @@ -285,6 +286,8 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@keyline-icons/react": ["@keyline-icons/react@1.4.0", "", { "peerDependencies": { "react": ">=18" } }, "sha512-zpeRzPHRFQcSEC5qBM5LYE9hNePkM2wMGBAgD35vOSoXMghSLndeYrAQovjsFIPn0cDxg7EVJoFx3pga5QdmVg=="], + "@manypkg/find-root": ["@manypkg/find-root@1.1.0", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@types/node": "^12.7.1", "find-up": "^4.1.0", "fs-extra": "^8.1.0" } }, "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA=="], "@manypkg/get-packages": ["@manypkg/get-packages@1.1.3", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@changesets/types": "^4.0.1", "@manypkg/find-root": "^1.1.0", "fs-extra": "^8.1.0", "globby": "^11.0.0", "read-yaml-file": "^1.1.0" } }, "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A=="], diff --git a/components/ai/composer.tsx b/components/ai/composer.tsx index 4679665..fca0f82 100644 --- a/components/ai/composer.tsx +++ b/components/ai/composer.tsx @@ -1,5 +1,5 @@ "use client"; -import { IconArrowUp, IconPlayerStop } from "@tabler/icons-react"; +import { ArrowUp, Stop } from "@keyline-icons/react"; // Styled composer — thin wrappers over @intentface/chat/composer. Behavior // (editor, store, machines, command plumbing) lives in the package; this file @@ -335,7 +335,7 @@ const ComposerSubmit = ({ transition={{ duration: 0.15 }} className="flex items-center justify-center" > - {isGenerating ? : (children ?? )} + {isGenerating ? : (children ?? )} diff --git a/components/ai/message.tsx b/components/ai/message.tsx index c203f83..f10bf51 100644 --- a/components/ai/message.tsx +++ b/components/ai/message.tsx @@ -7,14 +7,7 @@ import { useMessageSelection, useMessageSelectionScope, } from "@intentface/chat/message"; -import { - IconCheck, - IconCopy, - IconFile, - IconMessage, - IconPaperclip, - IconPlayerStop, -} from "@tabler/icons-react"; +import { Check, Copy, File, MessageSquare, Paperclip, Stop } from "@keyline-icons/react"; import { motion } from "motion/react"; import Image from "next/image"; import { type ComponentProps, useMemo } from "react"; @@ -222,7 +215,7 @@ const MessageStopped = ({ className, ...props }: ComponentProps<"div">) => ( {...props} > - + Stopped
    @@ -258,7 +251,7 @@ const MessageCopy = ({ className={className} {...props} > - {isCopied ? : } + {isCopied ? : } } /> @@ -285,7 +278,7 @@ type MessageAttachmentProps = { const MessageAttachment = ({ attachment, className, ...props }: MessageAttachmentProps) => { const mediaType = attachment.mediaType ?? ""; const filename = attachment.filename ?? "Attachment"; - const Icon = isPdfAttachment(mediaType) ? IconFile : IconPaperclip; + const Icon = isPdfAttachment(mediaType) ? File : Paperclip; return (
    { window.getSelection()?.removeAllRanges(); }} > - + Add to chat diff --git a/components/ai/thread.tsx b/components/ai/thread.tsx index 7a5e4fc..fe92a5d 100644 --- a/components/ai/thread.tsx +++ b/components/ai/thread.tsx @@ -7,7 +7,7 @@ import { useThread, useThreadVisibility, } from "@intentface/chat/thread"; -import { IconArrowDown } from "@tabler/icons-react"; +import { ArrowDown } from "@keyline-icons/react"; import { AnimatePresence, motion } from "motion/react"; import type { ComponentProps } from "react"; import { memo, useCallback } from "react"; @@ -148,7 +148,7 @@ const ThreadScrollButton = ({ className, ...props }: ThreadScrollButtonProps) => onClick={handleScrollToBottom} className="rounded-full shadow-xs" > - + Latest diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx index 843b7df..6369528 100644 --- a/components/app-sidebar.tsx +++ b/components/app-sidebar.tsx @@ -1,12 +1,7 @@ "use client"; -import { - IconBook, - IconBrandGithub, - IconBrandNpm, - IconDotsVertical, - IconPlus, - IconTrash, -} from "@tabler/icons-react"; +import { Bin, BookOpen, MoreVertical, Plus } from "@keyline-icons/react"; +// Keyline has no brand icons, so these two stay on Tabler. +import { IconBrandGithub, IconBrandNpm } from "@tabler/icons-react"; import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; import { IntentfaceLogo } from "@/components/icons/intentface-logo"; @@ -44,7 +39,7 @@ export const AppSidebar = () => { isActive={pathname === "/playground"} render={ - + New Chat } @@ -67,7 +62,7 @@ export const AppSidebar = () => { - + Delete } @@ -77,7 +72,7 @@ export const AppSidebar = () => { onClick={() => handleDelete(chat.id)} aria-label="Delete" > - + Delete Delete @@ -98,7 +93,7 @@ export const AppSidebar = () => { - + Docs } diff --git a/components/composer-tools.tsx b/components/composer-tools.tsx index a5ddf8c..4021509 100644 --- a/components/composer-tools.tsx +++ b/components/composer-tools.tsx @@ -1,5 +1,5 @@ "use client"; -import { IconBrain, IconPaperclip, IconPlus, IconWorld, IconX } from "@tabler/icons-react"; +import { Brain, Globe, Paperclip, Plus, X } from "@keyline-icons/react"; import { useComposer } from "@/components/ai/composer"; import Button from "@/components/ui/button"; @@ -24,8 +24,8 @@ export const ActiveTools = ({ tools, onToolsChange }: ToolToggleProps) => { onClick={() => onToolsChange({ ...tools, webSearch: false })} > - - + + Web Search @@ -39,8 +39,8 @@ export const ActiveTools = ({ tools, onToolsChange }: ToolToggleProps) => { onClick={() => onToolsChange({ ...tools, thinking: false })} > - - + + Thinking @@ -57,13 +57,13 @@ export const ToolsMenu = ({ tools, onToolsChange }: ToolToggleProps) => { - + } /> attachments.openFileDialog()}> - + Attach files @@ -71,13 +71,13 @@ export const ToolsMenu = ({ tools, onToolsChange }: ToolToggleProps) => { checked={tools.webSearch ?? false} onCheckedChange={(checked) => onToolsChange({ ...tools, webSearch: checked })} > - Web Search + Web Search onToolsChange({ ...tools, thinking: checked })} > - Thinking + Thinking diff --git a/components/docs/attributes-table.tsx b/components/docs/attributes-table.tsx index a6d51ab..7681770 100644 --- a/components/docs/attributes-table.tsx +++ b/components/docs/attributes-table.tsx @@ -1,6 +1,6 @@ "use client"; -import { IconChevronDown } from "@tabler/icons-react"; +import { ChevronDown } from "@keyline-icons/react"; import { motion } from "motion/react"; import { type ReactNode, useState } from "react"; import { cn } from "@/lib/utils"; @@ -80,7 +80,7 @@ const AttributeTableRow = ({ row, hasValues }: { row: AttributeRow; hasValues: b setOpen((current) => !current); }} > - diff --git a/components/docs/docs-search.tsx b/components/docs/docs-search.tsx index baeabc6..86bbf4c 100644 --- a/components/docs/docs-search.tsx +++ b/components/docs/docs-search.tsx @@ -1,6 +1,6 @@ "use client"; -import { IconSearch } from "@tabler/icons-react"; +import { Search } from "@keyline-icons/react"; import { useDocsSearch } from "fumadocs-core/search/client"; import Link from "next/link"; import { useEffect, useState } from "react"; @@ -36,14 +36,14 @@ export const DocsSearch = () => { aria-label="Search docs (⌘K)" className="rounded-full" > - + } /> Search documentation
    - + {node.name} - { onClick={() => setMode(next)} className="rounded-full" > - {resolvedMode === "dark" ? : } + {resolvedMode === "dark" ? : } ); }; diff --git a/components/docs/installation-block-tabs.tsx b/components/docs/installation-block-tabs.tsx index 1174e5f..fa4166c 100644 --- a/components/docs/installation-block-tabs.tsx +++ b/components/docs/installation-block-tabs.tsx @@ -1,6 +1,6 @@ "use client"; -import { IconCheck, IconCopy } from "@tabler/icons-react"; +import { Check, Copy } from "@keyline-icons/react"; import type { ReactNode } from "react"; import { useState } from "react"; import { useCopy } from "@/hooks/use-copy"; @@ -48,11 +48,7 @@ export const InstallationBlockTabs = ({ entries }: InstallationBlockTabsProps) = aria-label={`Copy: ${current.command}`} className="ml-auto grid size-8 cursor-pointer place-items-center rounded-full text-ink-tertiary transition-colors hover:bg-primary-bg hover:text-ink-secondary" > - {copied === current.command ? ( - - ) : ( - - )} + {copied === current.command ? : }
    {current.code}
    diff --git a/components/docs/props-table.tsx b/components/docs/props-table.tsx index 980240e..91640a6 100644 --- a/components/docs/props-table.tsx +++ b/components/docs/props-table.tsx @@ -1,6 +1,6 @@ "use client"; -import { IconChevronDown } from "@tabler/icons-react"; +import { ChevronDown } from "@keyline-icons/react"; import { motion } from "motion/react"; import { type ReactNode, useState } from "react"; import { cn } from "@/lib/utils"; @@ -76,7 +76,7 @@ const PropsRow = ({ row }: { row: PropRow }) => { setOpen((current) => !current); }} > - diff --git a/components/ui/sidebar.tsx b/components/ui/sidebar.tsx index 52b130c..534d81a 100644 --- a/components/ui/sidebar.tsx +++ b/components/ui/sidebar.tsx @@ -2,7 +2,7 @@ import { useRender } from "@base-ui/react/use-render"; import { SHELL_SIDEBAR_WIDTH_VAR, Shell, useShell } from "@intentface/chat/shell"; -import { IconLayoutSidebar } from "@tabler/icons-react"; +import { PanelLeft } from "@keyline-icons/react"; import { cva, type VariantProps } from "class-variance-authority"; import { type ComponentProps, @@ -254,7 +254,7 @@ const SidebarTrigger = ({ className, onClick, ...props }: ComponentProps<"button className={cn("hover:bg-base-bg-hover", className)} {...props} > - + Toggle Sidebar ); @@ -273,7 +273,7 @@ const SidebarTrigger = ({ className, onClick, ...props }: ComponentProps<"button className={cn("hover:bg-base-bg-hover", className)} {...props} > - + Toggle Sidebar ) : ( diff --git a/content/docs/primitives/attachments/demos/basic.tsx b/content/docs/primitives/attachments/demos/basic.tsx index e060fe5..07bcb8c 100644 --- a/content/docs/primitives/attachments/demos/basic.tsx +++ b/content/docs/primitives/attachments/demos/basic.tsx @@ -1,7 +1,7 @@ "use client"; import { type AttachmentItem, Attachments } from "@intentface/chat/attachments"; -import { IconFile, IconX } from "@tabler/icons-react"; +import { File, X } from "@keyline-icons/react"; import { useState } from "react"; // A removable strip driven by local state — the parts are structural slots and @@ -39,7 +39,7 @@ export const Basic = () => { key={item.id} className="flex items-center gap-2 rounded-xl border border-[#f0f0f0] bg-white py-1.5 pr-1.5 pl-2.5 text-xs dark:border-[#262626] dark:bg-[#181818]" > - + {item.filename} {formatFileSize(item.fileSize)} @@ -49,7 +49,7 @@ export const Basic = () => { filename={item.filename} className="flex size-5 cursor-pointer items-center justify-center rounded-full text-[#949494] transition-colors hover:bg-[#f4f4f4] hover:text-[#1a1a1a] dark:hover:bg-[#232323] dark:hover:text-[#fcfcfc]" > - + ))} diff --git a/content/docs/primitives/attachments/demos/dropzone.tsx b/content/docs/primitives/attachments/demos/dropzone.tsx index 58b0c92..c2b9f9f 100644 --- a/content/docs/primitives/attachments/demos/dropzone.tsx +++ b/content/docs/primitives/attachments/demos/dropzone.tsx @@ -8,7 +8,7 @@ import { revokeAttachmentUrl, toAttachmentItem, } from "@intentface/chat/attachments"; -import { IconX } from "@tabler/icons-react"; +import { X } from "@keyline-icons/react"; import { type DragEvent, useEffect, useRef, useState } from "react"; const ACCEPT = "image/*,.pdf"; @@ -98,7 +98,7 @@ export const Dropzone = () => { }} className="grid size-5 cursor-pointer place-items-center rounded text-[#949494] opacity-0 transition-opacity hover:text-[#1a1a1a] group-hover/item:opacity-100 dark:text-[#6f6f6f] dark:hover:text-[#fcfcfc]" > - + ))} diff --git a/content/docs/primitives/chip/demos/basic.tsx b/content/docs/primitives/chip/demos/basic.tsx index 9588a5f..f055b62 100644 --- a/content/docs/primitives/chip/demos/basic.tsx +++ b/content/docs/primitives/chip/demos/basic.tsx @@ -1,7 +1,7 @@ "use client"; import { Chip } from "@intentface/chat/chip"; -import { IconWorld } from "@tabler/icons-react"; +import { Globe } from "@keyline-icons/react"; import type { ReactElement, ReactNode } from "react"; // Chips flow inline with text. `variant` is an opaque string surfaced as @@ -11,7 +11,7 @@ export const Basic = () => ( Pulled results from{" "} - + web-search {" "} diff --git a/content/docs/primitives/composer/demos/ask-user-flow.tsx b/content/docs/primitives/composer/demos/ask-user-flow.tsx index 670fe45..62d6569 100644 --- a/content/docs/primitives/composer/demos/ask-user-flow.tsx +++ b/content/docs/primitives/composer/demos/ask-user-flow.tsx @@ -7,7 +7,7 @@ import { type ComposerSubmitData, useComposer, } from "@intentface/chat/composer"; -import { IconArrowUp } from "@tabler/icons-react"; +import { ArrowUp } from "@keyline-icons/react"; import { useState } from "react"; // Setting `questions` arms the flow and flips askUser.active. Answering or @@ -79,7 +79,7 @@ export const AskUserFlow = () => { {done ? ( - + ) : ( diff --git a/content/docs/primitives/composer/demos/attachments.tsx b/content/docs/primitives/composer/demos/attachments.tsx index 8e608f2..89a0c61 100644 --- a/content/docs/primitives/composer/demos/attachments.tsx +++ b/content/docs/primitives/composer/demos/attachments.tsx @@ -2,7 +2,7 @@ import { Attachments } from "@intentface/chat/attachments"; import { Composer, type ComposerSubmitData, useComposer } from "@intentface/chat/composer"; -import { IconArrowUp, IconPaperclip, IconX } from "@tabler/icons-react"; +import { ArrowUp, Paperclip, X } from "@keyline-icons/react"; // Composer.Attachments carries the policy and the hidden file input; the strip // itself is yours. Files can be picked with the trigger or dropped on the composer. @@ -32,10 +32,10 @@ export const AttachmentsDemo = () => { aria-label="Attach a file" className="flex size-8 cursor-pointer items-center justify-center rounded-full text-[#949494] transition-colors hover:bg-[#f4f4f4] hover:text-[#1a1a1a] dark:text-[#6f6f6f] dark:hover:bg-[#232323] dark:hover:text-[#fcfcfc]" > - + - + @@ -67,7 +67,7 @@ const Strip = () => { filename={item.filename} className="flex size-5 cursor-pointer items-center justify-center rounded-full text-[#949494] transition-colors hover:bg-[#ececec] hover:text-[#1a1a1a] dark:hover:bg-[#2d2d2d] dark:hover:text-[#fcfcfc]" > - + ))} diff --git a/content/docs/primitives/composer/demos/basic.tsx b/content/docs/primitives/composer/demos/basic.tsx index bda6e7c..fa4a8f4 100644 --- a/content/docs/primitives/composer/demos/basic.tsx +++ b/content/docs/primitives/composer/demos/basic.tsx @@ -1,7 +1,7 @@ "use client"; import { Composer, type ComposerSubmitData } from "@intentface/chat/composer"; -import { IconArrowUp } from "@tabler/icons-react"; +import { ArrowUp } from "@keyline-icons/react"; // Every owns an isolated store, so a bare composer needs no // setup beyond an onSubmit handler. @@ -25,7 +25,7 @@ export const Basic = () => { - + diff --git a/content/docs/primitives/composer/demos/commands.tsx b/content/docs/primitives/composer/demos/commands.tsx index 7af54e9..b8ecddd 100644 --- a/content/docs/primitives/composer/demos/commands.tsx +++ b/content/docs/primitives/composer/demos/commands.tsx @@ -1,7 +1,7 @@ "use client"; import { type CommandItemData, Composer, type ComposerSubmitData } from "@intentface/chat/composer"; -import { IconArrowUp } from "@tabler/icons-react"; +import { ArrowUp } from "@keyline-icons/react"; const MENTIONS: CommandItemData[] = [ { value: "readme", label: "README.md", description: "Project overview" }, @@ -71,7 +71,7 @@ export const Commands = () => { - + diff --git a/content/docs/primitives/composer/demos/controlled.tsx b/content/docs/primitives/composer/demos/controlled.tsx index 5ed5ad8..0242ea7 100644 --- a/content/docs/primitives/composer/demos/controlled.tsx +++ b/content/docs/primitives/composer/demos/controlled.tsx @@ -1,7 +1,7 @@ "use client"; import { Composer, type ComposerSubmitData } from "@intentface/chat/composer"; -import { IconArrowUp } from "@tabler/icons-react"; +import { ArrowUp } from "@keyline-icons/react"; import { useState } from "react"; // The Textarea's plain-text value is controlled by the parent: the buttons @@ -31,7 +31,7 @@ export const Controlled = () => { - + diff --git a/content/docs/primitives/composer/demos/popover.tsx b/content/docs/primitives/composer/demos/popover.tsx index 533646d..96bf416 100644 --- a/content/docs/primitives/composer/demos/popover.tsx +++ b/content/docs/primitives/composer/demos/popover.tsx @@ -1,7 +1,7 @@ "use client"; import { type CommandItemData, Composer, type ComposerSubmitData } from "@intentface/chat/composer"; -import { IconArrowUp } from "@tabler/icons-react"; +import { ArrowUp } from "@keyline-icons/react"; const MENTIONS: CommandItemData[] = [ { value: "readme", label: "README.md", description: "Project overview" }, @@ -65,7 +65,7 @@ export const Popover = () => { - + diff --git a/content/docs/primitives/composer/demos/store.tsx b/content/docs/primitives/composer/demos/store.tsx index 1daf852..8a4c50f 100644 --- a/content/docs/primitives/composer/demos/store.tsx +++ b/content/docs/primitives/composer/demos/store.tsx @@ -1,7 +1,7 @@ "use client"; import { Composer, type ComposerSubmitData } from "@intentface/chat/composer"; -import { IconArrowUp } from "@tabler/icons-react"; +import { ArrowUp } from "@keyline-icons/react"; // A store handle created outside the tree. The button drives the composer // through store.controller — no context, no hook, no ref threading. @@ -26,7 +26,7 @@ export const Store = () => { - + diff --git a/content/docs/primitives/message/demos/basic.tsx b/content/docs/primitives/message/demos/basic.tsx index f473111..6478dbb 100644 --- a/content/docs/primitives/message/demos/basic.tsx +++ b/content/docs/primitives/message/demos/basic.tsx @@ -1,7 +1,7 @@ "use client"; import { Message } from "@intentface/chat/message"; -import { IconCheck, IconCopy } from "@tabler/icons-react"; +import { Check, Copy } from "@keyline-icons/react"; import { useState } from "react"; // Message.Root stamps data-role / data-last / data-error and imposes no layout; @@ -50,7 +50,7 @@ const CopyButton = ({ value }: { value: string }) => { aria-label="Copy message" className="flex size-7 cursor-pointer items-center justify-center rounded-md text-[#949494] transition-colors hover:bg-[#f4f4f4] hover:text-[#1a1a1a] dark:text-[#6f6f6f] dark:hover:bg-[#232323] dark:hover:text-[#fcfcfc]" > - {copied ? : } + {copied ? : } ); }; diff --git a/content/docs/primitives/message/demos/chips.tsx b/content/docs/primitives/message/demos/chips.tsx index 73cb966..f4cfa10 100644 --- a/content/docs/primitives/message/demos/chips.tsx +++ b/content/docs/primitives/message/demos/chips.tsx @@ -2,7 +2,7 @@ import { Chip } from "@intentface/chat/chip"; import { Message, type MessageChipSegment } from "@intentface/chat/message"; -import { IconFile, IconFileText, IconTool } from "@tabler/icons-react"; +import { File, FileText, Wrench } from "@keyline-icons/react"; import type { ComponentProps } from "react"; /* @@ -47,11 +47,11 @@ const renderChip = (chip: MessageChipSegment, index: number) => ( > {chip.prefix === "file" ? ( - + ) : chip.prefix === "doc" ? ( - + ) : ( - + )} {chip.label} diff --git a/content/docs/primitives/nav/demos/basic.tsx b/content/docs/primitives/nav/demos/basic.tsx index b1ab475..55800a8 100644 --- a/content/docs/primitives/nav/demos/basic.tsx +++ b/content/docs/primitives/nav/demos/basic.tsx @@ -1,7 +1,7 @@ "use client"; import { Nav } from "@intentface/chat/nav"; -import { IconBox, IconChevronDown, IconHome, IconInbox, IconMessage } from "@tabler/icons-react"; +import { ChevronDown, Home, Inbox, MessageSquare, Package } from "@keyline-icons/react"; import { type ComponentProps, useState } from "react"; /* @@ -46,7 +46,7 @@ export const Basic = () => { render={link("/overview", () => setCurrent("overview"))} > - + Overview @@ -58,7 +58,7 @@ export const Basic = () => { render={link("/inbox", () => setCurrent("inbox"))} > - + Inbox @@ -76,7 +76,7 @@ export const Basic = () => { - + Intentface @@ -92,7 +92,7 @@ export const Basic = () => { render={link("/intentface/home", () => setCurrent("team-home"))} > - + Home @@ -104,7 +104,7 @@ export const Basic = () => { render={link("/intentface/issues", () => setCurrent("team-issues"))} > - + Issues @@ -115,7 +115,7 @@ export const Basic = () => { - + Chat @@ -146,7 +146,7 @@ export const Basic = () => { - + Website @@ -221,7 +221,7 @@ const rowClass = [ * reading `data-closed` off the enclosing trigger, so nothing is threaded down. */ const Chevron = () => ( - + ); /* diff --git a/content/docs/primitives/nav/demos/collapse.tsx b/content/docs/primitives/nav/demos/collapse.tsx index 354f893..f9cfbd2 100644 --- a/content/docs/primitives/nav/demos/collapse.tsx +++ b/content/docs/primitives/nav/demos/collapse.tsx @@ -1,7 +1,7 @@ "use client"; import { Nav } from "@intentface/chat/nav"; -import { IconChevronDown } from "@tabler/icons-react"; +import { ChevronDown } from "@keyline-icons/react"; /* * The collapse, slowed to 500ms so the mechanism is visible. @@ -75,7 +75,7 @@ const rowClass = [ ].join(" "); const Chevron = () => ( - + ); /* diff --git a/content/docs/primitives/nav/demos/external.tsx b/content/docs/primitives/nav/demos/external.tsx index 5de0255..8cbb7c7 100644 --- a/content/docs/primitives/nav/demos/external.tsx +++ b/content/docs/primitives/nav/demos/external.tsx @@ -1,7 +1,7 @@ "use client"; import { Nav, type NavStore, useNavStore } from "@intentface/chat/nav"; -import { IconChevronDown } from "@tabler/icons-react"; +import { ChevronDown } from "@keyline-icons/react"; import { useState } from "react"; const GROUPS = ["workspace", "projects", "archive"]; @@ -98,7 +98,7 @@ const rowClass = [ ].join(" "); const Chevron = () => ( - + ); const CollapseRecipe = () => ( diff --git a/content/docs/primitives/nav/demos/guides.tsx b/content/docs/primitives/nav/demos/guides.tsx index f242621..b968337 100644 --- a/content/docs/primitives/nav/demos/guides.tsx +++ b/content/docs/primitives/nav/demos/guides.tsx @@ -1,7 +1,7 @@ "use client"; import { Nav } from "@intentface/chat/nav"; -import { IconBox, IconChevronDown, IconHome } from "@tabler/icons-react"; +import { ChevronDown, Home, Package } from "@keyline-icons/react"; /* * The same tree four times, once per `guide` value, so the rungs can be @@ -44,7 +44,7 @@ const GuideTree = ({ guide, caption }: { guide: GuideValue; caption: string }) = - + Overview @@ -52,7 +52,7 @@ const GuideTree = ({ guide, caption }: { guide: GuideValue; caption: string }) = - + Chat @@ -101,7 +101,7 @@ const rowClass = [ ].join(" "); const Chevron = () => ( - + ); /* diff --git a/content/docs/primitives/reasoning/demos/basic.tsx b/content/docs/primitives/reasoning/demos/basic.tsx index 90007dd..069d1ff 100644 --- a/content/docs/primitives/reasoning/demos/basic.tsx +++ b/content/docs/primitives/reasoning/demos/basic.tsx @@ -1,7 +1,7 @@ "use client"; import { Reasoning } from "@intentface/chat/reasoning"; -import { IconBrain, IconChevronDown } from "@tabler/icons-react"; +import { Brain, ChevronDown } from "@keyline-icons/react"; // A completed reasoning block. The parts ship no copy and no layout — the // trigger label and the section structure below are both yours. @@ -20,9 +20,9 @@ export const Basic = () => (
    - + Thought for a few seconds - + {SECTIONS.map((section) => ( diff --git a/content/docs/primitives/reasoning/demos/streaming.tsx b/content/docs/primitives/reasoning/demos/streaming.tsx index 0ab9651..27ce537 100644 --- a/content/docs/primitives/reasoning/demos/streaming.tsx +++ b/content/docs/primitives/reasoning/demos/streaming.tsx @@ -1,7 +1,7 @@ "use client"; import { Reasoning, useReasoning } from "@intentface/chat/reasoning"; -import { IconBrain, IconChevronDown } from "@tabler/icons-react"; +import { Brain, ChevronDown } from "@keyline-icons/react"; import { useEffect, useRef, useState } from "react"; const SECTIONS = [ @@ -82,7 +82,7 @@ const TriggerLabel = () => { return ( - + {isStreaming ? "Thinking…" @@ -90,7 +90,7 @@ const TriggerLabel = () => { ? "Reasoning" : `Thought for ${duration}s`} - + ); }; diff --git a/content/docs/primitives/shell/demos/basic.tsx b/content/docs/primitives/shell/demos/basic.tsx index 72bd03d..66e1313 100644 --- a/content/docs/primitives/shell/demos/basic.tsx +++ b/content/docs/primitives/shell/demos/basic.tsx @@ -2,13 +2,7 @@ import { Nav } from "@intentface/chat/nav"; import { Shell } from "@intentface/chat/shell"; -import { - IconBox, - IconChevronDown, - IconHome, - IconInbox, - IconLayoutSidebar, -} from "@tabler/icons-react"; +import { ChevronDown, Home, Inbox, Package, PanelLeft } from "@keyline-icons/react"; /* * A shell the way it is meant to be used: a sidebar that collapses, floats out @@ -74,7 +68,7 @@ export const Basic = () => ( @intentface/chat - +
    @@ -90,13 +84,13 @@ export const Basic = () => ( - + Overview - + Inbox @@ -104,13 +98,13 @@ export const Basic = () => ( Workspace - + {["Initiatives", "Projects", "Views", "Loops"].map((label) => ( - + {label} @@ -150,7 +144,7 @@ export const Basic = () => (
    Docs - + Overview diff --git a/content/docs/primitives/steps/demos/basic.tsx b/content/docs/primitives/steps/demos/basic.tsx index cc5e1e6..a4d6b2d 100644 --- a/content/docs/primitives/steps/demos/basic.tsx +++ b/content/docs/primitives/steps/demos/basic.tsx @@ -1,7 +1,7 @@ "use client"; import { Steps } from "@intentface/chat/steps"; -import { IconCheck, IconChevronDown, IconCircle } from "@tabler/icons-react"; +import { Check, ChevronDown, Circle } from "@keyline-icons/react"; // Steps is recursive: an item's panel can hold rows and further items. A nested // panel picks up data-nested, which is how the rail indent is drawn. @@ -21,13 +21,13 @@ export const Basic = () => ( Worked for 3 seconds - +
    - + Read the request
    @@ -37,9 +37,9 @@ export const Basic = () => ( - + - + Searched the web @@ -53,7 +53,7 @@ export const Basic = () => (
    - + Writing the answer diff --git a/content/docs/primitives/steps/demos/status.tsx b/content/docs/primitives/steps/demos/status.tsx index 8fd5454..0b20bb5 100644 --- a/content/docs/primitives/steps/demos/status.tsx +++ b/content/docs/primitives/steps/demos/status.tsx @@ -1,7 +1,7 @@ "use client"; import { Steps } from "@intentface/chat/steps"; -import { IconCheck, IconCircle, IconLoader2, IconX } from "@tabler/icons-react"; +import { Check, Circle, LoaderCircle, X } from "@keyline-icons/react"; import { type ComponentProps, useEffect, useRef, useState } from "react"; const ROWS = ["Read the request", "Searched the web", "Checked the cache", "Wrote the answer"]; @@ -54,13 +54,13 @@ export const Status = () => {
    {status === "complete" ? ( - + ) : status === "error" ? ( - + ) : status === "active" ? ( - + ) : ( - + )} diff --git a/content/docs/primitives/tabs/demos/anchored.tsx b/content/docs/primitives/tabs/demos/anchored.tsx index 825a9bc..59bfba6 100644 --- a/content/docs/primitives/tabs/demos/anchored.tsx +++ b/content/docs/primitives/tabs/demos/anchored.tsx @@ -4,14 +4,7 @@ import { Composer, type ComposerSubmitData } from "@intentface/chat/composer"; import { Message } from "@intentface/chat/message"; import { Tabs, useTabs } from "@intentface/chat/tabs"; import { Thread } from "@intentface/chat/thread"; -import { - IconArrowUp, - IconMessage, - IconMinus, - IconPlayerStop, - IconSparkles, - IconX, -} from "@tabler/icons-react"; +import { ArrowUp, MessageSquare, Minus, Sparkles, Stop, X } from "@keyline-icons/react"; import { type KeyboardEvent, useRef, useState } from "react"; /* @@ -195,7 +188,7 @@ export const Anchored = () => { {(id) => ( - + {title(id)} { aria-label={`Close ${title(id)}`} className="grid size-5 shrink-0 cursor-pointer select-none place-items-center rounded text-[#686868] transition-colors hover:bg-[#e4e4e4] hover:text-[#1a1a1a] dark:text-[#9b9b9b] dark:hover:bg-[#333333] dark:hover:text-[#fcfcfc]" > - + @@ -221,7 +214,7 @@ export const Anchored = () => { disclosure ARIA a tab does. */} - + Agent @@ -298,7 +291,7 @@ const DockHeader = ({ title }: { title: (id: string) => string }) => { onClick={() => select(null)} className={iconButtonClass} > - + ); @@ -385,7 +378,7 @@ const ChatThread = ({ const NewChat = ({ onStart }: { onStart: (text: string) => void }) => (
    - +

    Ask the agent

    This is a draft — it becomes a tab once you send something. @@ -433,11 +426,7 @@ const DockComposer = ({ aria-label={generating ? "Stop" : "Send"} className="flex size-7 items-center justify-center rounded-full bg-[#1a1a1a] text-white transition-opacity disabled:opacity-30 dark:bg-[#fcfcfc] dark:text-[#111111]" > - {generating ? ( - - ) : ( - - )} + {generating ? : } diff --git a/content/docs/primitives/tabs/demos/basic.tsx b/content/docs/primitives/tabs/demos/basic.tsx index 7add451..a0e7028 100644 --- a/content/docs/primitives/tabs/demos/basic.tsx +++ b/content/docs/primitives/tabs/demos/basic.tsx @@ -1,7 +1,7 @@ "use client"; import { Tabs, useTabs } from "@intentface/chat/tabs"; -import { IconFile, IconPlus, IconX } from "@tabler/icons-react"; +import { File, Plus, X } from "@keyline-icons/react"; import { Fragment, type ReactNode, useEffect, useRef, useState } from "react"; /* @@ -81,7 +81,7 @@ export const Basic = () => { className={tabClass} > - + {documents[id]?.name ?? id} @@ -100,7 +100,7 @@ export const Basic = () => { aria-label={`Close ${documents[id]?.name ?? id}`} className="grid size-5 shrink-0 cursor-pointer select-none place-items-center rounded-md text-[#686868] transition-colors hover:bg-[#e4e4e4] hover:text-[#1a1a1a] dark:text-[#9b9b9b] dark:hover:bg-[#333333] dark:hover:text-[#fcfcfc]" > - + @@ -204,7 +204,7 @@ const NewDocument = ({ onCreate }: { onCreate: (id: string, document: Document) }} className="grid size-7 shrink-0 cursor-pointer select-none place-items-center rounded-md text-[#686868] transition-colors hover:bg-[#f4f4f4] hover:text-[#1a1a1a] focus-visible:-outline-offset-2 focus-visible:outline-2 focus-visible:outline-[#1a1a1a] dark:text-[#9b9b9b] dark:hover:bg-[#232323] dark:hover:text-[#fcfcfc] dark:focus-visible:outline-[#fcfcfc]" > - + ); }; diff --git a/content/docs/primitives/tabs/demos/closing.tsx b/content/docs/primitives/tabs/demos/closing.tsx index 98fa374..47e018d 100644 --- a/content/docs/primitives/tabs/demos/closing.tsx +++ b/content/docs/primitives/tabs/demos/closing.tsx @@ -1,7 +1,7 @@ "use client"; import { Tabs } from "@intentface/chat/tabs"; -import { IconArchive, IconInbox, IconPencil, IconSend, IconX } from "@tabler/icons-react"; +import { Archive, Inbox, Pen, Send, X } from "@keyline-icons/react"; import { createElement } from "react"; /* @@ -54,7 +54,7 @@ const Strip = ({ {(id) => ( - {createElement(TAB_ICONS[id] ?? IconInbox)} + {createElement(TAB_ICONS[id] ?? Inbox)} {id} @@ -63,7 +63,7 @@ const Strip = ({ aria-label={`Close ${id}`} className="grid size-5 shrink-0 cursor-pointer place-items-center rounded text-[#949494] transition-colors hover:bg-[#dcdcdc] hover:text-[#1a1a1a] dark:text-[#6f6f6f] dark:hover:bg-[#3d3d3d] dark:hover:text-[#fcfcfc]" > - + @@ -97,9 +97,9 @@ const tabClass = [ /* Per-tab icons rather than one generic page glyph — a strip of identical icons carries no information, and the whole point of a tab icon is telling the tabs apart at a glance. */ -const TAB_ICONS: Record = { - Inbox: IconInbox, - Drafts: IconPencil, - Sent: IconSend, - Archive: IconArchive, +const TAB_ICONS: Record = { + Inbox: Inbox, + Drafts: Pen, + Sent: Send, + Archive: Archive, }; diff --git a/content/docs/primitives/tabs/demos/external.tsx b/content/docs/primitives/tabs/demos/external.tsx index e4db5f0..0e3f14d 100644 --- a/content/docs/primitives/tabs/demos/external.tsx +++ b/content/docs/primitives/tabs/demos/external.tsx @@ -1,7 +1,7 @@ "use client"; import { Tabs, type TabsStore, useTabsStore } from "@intentface/chat/tabs"; -import { IconArchive, IconInbox, IconPencil, IconSend, IconX } from "@tabler/icons-react"; +import { Archive, Inbox, Pen, Send, X } from "@keyline-icons/react"; import { createElement, useState } from "react"; /* @@ -31,7 +31,7 @@ export const ExternalTabs = () => { {(id) => ( - {createElement(TAB_ICONS[id] ?? IconInbox)} + {createElement(TAB_ICONS[id] ?? Inbox)} {id} @@ -39,7 +39,7 @@ export const ExternalTabs = () => { aria-label={`Close ${id}`} className="grid size-5 shrink-0 cursor-pointer place-items-center rounded text-[#949494] transition-colors hover:bg-[#dcdcdc] hover:text-[#1a1a1a] dark:text-[#6f6f6f] dark:hover:bg-[#3d3d3d] dark:hover:text-[#fcfcfc]" > - + @@ -96,9 +96,9 @@ const tabClass = [ /* Per-tab icons rather than one generic page glyph — a strip of identical icons carries no information, and the whole point of a tab icon is telling the tabs apart at a glance. */ -const TAB_ICONS: Record = { - Inbox: IconInbox, - Drafts: IconPencil, - Sent: IconSend, - Archive: IconArchive, +const TAB_ICONS: Record = { + Inbox: Inbox, + Drafts: Pen, + Sent: Send, + Archive: Archive, }; diff --git a/content/docs/primitives/thread/demos/basic.tsx b/content/docs/primitives/thread/demos/basic.tsx index 6e8b4ea..eaad2a7 100644 --- a/content/docs/primitives/thread/demos/basic.tsx +++ b/content/docs/primitives/thread/demos/basic.tsx @@ -3,7 +3,7 @@ import { Composer, type ComposerSubmitData } from "@intentface/chat/composer"; import { Message } from "@intentface/chat/message"; import { Thread, useThread } from "@intentface/chat/thread"; -import { IconArrowDown, IconArrowUp } from "@tabler/icons-react"; +import { ArrowDown, ArrowUp } from "@keyline-icons/react"; import { useState } from "react"; type DemoMessage = { id: string; role: "user" | "assistant"; text: string }; @@ -74,7 +74,7 @@ export const Basic = () => { - + @@ -99,7 +99,7 @@ const ScrollButton = () => { aria-label="Scroll to latest" className="absolute -top-10 z-10 flex size-8 cursor-pointer items-center justify-center rounded-full border border-[#f0f0f0] bg-white text-[#686868] shadow-xs transition-colors hover:text-[#1a1a1a] dark:border-[#262626] dark:bg-[#181818] dark:text-[#9b9b9b] dark:hover:text-[#fcfcfc]" > - + ); }; diff --git a/package.json b/package.json index 2ebba3b..0346e76 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@ai-sdk/react": "^3.0.220", "@base-ui/react": "^1.6.0", "@intentface/chat": "workspace:*", + "@keyline-icons/react": "^1.4.0", "@tabler/icons-react": "^3.46.0", "ai": "^6.0.218", "class-variance-authority": "^0.7.1", From 6e3c2c6846afd4310d38c1466f0470af7c363eaa Mon Sep 17 00:00:00 2001 From: Rasmus Viloma Date: Thu, 8 Oct 2026 01:00:51 +0300 Subject: [PATCH 08/20] feat(app): redesign the docs and playground --- app/(docs)/[[...slug]]/page.tsx | 64 +++- app/(docs)/layout.tsx | 11 +- app/fonts/IoskeleyMono-Medium.woff2 | Bin 0 -> 96204 bytes app/fonts/IoskeleyMono-OFL.txt | 92 +++++ app/fonts/IoskeleyMono-Regular.woff2 | Bin 0 -> 96552 bytes app/fonts/IoskeleyMono-SemiBold.woff2 | Bin 0 -> 96416 bytes app/globals.css | 317 ++++++++++++++++-- app/layout.tsx | 20 +- components/ai/ask-user.tsx | 37 +- components/ai/attachments.tsx | 31 +- components/ai/chip.tsx | 2 +- components/ai/composer.tsx | 68 ++-- components/ai/message.tsx | 51 +-- components/ai/reasoning.tsx | 17 +- components/ai/steps.tsx | 6 +- components/ai/thread.tsx | 9 +- components/app-sidebar.tsx | 119 ++++--- components/chat.tsx | 122 +++---- components/composer-tools.tsx | 26 +- components/docs/attributes-table.tsx | 135 ++------ components/docs/code-block.tsx | 42 +-- components/docs/code-files.tsx | 33 ++ components/docs/code-frame.tsx | 87 +++++ components/docs/component-preview-frame.tsx | 104 +++++- components/docs/demo.tsx | 27 +- components/docs/docs-search.tsx | 312 ++++++++++++++--- components/docs/docs-shell.tsx | 34 ++ components/docs/docs-sidebar.tsx | 275 ++++++++------- components/docs/docs-theme-toggle.tsx | 6 +- components/docs/docs-toc.tsx | 26 +- components/docs/docs-top-bar-trigger.tsx | 9 + components/docs/installation-block-tabs.tsx | 48 +-- components/docs/installation-block.tsx | 16 +- components/docs/keys-table.tsx | 39 +-- components/docs/page-actions.tsx | 58 ++-- components/docs/props-table.tsx | 153 ++++----- components/docs/reference-table.tsx | 67 ++++ components/docs/values-table.tsx | 49 +-- components/icons/intentface-logo.tsx | 64 ---- components/icons/logo-tile.tsx | 34 ++ components/model-selector.tsx | 8 +- components/playground-settings.tsx | 252 ++++++++------ components/ui/button-group.tsx | 4 +- components/ui/button.tsx | 33 +- components/ui/checkbox.tsx | 10 +- components/ui/color-pill.tsx | 27 +- components/ui/dialog.tsx | 4 +- components/ui/drawer.tsx | 6 +- components/ui/dropdown-menu.tsx | 41 ++- components/ui/hover-card.tsx | 2 +- components/ui/icon-button.tsx | 27 +- components/ui/input-group.tsx | 6 +- components/ui/input.tsx | 8 +- components/ui/kbd.tsx | 13 +- components/ui/markdown.tsx | 4 +- components/ui/popover.tsx | 2 +- components/ui/preset-swatch.tsx | 2 +- components/ui/radio-group.tsx | 8 +- components/ui/scaler.tsx | 93 ----- components/ui/select.tsx | 49 ++- components/ui/separator.tsx | 2 +- components/ui/settings.tsx | 10 +- components/ui/sidebar.tsx | 79 ++--- components/ui/skeleton.tsx | 2 +- components/ui/slider.tsx | 6 +- components/ui/switch.tsx | 7 +- components/ui/textarea.tsx | 6 +- components/ui/toggle-group.tsx | 23 +- components/ui/tooltip.tsx | 6 +- content/docs/build-a-chat/demos/composer.tsx | 119 ++++--- content/docs/build-a-chat/demos/messages.tsx | 6 +- content/docs/build-a-chat/demos/thread.tsx | 4 +- content/docs/index.mdx | 14 +- content/docs/meta.json | 2 +- .../primitives/attachments/demos/basic.tsx | 22 +- .../primitives/attachments/demos/dropzone.tsx | 20 +- content/docs/primitives/chip/demos/basic.tsx | 8 +- .../docs/primitives/chip/demos/preview.tsx | 14 +- .../composer/demos/ask-user-flow.tsx | 131 +------- .../primitives/composer/demos/ask-user.tsx | 115 +++++++ .../primitives/composer/demos/attachments.tsx | 30 +- .../docs/primitives/composer/demos/basic.tsx | 12 +- .../primitives/composer/demos/commands.tsx | 24 +- .../primitives/composer/demos/controlled.tsx | 23 +- .../primitives/composer/demos/popover.tsx | 27 +- .../docs/primitives/composer/demos/store.tsx | 14 +- .../docs/primitives/message/demos/basic.tsx | 10 +- .../docs/primitives/message/demos/chips.tsx | 13 +- .../primitives/message/demos/selection.tsx | 12 +- content/docs/primitives/nav/demos/basic.tsx | 84 +---- .../docs/primitives/nav/demos/collapse.css | 27 ++ .../docs/primitives/nav/demos/collapse.tsx | 37 +- .../docs/primitives/nav/demos/destination.tsx | 51 +-- .../docs/primitives/nav/demos/external.css | 20 ++ .../docs/primitives/nav/demos/external.tsx | 32 +- .../docs/primitives/nav/demos/guides-rail.css | 56 ++++ content/docs/primitives/nav/demos/guides.tsx | 78 +---- content/docs/primitives/nav/demos/rail.css | 72 ++++ .../docs/primitives/reasoning/demos/basic.tsx | 10 +- .../primitives/reasoning/demos/streaming.css | 19 ++ .../primitives/reasoning/demos/streaming.tsx | 31 +- content/docs/primitives/shell/demos/basic.tsx | 119 ++----- .../docs/primitives/shell/demos/external.tsx | 13 +- content/docs/primitives/shell/demos/grip.tsx | 15 +- .../docs/primitives/shell/demos/hotspot.tsx | 31 +- content/docs/primitives/shell/demos/logo.tsx | 8 + content/docs/primitives/shell/demos/range.tsx | 12 +- .../primitives/shell/demos/sidebar-nav.tsx | 57 ++++ content/docs/primitives/steps/demos/basic.tsx | 69 ++-- .../docs/primitives/steps/demos/status.tsx | 139 ++++---- .../docs/primitives/tabs/demos/anchored.tsx | 241 +++---------- content/docs/primitives/tabs/demos/basic.tsx | 178 ++-------- content/docs/primitives/tabs/demos/chat.tsx | 180 ++++++++++ .../docs/primitives/tabs/demos/closing.tsx | 32 +- .../primitives/tabs/demos/confirm-close.tsx | 75 ++--- .../primitives/tabs/demos/confirm-prompt.tsx | 69 ++++ .../docs/primitives/tabs/demos/document.tsx | 71 ++++ .../docs/primitives/tabs/demos/external.tsx | 28 +- .../primitives/tabs/demos/hover-motion.css | 24 ++ content/docs/primitives/tabs/demos/hover.tsx | 137 +------- content/docs/primitives/tabs/demos/icons.tsx | 31 ++ content/docs/primitives/tabs/demos/pages.tsx | 84 +++++ .../docs/primitives/tabs/demos/tab-strip.css | 48 +++ .../docs/primitives/tabs/demos/tab-strip.tsx | 32 ++ content/docs/primitives/thread.mdx | 43 ++- .../primitives/thread/demos/autoscroll.tsx | 166 +++++---- .../docs/primitives/thread/demos/basic.tsx | 34 +- content/docs/primitives/thread/demos/jump.tsx | 160 ++++++--- content/docs/quick-start/demos/hero.tsx | 43 +-- lib/ai/chip-icons.tsx | 49 ++- lib/docs/code-theme.ts | 53 +++ lib/docs/demo-files.ts | 64 ++++ lib/docs/expand-demos.ts | 30 +- lib/docs/source.ts | 26 ++ lib/interface-theme.ts | 8 +- mdx-components.tsx | 54 ++- 136 files changed, 4110 insertions(+), 2800 deletions(-) create mode 100644 app/fonts/IoskeleyMono-Medium.woff2 create mode 100644 app/fonts/IoskeleyMono-OFL.txt create mode 100644 app/fonts/IoskeleyMono-Regular.woff2 create mode 100644 app/fonts/IoskeleyMono-SemiBold.woff2 create mode 100644 components/docs/code-files.tsx create mode 100644 components/docs/code-frame.tsx create mode 100644 components/docs/docs-shell.tsx create mode 100644 components/docs/docs-top-bar-trigger.tsx create mode 100644 components/docs/reference-table.tsx delete mode 100644 components/icons/intentface-logo.tsx create mode 100644 components/icons/logo-tile.tsx delete mode 100644 components/ui/scaler.tsx create mode 100644 content/docs/primitives/composer/demos/ask-user.tsx create mode 100644 content/docs/primitives/nav/demos/collapse.css create mode 100644 content/docs/primitives/nav/demos/external.css create mode 100644 content/docs/primitives/nav/demos/guides-rail.css create mode 100644 content/docs/primitives/nav/demos/rail.css create mode 100644 content/docs/primitives/reasoning/demos/streaming.css create mode 100644 content/docs/primitives/shell/demos/logo.tsx create mode 100644 content/docs/primitives/shell/demos/sidebar-nav.tsx create mode 100644 content/docs/primitives/tabs/demos/chat.tsx create mode 100644 content/docs/primitives/tabs/demos/confirm-prompt.tsx create mode 100644 content/docs/primitives/tabs/demos/document.tsx create mode 100644 content/docs/primitives/tabs/demos/hover-motion.css create mode 100644 content/docs/primitives/tabs/demos/icons.tsx create mode 100644 content/docs/primitives/tabs/demos/pages.tsx create mode 100644 content/docs/primitives/tabs/demos/tab-strip.css create mode 100644 content/docs/primitives/tabs/demos/tab-strip.tsx create mode 100644 lib/docs/code-theme.ts create mode 100644 lib/docs/demo-files.ts diff --git a/app/(docs)/[[...slug]]/page.tsx b/app/(docs)/[[...slug]]/page.tsx index db66f4b..e862ebd 100644 --- a/app/(docs)/[[...slug]]/page.tsx +++ b/app/(docs)/[[...slug]]/page.tsx @@ -1,7 +1,10 @@ +import { ChevronRight } from "@keyline-icons/react"; import { notFound } from "next/navigation"; import { DocsTOC } from "@/components/docs/docs-toc"; +import { DocsTopBarTrigger } from "@/components/docs/docs-top-bar-trigger"; import { PageActions } from "@/components/docs/page-actions"; -import { getPage, source } from "@/lib/docs/source"; +import { ProgressiveBlur } from "@/components/ui/progressive-blur"; +import { getPage, getSectionLabel, source } from "@/lib/docs/source"; import { getMDXComponents } from "@/mdx-components"; type PageProps = { @@ -17,24 +20,53 @@ export default async function DocsPage(props: PageProps) { // fumadocs uses an empty slug for the docs index; the raw-markdown route keys // off the on-disk filename. const markdownSlug = slug?.length ? slug : ["index"]; + const section = getSectionLabel(page.url); return ( -

    -
    -
    -

    - {page.data.title} -

    - {page.data.description && ( -

    {page.data.description}

    - )} - -
    -
    - +
    +
    + {/* Content dissolves under the bar instead of cutting off: a progressive + blur plus a fade that reach past the bar's bottom edge. */} + +
    + +
    -
    - + + + {/* isolate: demo z-indexes stay inside the page, below the sticky top bar. */} +
    +
    +
    +
    +

    + {page.data.title} +

    + {page.data.description && ( +

    + {page.data.description} +

    + )} +
    +
    + +
    +
    +
    + +
    ); } diff --git a/app/(docs)/layout.tsx b/app/(docs)/layout.tsx index 658ab67..6f289f1 100644 --- a/app/(docs)/layout.tsx +++ b/app/(docs)/layout.tsx @@ -1,14 +1,7 @@ import type { ReactNode } from "react"; -import { DocsSidebar } from "@/components/docs/docs-sidebar"; +import { DocsShell } from "@/components/docs/docs-shell"; import { source } from "@/lib/docs/source"; export default function DocsLayout({ children }: { children: ReactNode }) { - return ( -
    - -
    -
    {children}
    -
    -
    - ); + return {children}; } diff --git a/app/fonts/IoskeleyMono-Medium.woff2 b/app/fonts/IoskeleyMono-Medium.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..9cce877e866043725c3a9d7173ac54f1851f1a25 GIT binary patch literal 96204 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%0Dqq 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 literal 0 HcmV?d00001 diff --git a/app/fonts/IoskeleyMono-OFL.txt b/app/fonts/IoskeleyMono-OFL.txt new file mode 100644 index 0000000..d8aa8e9 --- /dev/null +++ b/app/fonts/IoskeleyMono-OFL.txt @@ -0,0 +1,92 @@ +Copyright (c) 2025, Ahmed Hatem (https://github.com/ahatem) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +--- + +## SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1. Neither the Font Software nor any of its individual components, + in Original or Modified Versions, may be sold by itself. + +1. Original or Modified Versions of the Font Software may be bundled, + redistributed and/or sold with any software, provided that each copy + contains the above copyright notice and this license. These can be + included either as stand-alone text files, human-readable headers or + in the appropriate machine-readable metadata fields within text or + binary files as long as those fields can be easily viewed by the user. + +1. No Modified Version of the Font Software may use the Reserved Font + Name(s) unless explicit written permission is granted by the corresponding + Copyright Holder. This restriction only applies to the primary font name as + presented to the users. + +1. The name(s) of the Copyright Holder(s) or the Author(s) of the Font + Software shall not be used to promote, endorse or advertise any + Modified Version, except to acknowledge the contribution(s) of the + Copyright Holder(s) and the Author(s) or with their explicit written + permission. + +1. The Font Software, modified or unmodified, in part or in whole, + must be distributed entirely under this license, and must not be + distributed under any other license. The requirement for fonts to + remain under this license does not apply to any document created + using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/app/fonts/IoskeleyMono-Regular.woff2 b/app/fonts/IoskeleyMono-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..5f8cefb6b635080e19b1563f28eccecfbda1ea62 GIT binary patch literal 96552 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 X>Z5-fyhqvjg`aC&*YnL5-a=~v1XupD literal 0 HcmV?d00001 diff --git a/app/fonts/IoskeleyMono-SemiBold.woff2 b/app/fonts/IoskeleyMono-SemiBold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..445da28e8ddb0f034a7a9a2e492b73173cbb3e3c GIT binary patch literal 96416 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 U+|1byLp0#$>Op$3yV@il}day+NU<$ALEB8@2UN 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

    (dd4OfKeh@a8X#2>=<%LOsDIE zZEe{>+IACg68uPsuE<485%hRO@nb(^mSWe%P_rxDSsfS6^XW*yD3N$zk~X$4w~cP=Z>vM?^x zBk;DP5Ey{1%}~0aB~lwZ5Cj8rH*#L}^T;6kNPWQ^7Da;$39O81G%Rs%!wb;d09@1m z=MOk`GTAZcKSF4F{2Y1Qsh?Z^!f>U7b4C&g9XaFAM$&@Jlp)vxvA2~NfFXLxq$2ia zCr*V8RF69Ze!h50Nre$t7r>`3AZcA3k{#8I zKxBlPrU6^BhDQoV&Banf7ZT3Eh0KS!m#(9LpC`(UbCFxm;ZJYCw;$&+I0{UKuVHEu zLKBGnfJB#Anp-MXh0s{ww@y7lXZ58%r=?gkqIe_3NjHDT$6xxKW>a_xfRlN`T7qu` z_a0uMI%zb)c=Eu}6h%Vda}sA432ph1T^Du^-SG?3nK@q74N^+^bA530T6-2Ix6=I`fMN&=IgEVb#s0S1(#o%u-R-l}+W^*7vY^M?YAPfr zHmH@QKTUG@f|=WFP$wZD!A&G4gn3-DWIf6@U-X`7Uz{KT;j67@FIAlas@8X40qp{|8WT zQj@M2mfL$jBga{8@_0Y~{II90-N>4Z+5s6ZHbttlxS>uIWIY!-C0ZO)#l*$rtT}l| z=kxNNXapxx^`jTd{CU&s-qqYbahg}fOWmfPePJ>D$DSPvd5ikf%s>hW%TKN*yU>!-f&6rKZ2RssiqnOqU+h6A>pN`yR+mU+=d25E;l^k|22iPgL zi%GXev1ecSo8$Yjync*GR54WOc5Hw;PUVS?h)P=rQMu?GBB#lVw&{oT+;vD@vbZ4} zY#fruMn(pR!`2<`zYJ?O0~`n)G~Wy`xQh__icC~*`-mQ9+My%SgH%3V<)5x`W* zA*w{0nzplfEK8ZF1olD~B+i04P+Z{1=owYe!hU-ils46IuVbjP!>Jf)ivAMORw)Q* zpU{|~uG5#wZBMtN{l!@GLlNtZXpD7Zmu83fV=V;SIPur=XareIEibwv)O0>P5q&QX zx+khmJ{7}i_h&4P^DHne8rtZyO%aild?VxG39!c>5tqBhDJ8CBLdk*9%OXt(P} z1Dmr07HG4J&PMx-U1UIz-LAKn=NlS5TyBgRNk=;^Hqf1~SF=<0BJ-tBv?um+Y(G0Q zz4o+S>D^N}FcWdc#rAR-%D63Q(s(MHRLb7 zCTm`5w|C6vb2Lmn-_(I3(x5^KD0@Ph+^9oI6=st)5>z!_Cd8^cL6QK)GZ7urY4U_j zKuZCt$l(P4bL=yCo@t4)>W?LG!~(q!-8h)X{p*Hpd%rDBKCYJuDv+gNoFtgwjKXZM zC?x5qOX+8;V`Qo`+4gcXc2b{sxr*)l7hnyZj;*};IjJexAc&-c&GfSgh6OM6OX@}7 zh(Xdu$bZ9(G2hCMTZ1{x+nqZ9L-YSP`VFyz9G%C=>k%>-3s1IMFN(6VW`R-5`m)FR zqZ}<%zu}a!z!Aucqpp(+-@XZ<(u*cd#|OW^9-1$?AH(v*f$vJbU4*fo2-b$aBZ_`v zoJ{7`k1MKdj>Hf+#r)6bmt-0lzUKhe<0;DJ8q`d{(?Q~`dCwQb-!Xq;bJVpo-G}4K zo-V>#kInPbkwDjJC-loi^aa_VP5{&yNs&W2IR`XtNriU34yfxILsbN}GU@~mbl5O| zsCcyP^d79-o&o%zLXdDzJc?RgJ8h_-5-bsL>ZDh3Qo=p)sQ!=IyuN`-%?9p_84&0o z)*0vC9Ya3hi?Ffb0PozG+2CG> zv?OhX&yhscp+Z$bfECwSZK#_ZCP(u!jR7u`CR$71U}<4Z?+0wyqRrfU`%ov~6-5+G z1}L7w?|*EI5kix37Otn)8%H8_#dCSky?_UcK0UeO*b%S#Ty$|u+DGUBk2LKXz?&+a z+}0Ht=!()HhjaD&jX1<14snP>9O4j#Y}I7+-Xqi*@J_*w!+z}HT|t*$dF*IehnO?( zdI@8IE?qD_c2&{frz;Jit8>o5W~}gO&~dnoxS`vf0f+Y`J40v>tfjANUwKVPlOY{w zh?N(5=kzu|95gws>@}TlpMWN9odL3zpFWvgmrT)=XdynBih)YiKq01RDWQVkv$qN* zS%Lp-!+mxI0M5<(j0`#T`;83aJQXo-B_`tVzNC6FaEAq6f^Q)&Kr?RO!I((*>k1FeqoY}ci8a=* zD=gf!dT&%=?_RFPqC#w0``A>t@*ldXGh&Rol!2%}IHr@TDD&Q1XJs+7KOdQ~y1ITK zrpEf155B46G>MH>s*rfGc)T_<>Bd25Y`z%UlM#Jhn{H$(j*|F5>>FSA5YI3hjGu;SpJeLwfM-Ndz zwYdL4o4lDaXg;?W zzeYW9B7Sm7^JDA?jk~`3Lypniu#j-dl>VD~>S7vrFMmzg!abQtS(ib(RaexMzt z*o0{CtJ14uVd$N=Y}trg$GA;piv0xm<#${szb>Oc*`GfnoULt9F$h?Ks5aHB(MH%F zLWAs$Z{EHUw|-<+Dmd0jRD{&D>V`d}9lpQlblqA^j82qKwX`2OlZBQ<7#UdS9z1Nc zxg~c25Q>5d<#CAv!xM!ZBLrAjvmyH1+iMv|3qDtsmz$08TZ2`}MuU;6mHgHue(PGj z*2F_)dU+*l@iMCXFKdIIhz+nj_0VcKus{7@$Q<^u+j~8oj{nYm-VnEe`ri|V2l@F< z+T=90Je4|89Mr$W)IDPQ0=hwg+I79%W{^NQWVb2Y@X1{K1tRI8;@F~pM;2jxZ=+s2 zp_kCE*VsQnAWZb9R0C=#y?30Mm3l4Wd_>yyh$C@Ogv?kHpuNy|8CMZd1mNR=PLLsn z&^Zw)13~5x_yE=nP)YyQxd%Y9o$mN#U*qsn-Dka@|2)iRQ*U?btMjSUswlh8b5vfs z&TNGS1r$yCvNZ4Q`Vs?0d11oy`Jb{{+MVJLf92L84*O|I0uGz!|H+hyaWJMfvR{5) zbL>rnWjBR>?|5h1k6EZMw9&W77upE*wVz1W^*}u7#0blf9y&N3q(_+$)A_^$p{vrK zjXZyFn1|yHA3Ps9t8LJmewc$QnrXbLDWTaohuIf4Pgv`O?_GhM$q=x^0V!PDvZM2p zCi}p?Nz2I)^B|i<+whU)SECDR|F_qgp)gR5s(5eM#|djLGKZ$8$^isOYC^b_I>#@h zmQV}%b5v<~0u^65lqh^f%_^Pk_!9hfomDjzcsMZJ30(M7UmOPK`!pQ4`_GUY%`+$A z(7x7;30>%@>bv2;^NHta^!vZ}(P<4okun)ISYe>rTAp&=ik-TxwJNb4R zC-CSyND_zFez0>7wW3&0zKpS$V_z3ow4HAm`UpIdHTLC+3orM1m|J20z*~Uirs6xvKv9MzRR%t6x`OUuWZ%;U>T3_6-K?6V(fSax1&)(MRjJ$1bU3g*kp%Y6jyfDVQJ^Z#2V+<4#>5YH_+`TtLKiY@@? zQfNUhe|e;p?5YQ!fg0L&BRcID9nBu3(+AmTIu1ZBKa54?kpmY@^{vTdYkkv&K=LbK z`#T1O1l*0j^O1)`IM;R~5Z$%Th+mZOs-|_qnekPdFUNTA-2dI^2Hj+J4jl3I9Rbbs z<|pRae$cIl53=bEK6t14qi;^JwO(sLANH=>nn+!B{~VQi_Wmkr;;&@V=QrJ^>qw*= zlkNvlQlhgNl9B*Q$rr4OD3z2Vs|#c)m_TvLei31#P_?ER#)J( zFCPkwsr#MD3sfN|kc_k2coB_^Bt~NdZ`;|4s1CxcK_(%IkZCYW=rE3+=vTR%_)qoU z9T$~l`9zh9b>g1to|B2T6s~gpY^LgtMA>9v6KeilzS@such}A+QPupbS+&*LS0*GR z+YefC=@c8IhSP36SVhIfCyW2qxY%ko>*|ZaKQuwx89n`1M1R)HK1z(ULHR@msIAg= zo+v9!GbPI=QW{(#C1y}Bj6NqfN+x!TqmO}lnL$ci8!W;mink<*CoB;jP!CNHU8*{- zeZc5f>kG0nYtB8_&0$M&6uzRM)FM;&#-g;K0>A$SyLraMJ#Hzhq@s??t*a@o!wjL*@Ai7k$=wd^t>PAjf>Be24rFCNS~jrnn?3YE9ksFh{Gn{bCqcS zgc>flHa=oaltEw~%Mp-us5@kUBZ(KYi+PMxk4vkfC+4l9(N^Up(yQ!Ek(?C0vEPdv zj2cciVhz%0^@jE|*1nC)PoMAfoV&*2JiWA^BII!VC`}J?A(XRU!>D-%P7C?;Tw_6;bKfbiOm^+KNi` zfE0zcOg-qR%I2r7s(*<_Es-iu)t%luDr4M(Mrd86mv}1cmTmDCr^0eJ*v&RB8xqz1 zUkal-ilvv1vCg-=5&zL>eVa@w+i6;eNN#M6R(LS>kGWT<2bQdlFC#-UP)u#;%o3GJ zwl-iAP6uoyH)M!iQ^`hFK zm$dZ`gK@i(7v9L2XEcWMDsOv6;VX*Lfm-}Lz7|L?s=)6*sg34HYC@`%a#6R4I!`Uq zy-1O!CQu#Erj#Sv_$@W7thRTaZoAd0nk{(kBj@iB{~75J83s@WE^&XTaf+r7u{7+E z?o#HHS`<$B?LchP!BrHLSWe=g8Az5T_1ypZjZSaME?t}~r2F;C?eV@&Ri`;~jTmTt z$=IOUK)l3=A(~%NUD;=8`iu#C*H1QM!PJ`AQ(RCUkHu9MDm5~3_4y<*a`Cb6$G-M` zj%dJjNd6Rt!WPx~&Dwc)=!~=ZJipZpwcZbL#Uy2NB@S1atRxlV)K+PW>Y>@o^~=y@ zyngobyh);}!>m#Dt*%jJbEKuIL%gJKei%X9ATywQB& zn=iyH$o=nNF3eu$on}D1hWY<))$TTR+bh+p|A{e-OT=E;Uu0fO>Z4I0>B9^%f2A_0 zF=&H8@-qkBO^L_^n|!x?6~ayu5?v*#G(IEW5hz`eG$2x0hY zNmxJs%P|0R?D_O>C@U&D3L7W)!xvxyte@khl_cuHjc__0zVRTHwDOXpU+G;=0p3p@ zhmCUh7OBcm@zy19=MbHYTTM|>ULIW6HDUCa?=J7(U6GTQTUC|2b^)#_gF-wYke$0# z{!Re_(!d~@OeB|^#xg>Cn?~BVw>1BP=UpIT^qFtxN1MuXwOU>I%c2O6v!p^$P^`=| zw45&QaoW+c?LT<#1(UaRkoW3&&R!%W#@#+S7hhfww+tcQ)A$-h{< zN8Og@D;^S$54%%O1c0LqeZeemRyowSlgHcHH>6BD_pay-#&qF=aVCS2X}nN4&FEa- zrMlF7GP}N;jI*y^XyKsgC?wa;)sBlqVaTE`w0*p=88MY%hD4ZWOd=ctvK3{rQJJCO zDib-ySC+Gw;Op6q1odLZ|EoNV`+eB*#kv`Z~R|e0@V1gQKAJ zRiQ+3bYh3sw|WBcaPBQ4;q=;91Sp80o>_-b6;Nq4+04)#H2Q48`#&{hx6RG1Xw_K; zZXmsF+Sm-tGmGOjfbIPvHkk_F{c!H}gui(B5Y&WPr@ zN0*}Sb?6j3n2Q59JBH=RHhwNI+sbBdT_b;P#C|g&%?-^peGSyq)bOq@$)XU&&TIsN z<6MfckgN1=dH*9N()Nz7p$XMOu-7vDdGCG>Kv54F4@`k!!DXGbqi&;9nm!}m zJ)h*gpQ5}ZUfSN;KAEB4zXxiPy*lcWmyU&EFx4D624l?}!)OM>m>bsrV6jX$da%e_ zR@6O+4eg0Hn`WT~J6Mn)P0WI^2!k)MY{lWWuc*d(d#k+ryb0d1z6o1CzGZMc_XNyV z#w>1XK!);kdeN3+#xuN-4{G`J8LYkN{@htUG~c3Vc{3!(jK`Xfc|s*RVZ&jbsO7^# zg|u~%y4b$>X}*&s&2r{#O7Qn_y^P?M^Z%F*?g1g%ZGv_5#Pw(EP4JKAFNRkC?8Tt9 zP9LsDcvI%#{4-l2kRW=;@-Jn^gt{t^lkrv@TFB)VhKk>2aPq4D%_Gc+Uac}C5X@G+ z63r0uEW`X*$Io?qps~1-$kg4FTzVs_<&Vl|O%NRIdK5XG8@ZM zFv<$^e2Bx-q?b7m^QRg7Rj{gx9CQvG7d`2RhsC3KrVZP8 zYzI{olLgqauSabKPG87DjXZ~-a9IcasfBiK<*`svnSLeq>1FiwwGj<@egw5O6qnme z0w5dt#0$bKB3^tZ^Dn|3sXeC}X>HWzq(GLsg1F3I4bNLMb;6o2TT#UQM*Sa{tjNpR z9-Sc+s#t2J+m*|Da zXTVXA{IcXgJhoeiO(NTVw3!hebzL;Kc0fp28`?5LxN(v=59iaj!e#UbBT_s#t~Su? z$V>8*u^yoFxAZOf(tLllzpK<$hSEP2{TGEoJy>L1lu8(s13G0#=cah5{e2gPf)aw( z?7R5j;t?V`_r5+Fc`aVHC&7|V;)5}rwuJo`EOk*Ue|K(lmAd{HtgCl6KSn&le4-Bv zxmunn&8(rof?F-NL{*2ZQT1(XexOFEG?aRtggYCcP-t|yy-3^8E6q0OAF_q_gcb== zTV+;|@;KGj(0h~bw>lk}YICS>@}s<6iFPQI;{%$CMvLj(PPGa&-%}H6pKZL#vvkH( zu9oixx)rB+T{6Nyqi_xtR+{U+RIwo_-H1AYF&@t$O1y6X>27chrIJz;e3um98&8oF z_B8K^xkIQV+=N@JEpj)V;dVMuc>O%JL7%N)qAu#jQY+>2u%1H zrt?47jY*cM&tEvrNa>BBS;Z8C`Lh=0yqSqn!vWdY*cL|9%f_{?=`Fb_%X8rL&Z2I z&*$(wVPmej+~l!tMQPp{KoLIBiT-Y^=QcJ_<7)j--CsS{tombmkhPoc&oq=?f=|YjVsYzMrmk)0!LY|BazeAI_wTk3Hb7;s(e|xTZw&#$O5N{m?3N-&n>y z4|o?;`|3Khch{W}c9X5gTuw0nS(1tORMy0@kiE>>Rs*&Fa3+3wMTZ z`!wbIW~bHDM@E!I*^NyPS}8u3v!o&n%`2GlA0DCA- zxJ zJ=RK$&wB+1qj>LwaYk@@lA18w@QfWNg;p|tjwhb?)2DkC8gna8Zn6)0j?dz{#P!^f|p0o!ZREo3rA zjnWQIKf3;fS-~rv7weCv2Wz9$7}aWv^obtXK>e^hYEIpI3ASDYq{6SZ!xlm)CN}kZ zPJYJxsa7*7XFLx7lA~Uxu;)pbieI*946sFZqQWt3sXWM-Cm8k0rA$zUMDnmEClYd5njVVt^VX#Mp~}$)bcO{OVw`}XP1ub`uhf{?!7-jZn%Mg`?Tw{9$q2* zMGaTGZ_PSbvS+H-^I<$42=OsZY7M~TO*#+J${rsxhS zv#)?j`vhTv&GHh(zDMW0go3XPT2v|*gKF^<$$6a~drB~xqU*Wt9UA>^ou@7Y9fXGL zk3>PcWH=U{IaB!RmG!=aNR{WD+YpVyc31sn?-Az9h zHDd<|h;fgiAZ*B=1n3rf`@UVqM3%u^u~SIPKwW)Wd$F!)TUZXv%irHAw3(VG#a6=e z42H7u4*OmQ%PCLD%U2{Nhxyp1rugK+pqgF^K3PxCR^Q&hUMQq6pD|pA8oorL>7Mjk z9&0S-HEV0kV>!D`wDbF2(r_&l9IiDK=@r`OigGL&_=iHTRD$?q*C1&p3on`(wJxPf zXo}v%GXr(Z%_oFjsbuj>+yqfbP&|xet174yoK|W_!{GOAQzGEkS%|ltQqKN5?s=-s zp1=7*^(G>o-Wgg}7P|8^(VuU|z4^*^6jH!D^03BydV!mosmi^KT5OnWFS7Q0pKPVp z%O*QHaR_jd_ctP|DLVYFV|;398%oGDEDFCFkd{ z^Cd$y?^)>MPoeP0$*HsF&)>WM_V@eR`*k`zEiEht{X@$?+{fF7gzdY5bETeh=g@-p=kSG1(wZI)g#T#aQN9{77fB(t=jp|Us` z0*ctPwFItd2PL96-6RqYv@-~ucC59y07O%F4T8%;T{|_4M3nT5g8~_8vFj}mzjY#WcPkUv~h!OB0DT6f2Dv;3+B$=?Kv4-9Y##G~OOB6P1s zFT5KL+t{ra23P!2T3$u$?WKkrCy7?X8$&{3whbUBOnYr0M7x-~xZ1f!m`6mz8GcnT zZ*yO<+~hVIIilWd_Y^z}p=KWLr&_p+S0ir$^)?NxrZUk@Msi*?1J6vaoYEa@VOi9- zgYbSR!Frl>W4YLF6Hn~(YY^UoxBF}a4;2T)r7oA^ur};1*yb$7k()#k{8+@JV1Nq* zKZ-a8ClPNRQDj-f?W^BFjaV%I5o;ITuea9;Z)u)FX%718u2`u1Rwz-`s4Qo&{6O4)3K}I@r{5iFd*sfT#5aR{3htO=Nw$_D8)Et0K0o zQq0Xi86aj>k-L^MSep1RoUtyF-0}u0JZkOP9Gcu>;hCyJt1?9D@0S3g3pmQwAZEQ0 z&V=;&Zb;*v%Aga1IFh9ww?rO=UBxw5nG??^{A#%Ih}{hYaJMwvy@8(Tcr9flL%$js zc38|}+lQ6Hbi!$du(7Lr?PT1pe&ycyTB?qo8Q!veX|i45bh1U}hFfAP7$yP$-3=3MsHjS0^k*eXiE&SpvktRM%j zZ{K_pj{9xwr8B;bMc40Qf_9Vbuv*o!g@D^qT^clvSDj^f$dS_sU7PnpO-&7UlBq7V zx`GwA0Ct>y;XNPAY`x5&?(L)+eLLw=0Wb+)%9mhF=9hRUvS5y^6eL3}E>fXa;)F>EXg2O8Om*AqR3LIfe z%lhEBLX5-lMeY&hfs0dwn;pbqd$s(M;<4BexgX~M7LtKrav^;Wzc87wrM+JWOrXN$ zMrNdxB3DSW~Cc(=EBNHy#2UM`q1v z+VZ~jR^`*N_3y2UsNNjSsOG4?oO1e~S@=~J^Jr`4_}7M;Oy1N=@zMT=ltj6aAeqsE zHTF<5KoHU@!tWrbFeDrsenSm1H~0MTtzW}{}Yf2 z+N^C^f&r}GF+3Ixm-;Ckrx}n$Y9-qf1_+7dE`J@=gBOrb&?!mt^F%uerwz&#iZIa6 znfq}f38=jJK!$PFjBl)>vTFfBffX zHtE^RW5e$FRpcE6UsEs=F3!Mjbk78qv>fgVsqYgru&b08>?z&T6A?Q16*Hk)d zLMT5rd2TXmdulf~fU2O(_(&Dw^{r@nvk?Cnrfr%ym$Q<6GV31s_W%18=V`85#Npe2 z_RAx`vS>Mxb>D_Kt>mtQ0@?Q%e#7MZStrzK@SN}%sM6FacW3y#)5M$FA-!bp{Di^AD#c6K@YwB?R4v4zGaBSCdWzppFVbbkDEV%kLfTt<{Kdjx`rHe5&_qk5Zl zkuFB#+BhQP494qoHME`65%w_-ZX$;)WO$6Ge%Qntw$XF>nro`4EN0Ah?0!rz^SNb9 zF5bmlZn3w^QW^Kn@m-=&*HD2X|M(lC9w2h%`K{3A<*S%aix~wd%xbh*Z6+R1Qv8`? zki&HIfESzNa0!)H$p9kw`d-f?{L)3x*x?;k6p@IiP98z9UF4{)?_thy8O7gG$o~Zn-b+3xa=VF%nb>j+n~wlTNjHvIpQAK{{@ti+MN7mkvEepjT(y%Sb>vt1a(Wi2`VGVTNs(XcQx6CR}Va1E1x3Sw{lzFpJ)vr3#|Mc-!V_503bPoS zr)iYt;1|f3wcH$l+j4cIme$6rEnFanTl*6EBDk4Co8HXGDx~TWW^8v7@Y6xfczkov zG@h{2b_Rc!cx(545^28Rrv>R}!90m{fA=k)%T@+uqMN>s$1k&FAi2LVHiG0ZrhCvn}(-`qe}=n+2m%*^w<*X#Vlvu0v`=X#vKcTnYz!lVjAMPL}cO2wL6 z8MxALrF7*ZSLmqfXP0FU8I(qPMA}?8w}hfL6AvhuN&0Kz7?|wd0Ih$2Z);wmI1zA~V`8l^L3fw{6eqp4Zztf0l;};|3vq#A_*g%wD}O1Tx#X&~ zq|#alb47fs)DIsU78qAIRICfKZT}UYDl5wxrr=^t<6~X1vHEqf=vY%+>=iizavy^bx9$dKn|Bp`a^tPN$Fp z+DdKR#MVGcq0SuC6%3_vK+4#|R?FieFl{t^Zef~bD-K*OUF`;!7R0q$rWNMmX>Aw; z9j?Z379WmLz&I2tW1G9JyN!M2uDeI?-Q;)0M`32G562@Ac(}f;nZoCa-=tpDnnSguo#XIK*|Em~4E3gp__F4kdKFeDO$;oSa#l$>C4ot;N~w?ItsL81 zy|%X!T71v6X}%0i2FqJBC1ywt$iMRT3kUCHW+DxL%=DHyypYDIO9@oi_Y^8^)vx#J z#udHsu!-Ww;Rq@FFFobEij6dm{vb^q1y8d#tf$ciSwIwu8^PY*=T zMGu^|qqOsW@oF-HFQvQ9Gsjguz>jS>H>e8ghTHZ7=uwSEg*Q#|-BfORXT2`5OWG(6 z|9h}B0hzn^>0`bOj$eYV^JWxU#z%z?*RRafxznm%NeO7^rKq3fe2x4<@N!m@69}tL z5m*Kqt*WgW2HJ#Es|X2Xb-Ws|ILXqSQ_X3zPFetJX-0})pkJh)%1?3&{Jlor4ZNFj z8+`E<&T=sK+2XA`=XVC7uBiVz^bg>wmlKj=ni7(GXU)b8ZA?6zkao*@az5l4ya|rz zfx39r#PbxS;hPo$*WS0;3?GLbm1Hlva|-m4P=ncI1K&QPMV7Pgh1Q zCphejBj-z4Fvl5dKViVOfk0@m9Uyc@vM%k8ryg*P=i0jVYfv9P&_Qx$)ph+EvO4#{ zjwjFD*qj;??h2XHEufyJ7U<4FT*E_Z^3#e=gfmP87wCkoEv43b38x8rtxH?B66hBM zCJcBYx&~)=yJ_ZwRGv|+dobw8WktHg+64PMMHwVvGlaLweBt04rgC}oOZDr7i>iOZ z2Gwls&l9f12JVM>=xRBy|6XnRWVaTtE7w3udhcjX9n8MsNu_#jf=#75FsXc)S5dD= z$f23O!o%Zvo5Py0=)&~Vk&&mRzo6mf4a!V3=F1ly*rnExjjuT2h{D}198SybLPR*{mHZXJIJv@I zrjWU>ILQEBnJIWe*+BW5wNY#o%p{i$^(5%n=omwB8)1Z}2=UdZN39E4Xyx}oR9sS= zb$Kt=o78()>i8-j(^b0;3)#L0JP@bB4R$yng)5YHl+no++-3dYe_*jb@c*!!F_}IX z#(q8q!{5)qbY2^*qa%~9WQCb@86kg$a>$NxFTy&uNc0`!oAc(Hcn!piLUx5Ux`ZXYcDX^r@rH`>`*`Pv7|AEJk6)j=-if;up~&-Plk>u#<=!i`MaRg zUup4yI~C#iQU3{DXR-piXMYAYyfHj6|D92_zx}fgNt8sJ4l+OcA+bIkvL-W;iQlf9 z@frq|aq*aj0xXsi1>cuUTB;2|18T;FDXKSn>(1OoL$>#d3%si()XXE>sWRqfrS*aD z%>G^C2u_pg+_q0>d!C@6onAn1FA(Ilhx(Y%8`?qj`$9OA3*-Xw!XyV0rl;?*I*O|$ zw9FB-M8LF`+uZJqc_40W%UZAqBN9jUQYBaq?EH8vVXn)t?)lF0k=fgycgE$6IgaJv zHV0KpzPVPfolrn%*IRq@D~;}X+SQiTBH&ke4r%T4`K{sqDM$sR*#E>^=bx{omQdb` z3Tc#kRX;gNO!5783i0F<^_eR?D$-U1gE>R=G{VFZ=b-Ls^;#~6;|g%$%U->~Sez%V z{@DEG99aH+;tJplIvZG1RkUg6j0LW={9bNi7}%f^=47zP^wH7(^y{b@k8WEu_tNJLKTHJHs1POicgp?7@n#hY;&Tqu6n_g%=Amk_*6-8NyysYQXTB>{wA9) zRM$10xFzbRhJ(IgJ`K?IAxWVkG!Kg0+cGd$w|#nMa`MK>Ysl_Y9QyodA&2$8o}KFV z(x4iyE6iN=_<^p{09BMa8;Q(TM@dz#Qi|d42FzXQp%i)l)Y<2@heN1Q-tX+}B~|AU z8pBm`{^csu0^S2y`PlDm^w4QL1f+5l9Idj?8_)F2yxD=)ek$ZhTQ5(Vp7;31OEe)P zub#YlaB6ybdp*;fQ2Fsb-e3^|Je*WLF>zZPJ{S;k%)hj9>qo&+(c0dGvQqVtkD#Av zA&L*|b%0+gxJ}P{8eH^C+_jtm){Y~uorr$)jyg`y4Gjl5rp|EvKH-NJaPVySM__K< zXxM17nd=2O5c7bL({lQ?cYDbuPpaxRp5qGWEfg%`E|`%A=vDYNzsdCWHKEctbe?n*BdaZ8#M(07%}zYGNe+|AnRMehZT6iWYV1Exp8R1G$Bb#ddocYf z09;K!c-Lt)kIIv6JNb=UZ*Fhvi9|p!4bF|p^cgpWwXIWMm3PZwGW!s#Iv{!h#_bc2$hn2b;is+PDg1YY<)Z(0u6Vz2O4<_ZGDhoTzzw8u3Zfwo{(#<)DPn# z830t2_MHvT1SdhX@A+wSk1<~zDJc+Y1R4fF#6%yhBM+Z?DlHNiNibW`M3xLn-*CLS z|5TrQ96@@n^UxZ{mCAiBt=u2QOFB-D3xdWEt@nWL5<$@teLt)R&y$Dq)7Q7~g%k4k z7yUl4kNK(v;og@-ZPIY*<6Pf%!ICukc?*cP^Zho)DVj`G~H<3n*zix+5n5QYR}jpVM{z6<6h{*CPsdB z{`o3b6}lC@0<8*0wQKdfD~c}r_GQzYoTp~^>BEN`$?V_ zgtfJec>ow-Zn_(47fT#7{Rvg}fumqwU1mI=lxao{JoLZdzu2MX_$Hh?XQyD^@J$vF z{hdab`6xJQuAv9V>}k+|v4Fz;v&Fm^EEbvtZOn#B&GAiEnB(|?tUJgDQCF|tm>fjn zCySp32BfDJ6;$O{1TO3cW_XXtYG3EE`{-B63IW1LY-J`_w6ljFNMucx}E*35Ugr&VXk;SHi+6Z_6SZ zw~esd*=xHQD}HY8Na{dkgUw(axD7-d+?BK|;HQCdCFlvRR2qKUy9b(>pKC~B2w{gC zKOyWrZkY;H-Ru2ORe8WgU|KtVCOUNI z?q{L#0p4*Rj$SW!!=E_~2=ciY`vPk>ynY(EKnjV4TDg{LkA&4?2ZlqWS&Vj4cejNA zCt=*kY6@t0f@kQt5EoXd_CfARg1L|%dz5tUR%unqrwD*yE2<+AidQ`JY46n}p5qG#vZFhxN>GuMV@z zVJmnN+}7QqI!wyi;s+XQtwjVSC3Z3p?tE0i$F)1Bz{Jj^AjH~toyF(^Na83s$~fEd zFrnoELlSi#R=1qxV$ehE?vtQ<6NUD3Dq;+0%eE55GX^N0tH=&Sts6ATk+#fHn6op# ze5mG20}7I+iG3>!-yT_Q;*prAhwmA33Hw%X%R?yYQO##m=yd3;7hZP2I>M$yhwk$3 zi=9pgPsA23j~I54Dp{_eE31;!VK}lZWQ#x%ea`6sYA0<0T%hel9dMeXi>%gQPx(oi zh)Gl~t)}MYvktrF2mSbtc>NDuH~Chg@MX^W`t@7a?l$npdGh3Z51hY&0nVTA5$dV! zk2TmGwwu-(i!Q%oD+6VAw=2-GEwtU9iUx2LY+Ihv-`eF@oCri=XA76p(piXz;O0GZ z%GF9Hmsz=wA!_u*vA`AQFF|49Ta7tGwcv+hRxEVGpRPgS4e7KtO?oPs)#i()@x zjnD7zeegrUZfyQ0WaS44MA_NKe;36%)b+1l(5Nq7uczt^G^_qpr1++Yjqtbk{JoBy z4!k?n1P(V%>2|YkxcfSupW%V@1z#INxjh%7#L zib6ScP7H~J5Z%}dg<8)6)y4$nNXLoum%u=q&e3Vx4Si_vkG%tlwC;Mkd~2WQaL353 zV;R55 z`)>4q*KNDx2h;eu)? zc(?(OYds+kyud|II^yPWj+4>2*W?YZP3$c*!>qgo=U)LVXzE||X$RW>3YDTQxUGTx z=@=6*KIL*e6hH+-F*dtdXbh@TgeI(qMXO^xptlCno$)|$=iA!XBz$4OazgYc<99S&Cq zq}t8c#Lu$6KwL>GZrNqH)RIUe`IisKY*82%8&>2V*-Ek3o*@>H*>5c+UwE~6T4-Jg zt%+8W7fQp|27Zb9C#roRxa;zsbbOj-J-(|4^=vi>)r1O~eTF)`gE4}E?ztp$(5~y{30A4_$zhF-n@fF3^_$It{aRuHTIb_u= zrGPZ6?L*NF&|Gf#PJCv!ff#I;3oIL+#D_G}i^L;D(vid$Bw9*>WCkl0N*|g!Y_YGM zW&UaMT!L7z@sFv_G;EhomI z0tqhv17;fU4b*dr9lQhDV-ix+QVCpqI=LS2QldU}V>YT?5A~u}7TT;9{fe!pGDm8o zyIwG8RjchDD@xKv)_vR-grsU5!7$~`Ul66v8PUd_mZs$AMgyE&<)a$c*8&M7XlzS0 zm!%@78>51VR$%cpQFn}K6rfy(01I=OZ^&JEG;ufkTAnuzVbWEEJ!aJ)X?pE##Dl6W<=T(vSNV@g9;{}j{%@pAjf6k*ct;|^2 zjb8PyRpd08oNa5vzOmR8IfdRiHbfu7Y{htDHnNp(KMoaVp6R{oG?Db}nE#PrlF+8I z*2k(2=pI_LM!iq-r@5ON_7d!+ifDGY6&w5ml`dh;*BxRuVR)*{Io@C8ui45aDv8q+ zg__i((fG`fqT6@`eq$+c6DwhbK`B^LrJ!SNSapx$zzgPvKSfzdkWSjo1`zB7^bW^U z;TIU%$6q%P;|Oj1y?ElLZ#x6H1Og{u@M{M_C9iyOPOj&l1o{r|$3C1 zKKDq*C=@?K@w}gr7Tc-1+yt=4 zGvkZR*SAYn5%9Vtm3XXZi)>H4;OA*rTwHv7LTF;5m)y&?NY1y`)Gg%mZS-vI?7e-- zKBgO>8g0QT_+@UiHUC>6x+agHQYdqB0Ao$1eM9{kee>V1S4J>2B5rH<vuAaJiW_o5|$Bv=F+H(kaLTFMg-^81;hZXGZNNII;Kz>c_9SM?%(J5b8YOMvYjpk#h2P?xukCm(7F z8G@}ZXQ$PwaE*E&%X zFuinkpe_O{fPPgOTUUe^_n}u*7puHV2ST$Ep*r$PYtf?eb=t0XzLVIvSIARfMO-`* zmX*6IH!JMOBJo|e54736($eFFt90IF1nWogk4Ue)@4?^Pr;#xCB@wIB{r83K;X-s- z_W7rCJLHodQMR0jdLUNtfv1q(9sDl(zirLUNx98c|A8FUuuh;{X)P^J!g6%c|2cw1 z)Z&mE66H435{BqOA>Raxf@*9SoACIP0>)pGow_kl;=t)6=KR2C29RMkB_&sOh8fIz`u9H9v<1iP@l z?~}0Dqz^t=tj~v+i+=Bm2?OV9wc=wKd+UaTo4@a|M>i8TY-Oux|2*12qiuNf4=qhf zx*OI>Bz1<}B{^Oa(a~9O8SC>miHS}A!*sOopVUv#Nq>D9rHtEMfknF*(ZG0%F#s61 zj04e(T}6Rix0&laakGACIwxGt%FYtT-Yr*qt7D&o#W}C`S)nlUNA?(u{UbSsk^L@> zgoX#EYxN}UT{dIkPN1yzy~+^>f3{S~u?JGL4j7_I>sooYT$$+atM_!`RJZS#9Eyn- z#{f}G!)HFCZ_i#PW#^9*{LbmjHI+~#ttNG?mtC}-eeQ|SpRmDpRy7_)p(WH?Nrc_fr$WpgliBihD z#V@O){C$<0{Q$uWLjvpS{e9nu`lrTv48@KlSnegS{Z%|V0j+PBUJ^1}LT|!v-trw^L4Es0UJL>OoG+MnNy!-mLS8vrD<4s{E^R?c;fSkbYb~cKHX%oAmSY(aS$c{XCyx zHmG+?uKFmxM+AFnjwdiwk%99h_|Pm2AIY2>_&bTV8(rsABNMf(!tb3kKS4gp*S{J?99x z!jJJ`@i^~=7yEya2*X~(Qzw(r)o>S50?co44%8xUfohNW*uUzg)`j_m4W>Q_lhkhb zM=px*U^?zpJQ>v|>It4lB1i}tO| zkZVInRev7LwTQ0(R0=JHN?ZR6@tbG6I7ad1aD0HHZ%(s0&|l%!V;w9ji@QvV=<6&MJ$zhUzID5nbtZi<^kPi1qN52H+!van9qcSpxOe1*&no)5u>8ui z%h&gNJ34U8K+&yd?Yak?+C=F6DZe1*^7Jl+7Ly)(rU0z}I^3TkT_Vf7ZthG!g@aMh|)N z)qI8sM*J43a#CICy`nO{6FDGG>h9;I5q99mKW+;Lq7U4C4mjLN;Dg}|{MnBVKf^H% z+oO@iT5?qp;2c?`<)tbHwgyVh6Di8;&2^05+M}8^8XQrb`c1}&)ACv&HlB%Ax2r|A zTVP6S!nKIY=dXJ*34XHB+L7x(&J-FGsBLzeh;xA%gDVpN91TWzOp~wPW(rIm#_EdR z)7frfs^Ug$QlmfQJx9k1W6@XgK14^@jF6u+@Yk9ZiDxVPF_UY3^-rt_FS2rEd87wF z+x3V~MIXy-_u0YW^AW$qqSjV? zhxa;~q@bUE(c8T!VaTKK`f;ta@QDXbe8Q~?1UYlicdxgi51W@#i7 z{Uq^Nrl2<+4Z7Z%A$<%Tz;5F zLlg8M5u#=S8}@*E^ey3+aFtN!BmE$|-?=IOP7mt>@DiX#I0Y>DLO~xLF;tm#8C;Im z)dzRpxR?~iX4}i=VX#w2xyT)ISl6E!ao)yWvWG?__a0*zoL_c4DMli7G%Pjm=Vj;My7^^c8j zv2Sx_)KY?q7K+VvQifl)xYOQ5Bxv6>kI6)DDDAskU1Jwr!cSE+X?N!ImymXAyC38f z7$rWo&)7~Ys6eZjrGetp!rkfh?Czwarrq*`!cQ3_*Pj8O9p2u{WWOIJZwf(YNE@&WuNYMTy ze?W{k3@wT*(OWLfejalqexYsE6CJI=_MyIUEs!m8;I?W^mua#7wbTUoBn`^JwFNuv zn!4?0I@iCjyXZp8JQSGs1VrI){V>n6oeuS?Ja2V=*t?NEx@%*K&0R;Vii%Tdv8F0$fzvkp~(?i>f z=7$M<%Qk$r$z4;U$OSYl|7B^FO>4Ar9YkzUYrJo$eNap1Nxr6SAzxwDuv+Dr#;OO~ zvOx{>5WIDPRd+OZ1!l#9^>E$1x?bjU5T9GBQbjnl>yaUOVE{Vca=~4+;C1M>64i>2 z!36^)@mUKyu;ymo(ot}$?{MHFwe{}p@D}ZXNwCu)lsdc*=A2QpimeUa{Vjs}IoeeHX&^ z8C#7)#0P~{?n7!I@oK~{k%)xTT1VH}K7xQ|HxFQTBU^HqFMhXqX$-TSp@#uqmx%ki zB>3azBzpc$%dBBp)q4W+cRwd57Fc(82u~B@YnseZnAyOVrq54Pw`dC&Ame~}JXnJM z{VV+M>)!^n&EV#Ka4q_E<^+)GsHGJA$`b;%UOK-RD6{(DL(Q#?lu&>=x7tCE2Jqho zk?eoZMUW&Y*(+k7fcMf37R+Zf5r&hAB)8r7=v#@_AO}jfPSjJJ%ik&&*He8yu0C3A z2d07j#($Q;j^5l?_0iVfmgFscv(z&u02`2g68ciYKCS=*SL_f~uf_ zJXK&|#Ks%!R;Wtf%0so^M3}=-P=fa@DkdX_adVqWi*7q1S0b!P&AX#LugU{7^X3YN z*rY9D>(Aot5kHgalj<2|EB3)Nv;`4PoCA_pLvC}J#6t*@%}A!;hzRFG+>#(}a$A@y zt43&HU<_LeaX(TgdG&uap*bj>l5M!v*j_b?U*MaGsL$6oX^-+dLK2$5%dxAb zd7?SkiR#3+uAYZ@Y;4lr#@m&SjQAGamhlWrzy$S-=M0|Vib*IkAKptw74@eH zLjr8_@`J%W+CO}IiKp9&xF4#p`0qOp;5!I8)wOhKK9!mnMcdR*p`PA!_wB0Ki&p0E z|Gb%o6vT_}bTM65mKLztQ1Hta_Re)Sf4_iLgfk?vYH2@?-0XC_&gm0f%}wviOw{Yp z;>+(n&l--&+K_m-B7E(lFNMAVO;VF{H_)}Na@(xJ^O|>67|>PT1&|&Q|83^lKm z?$;eAU7cLY{_Ec4 z^*F!!-2U!A#CIqsnKgIysNWKTYH<%T_JDYs2kgjwOu)5>X`zgiIXi* zDbz_0b5rXi0Z|7y>p(Xqm;QM}H+%k=9&e`KNiAV$`eKeVY%sWFtr{G*#w-cv<`N-l zcm3)b=_y+G=njqL7L8fky~AU-OY0-Ccn*W^B6lqpEf0q;Az1I<8jKsJ;5P$Hn9U5g zd~8X}oDGMeaw}nOu*zH%42Is7LI(&!@LSc3csKm>jIH>;CqCmj-ex5ZzOAAO4r?mk z1~b#dL(?nG6TJQV2;Nk&4er?@FR(VY#^P!%3UKDe=Exlgtedf0fvvLF&{u3YEq1_! z0GDim&OQ!(ymT398om*S8+}X`*wTCUZt`97X`px08+?|0H|_1APp-6BYGS0#@EK}1 z^~|tMWFmF3cPfY{r#IPcAl@Zzu-i0!lBj*HN#bg7>lP6Wz%QZiqA$S#H1Y36W8f-j zy0*F(NsB!~+wMrkB*5WVG!~6!vrHo42(=3ri$|~%*%Z42I_I2Qka$(tFOkYhEIyD_ zUQ~Wo?qkdik(bJgF!Do6ycedLv1ep5uP2{h^#HGmlF3vP`(&zcg9udw^K))qE^ocy zJ3%)+nWQB%*a_iK3-Q|7L-LEnGU7$~p|jVB``*MuurRPI1Tn6nM-zaQK>*F33LGxC z2hzV(ke=MElUFp82!6#C_=(m={q=-0!g~G2)(JcTywo;t8+8fB83>F!z=`3Qif(ur zyt@JehwT=j9}R=wW!ITGsicC?8*`p8N;n_WOThPL!^YXY=Lj7j?R@AW_*Th|nh+fw z$mn{RrY4kxZjJ<$#|4}!a$w+a42RT%K{!&)5qA<)iJ)iR zuMr%k(|5895)1N8hw01@I_k?FOqx;MmvWRrpfVD=fsltGQLyF+gi<--gn5Je7aId7 z*Dtirpni(aMt}KyJda)^g06Z~=(3MtlmgX%S+7hO@BKV={jrCFy4n*tWah!B4_icJ z{rV%?@*(OVlWc%niX`6J?enHl#UuVNP=&Qg+t#br|BpA_5rU6=hc&xIziaP-}-Ep)-72 zd5!}-#O%qaP3iibPCSGI{HPv{56$c-ASXapEi z?oA&3IL5fC%3YkPmuq$?pP+D6J>hcqs%pVif%EfjIbdh?^aQRdbO+sCfxw;~*6Knl z4IcPm&JMZ2G%#KR_42f9Zk&UnRnBotX`ryo)j~m(fiAFmdI*^IRzsyC|B z!na)bD=;nBkmlT818Ox{4rCNPwBrydic{AU5a4__3Rl5}2t142*kxChE#jDZ5WYww z8ILR0*p3IauY8wi(@MO4DQajzWzjBq69my}Vt<8~(6lAr&ufF6vvGJaNV9AwC1G*} z)!+8bs}p%w?n-!bQ`no>J1OgSUKGZ$jTDV294_^v80$V!-78eu#FN~;!aG~MvGu2} zn4J5SCHE%$+=vbT$X=}xsZkE8HxE{Fi;Hy}tWfT7ji)DiZ?0Qllmzl5qUR$?l+|0WAa_A3@#iIQg zdU=&~SbCVW%i-wVrzFzTyGI>%k(!McP404a5y(In(J*}AvI+ygfm+2~yP<NduM6g+q)Isj^iRhZ4q6p>yRx{7-(zn~PUo ze$W)(b>=ChBr(obFyr~3ZONrOLA@K*QFjA(DkrW6Pw{iHtu%R@31oaAZU4&@%ur+U zvNo-%YStt-u12B)oYj%R=y41r14|j*NNkOumL4iBJS0^UY-R&17HaYVE>uXbg@<3$ zsj8-tz~V+Wg6JtP?W|%c5C+2hTjlJkUgAGm+y#*EnD9+As08t-Qvde!sA<^&+(9DN zv(YOdBBXI&H^)ZRHpd`#%Vs^MHYy{p??6>v0B2)8Jva0)XT#dVuVXvrMb$LN0F5t% zFkp;T&@nYp0YMp&LA%r5hi4qmJlyLviY{s54%mh4a-JE~-T51gg{<^2L1rK)q!iZA z$9ad@__UMx6LPpSML$)vIg=vivLn{oHFQy32nyY{-xUWiKsRs<3|)W}?~DWEE)mvG zuMdI;MJtp!COTLQ_TdWv=4R!n8%h7JKo$6?!m^OZtuc@^Tkrh}P9tDdOS`2v_AT^u zFx?sc=6mxBRet;U@@v3~<%dk^1EEWyubo2kL!Gpuz*9US>khCm3+?gB7dnZ`8lC)O z2k3-Vii9F9V!mjgdm;nBwD1Q$ypT1M-uC6UagXY?t$C^WJB6TlHMPlV_d-04x=*2E zM{8oKUW#Vw>EIOxwK;4MF*-ow4}zP;bnW@NK(P(cy}lfXHhV=g!MV=t`Os$OTU7p% zS`)Pmy@6v0`bbXyy2MJ@CZ!W;h_RNUGz5EDR`ycYV+J^;KD3#QMs1eG4zR`-LL-%N z7NL~p{S-1cNcn-9yV>!Qll6L#=Xt)bS!vKy5Oio{D@~IW_^yE@w6%!m85>wMO zn~AV|(-MOT$BW%FEv8S+mw`tNj6;TpZ&&d3`t8d(yfuctVswNRscHpVePsW+4GlY_ z>Y|r={FepD)$gk|iW~Hw^I%5ULLBYB16x>e* zV8H$ZW;;}mYT0haie|=cOSMO>cbKsbv)}#m^<$gw>nkg%GA3f+%jwf!1`tdcwNj~n zfAg{HpWXZMLCER#YWsDPix(y9?A7b1k;r-%E(eFlArSvxh;q0t^?p5r`1R1~5`R-P z9*;KlFPVm}$1`d_HebKq{IQlnzL%vSAi8=03jBotifZN+wkof2Hxh)nltpa-no#}{6FX}V}fjWazG7Vnbc{+id zUenjKnV!;V<%YTT*aWpO@qOSezgeWB^2*lzo5Cu7sG|45wEAy4+j1lM@k)QCHN4bc zYK@L^z$(z@s{(DlECj%QfcVE$N@~N z+bD%B+Qum*!B&V~Z>k}bt8}9rFP9K`ulj2dQdlQL>TtIqw^> zokR+NRtSZlo{31NKSWR*LLq7KhcMIGM3})+b-n%rN7t81pNPTB`vO!#G-P~STG1e? zoUNc_^<=dhNz_Syh-CGMPZUO2lt+K;LU0F_$NAsWskoL{r}fj?DWO2?pv}_-WLnP4 ziaf1ABAoTlX>;9dVVd}tRoO$H@}DQ1#?r`;G^tyP&MG4<$H$_%SvLMRcFg(jdDZ3L zlnj&}Bm24?;&OU<<-Z|smZ1LUvOWM1St_sfDPWf3wH{^DRLacZ#$UQt=*v9Ug<2GB zI;X|dHZ95VSK9KfvjH#EkSjz}p{Q&22G6qV5n66~WSk6Ul{VK)F3n!l$=y@IxlGM0 zo%t{yezcgmzn@J4n75O9)?WIb zuEfy!r!~s&xO7Eax&y?2WRY+q+R`VU|6{b3C|< zbaI8qD`ng~^n^AD>#im9rC%!81RqI{`&^D~1tK%Yai9Iq#o(SEHUnFs9+K$^-4^V> z#%+=n*oj>i(&rB2=aD6fI_ig6NZz~yERW84k1jyLd4>rfU0+>Cbzy;|(T>_H+3SP~ zlmy1rS0q>LP)IiuDgr$s8KIdHW@K5i>|AE9lde)1+4aEHjyRe-GQgQeWXP;-!~q0* zEI#z>Xbo|^N)YE0aNF8#BtsK2u{MWbg~iwebG5ug7@x&o=J2*SM9|gYhXu-v(#{=Jotv5EEI`>=5Y@n!zrgPbRdXt;$}%t?N}hBJ*P;Gtno zd~rU1@|Z`H=v^@LM8uB>-sa72=RWzLPx%1}^eKxeo}8!2$1z22xl(Pamnwr?K(_Rx zK)~sWi=dXt!j0mWBf(tU5=>Vm%SFt`TB>_Ki{elPTn5Tl_CkwxSg%^#BUVBo(@mc^tvDWNUMS7u7HOQ35fLc0*Dz&jno`!U#LSpx`4;adkN}AGg3*B zo?awPFCe1Ny4p*#tn(~eiwsL&a2$Y^rgo!}_Ywx!#o{UDlvS{@{`+Vnl|j3>v7; z0q|c$Si%$B#t&t;p=s$H0wP0+-;5O{P?;`)7_b_8K=*;B>R;NVF$HIbSRe+Jq0!0G z#N-<WMG{Q$3hFGZd;guFqeJ-qdEJ7JXH0D||JUC#!{7h+r;IZu4g$Z6 zuK>W6;@_5?6uLlFRyN!F&CFRNA7GTyu?2wv@>W|k5*gig3yCZhI;b;)f#RgV!80f% z9R5K@Qi?`IB5$^5TUCI3_6+kfGR(M&Kok|$Y+;VJNcxyvOE z3^Ts|2)NReRiNkKx%90v`TeFei%NC9#5+pX+KTAJ5T|#PsjV1tkf!PG6u33`$s- zyt4+0C)#bynGE?lsj!;Zsg{=B(>!@EFht)I`3Dpcbc=7|5#@;KZn2(vrBcuhM@B;8 zRdJoN?s}w4v%W~T#uM7~1_}5 zZsqN5C1=K1Sy>`KdHFpTD^dwdu~7iU(=f%*lM-NL#2}EA3~t$t2!V(722N#t<+!Z! z`dz2KdQqG<)Ze{xjgp+x!&J^+ue=lKV;&o>SKg_E+?}f62og?Z(hkiG-+^m|`)03Y zU{2`2bW`=|bd|SAOH6P-!Q4QrT;55vs!o4W-3+@}xz;yBbBC^Auwq$j9Lhn&e%GvZ zI<@>7h{0j;bAZ-6ew#!ovF*~0zH>JaI*n{kHiO|KUhFAZk>6;=c4FTghcDog zPd|;oXgv+jL1-P!sMEr^oKc^M!b^2Lpg+FM1XWQ7{ee^{C>b>KP zth7H142&EF3Q2`hAxlCoUCQob$lxS110lwKaQ{khCS%H4sE?a95Msj6$0z>o@YTBe zJLrzRdwglvBhD@L8j3?9k3>^b@6u(%BZVGic==4BK#d_u}Gyh%Z~K-hamgO~G5L?iE(+0q?A^ z3n-kASxk3(Yqc&8u?|#!qm-dZ*jKmMLg5>O>crw~L(f(!A<^2$j zcf-by{p9;af<2pUPq_H~3EO7C21X`HDQMNKE&TIyL*S50CXlCw=FYDil9h1MkfR^X zJDBjXjv$^V2_S=P6HV}>a65_2A$m&T(6r&3yk$NZG|Xs`!QOK)rV-3R)s;9Uo!Q}p z+&s58!T=@`bSzkek--?8;VS^^GHqdXMZjRLj0Iv)tv6jm*L(T8dR~)BG-)ozOFUrI z7dZmJ(%z}L#Ot>Ymn(#ZLSfTQA~xQiSL`8tkBBa$a@D^jG>wDleGGui=uaQfgh%|& z;VL8C(VubfDD@R%Ua{ALi^(L`(zYFSx9? z+lr4XSS{SD&oMENfYqc^(PeHtRHyR$tzlM_x3O7-m8U9*E}OAh1Aa(-qkeF{5ux22 z?_da16a>Y=g|ks5Vf=nSW{v8FukH=Hx)6;lWXj_DTCK0Kh6XBa!zDMR^OrWzK#s%L zypC-g_O@MlUjjJPO3*G2LM;~mlDBIco3pJW?`r@DWS>o=iqv>zJ4GczQaFigDnI+P z*~VWJ8oL8?GxkTykC>rukr%6Jl&K?SRBG9!?KF4ke8`iihyk-t(wOj-$Y%S0)~!k8 zq=d{{IUN_orqH%uiV`|9rC0W=W){8|@ZWVkp45^)qCpKT<>kgvnxVa3hVNBZ^s#?# zSwZ^+eU)Dl8W9Zx9kJ9Z45DGZ(U*;njrue-5iV4quhXExm7PEGUTEbdKP=$x`D!ZO zo$xal2@g-cV&MB{$`!!isK>+C;=dWC}v%7d@zPH9>A~4a8 zD^0rWwlV*4#2(NY=z&5ElkKQabql2L*MeHeLp26-UcV)uGl<~8xI8yYu}uF*?55+7 zhrrud4%nNn;!n>^PxI9()ZmVSNQ*kaa|h~X%zY!I6~2ioV*+)o$bub%DD^Ag@1!&Q zbX70N!QKWB{pffzBhC?2BAQn}u}}+Qq?D+8g0;#CNuKiLp@$bHYVCp44rKU$wWob# zfm_JxdXyi{o0)j_kogJI>a2A0z_nuG8Zj#v=KCJV4D&A`@eEOe2MbOpiabTP)kUa-xfP8QaY~@r-0_c0vaqc`F zxYQ}UeGnXL6C*rYlfG6hBQ-vMWGqpq-*>;Wx5n^64BHWq{HcW#@QZ3Bn-e!6w?&!- zQ_A$5m`igKP~wbG)_w15y|gZ(&o;%z-lXK$W*W*??0lF#@ofKD;;1(8H3fg}rc znRZjOqbyGJ_ok>gh>{Xq4+Je^G*CQ`dF(>|12*b%(s0uW?ya0yj>4Y7E?4(6`f1g( z(%Q|&9WA3X1hu1fwE|uB=`#WtxgI8%)r$SEs7(KVP$R?3QFl`_cg5K~(5;t4MD ztXvcjY6kw;`fwLft{@@hF__?<79gUbOMNlp0>H`G0`Hd?E*Jdg{k+p9$$&)|!OptC zJtaeFfuuc{V= z;Z|z8ypw-^j!Ji-)kj!ju+~=YN~7Na@6eHyCkhsWO1;ZPq}CRPL}~$!zxT%>aL9$} z;oBp_=}G*TFHfI3y}ZgP-kNfB%s<8dV1NvoYbTfMMqSF>BY)hrVJ?!~LV@sav=LWO z|J~D9+>55%o-AvZB_Ec#9B4=5YDWinoo)nW;8S~ld9OqUP?XUEe@kypZ z#kbd?Ah<2Z<%SD0ZF82lv{rI05V)1SyS37X^O((x8fLmpLf%GjW6n}t1n4A!2+&Ck zkxS#3)Wj-%IRO#iUAxJC zI;eJ&0-$AC09uv;-~u#6&;@9SVHuzaf-V>Tix7}Ye*_BQk&Lu%3qsO@(1d`KbO_G% zIVbppg#Owb7EvLvBb0fS7?xKdup^Yy%{Z#zdX#8}%4aIkujl-1hI?4j3~IPmC7Pk~ znM(AlJ0I$54H>v!Y53Ow3cfq5-l3x0);;+`_(SOpo<P5; zWKxC*_5fDeSws#i)r#`ju?E>;z(7Vb2`lY%P?4Rfot2AYj@$qso&%XC=0K?-t$KhH z<%&>tX6w)WlK@uF&vIZP%ZggHP}5OSvKS!iAF0!XfkTiv>wtbP1L!=k_a==4+1wDV z-~RZ()|;SAuKvg3kRs?3@M!sb;}L{4bGipP!1FOjNx1&XCC|KhY=i85FKhgnSsZoL zL=mS!NTm6fev0pRI>rJSh(UO2gv(qXhTAgXSVO)uF4F83)`?~kX+p);EbLcH^4M2} zUo0$#?}A~%!!;hd%51|COkN-lN$q=r6bK04E{LN4udv zL{CpoPp^TVo}PnhFG!q3u08R_w_#siv|exL?OI_80oLvKz{2fBh76y{xtT||I=zgR zqTdPFxOTC!nrJUW%h^^)Yr)Ytun04n#s^Qo^t*VwB3HuAPk4%zoUBh;`{--J`+7Z> z<3lz+vOONZDirHC4Vj-Z_sZG%mxXpcL^q>hC#yP)O)iSSnwZ8pwEyE&!`~!y<}eH{ z1pB?!ae@YX`E!pr-t-Q>51Ui*{|!M7Yr^|D;j1|-{Z`(1f_8hz+dSSIw&4AUTk#XW zi_LjFBY6`ulVXXokv<&Oms^IUKw{~ElY-L~hg$$42|FRn1HL6l)E{6v(IXNg32Uk1 zd~C#VAgG}!vHNHJZSBW;3!4S?q>A-zfZP+T-Ps%al|9iC$UV`~P4iZuw;aLhAl=(U zU}dt_SjpHH`9Z}FvC~*--H|Gms%NhDN2b9|M4FJ6NoS}sF;e?8P>)1p`o2Af>Vq{* z3CVz?Gkdcjgv0@LyTRUpKo}iQU(g*d(XFoPN<4I$zorlM%jh6VyWEq~8Zz)9x z6RahBEJQ!d`*UT%50tLOH>O(%j2tNmT9}sofhb+ywH@6=qX7z5v9F_9$a|&&Fy4zK zMC`#!sl@hse*;jw$?goyFE^GP-8m5Xo19y-3)Ws!Q5~WH<}xiTViuDMFdA!g{aUn} z>SDGzIFV*4mA9YXw){u&bWUkuvxF>C^7@Nthn0Qo+$tpPQXGA9XO-;ik_GJ0AL2qu zVKfKr^sTjB+5;#<$EHHfe9J)H*S_F7Ft)MF=D;BRldi3ba7$=mFx|)u!51OIkszM8 zDMS1t5ZofbA=2{Of@z5mYfsRE7m@dLa|TuiamX?UWxWS7?<#3nJ?lLLg}w+_K{d4-T#cRW5|p zhiR?t;&7J0^PK7DECaq#AZmXFGZ>YKv$78FX!)ZiV~;^9RDcJi$~N82$JH0imJ0cf zJK=19A)jvmWXp#^ec^Bf>P+pK!;XxiDf~4S;f+yFL5l^`Q)hXw6Lp*0qw4Ry_W0 z^+sU}Nz^A`5pH?B9^e|OnooL@YyDatQj;91M>?EP=&4B}JxV{E#WpJu@0V3c^}Lv( zWvHd0Bu(55u$sJPJ$Uet=E*~Wq3I#fHI99wh@e|!iS_;UO?QiJsrUC6bi;mrkmxD? z$@!1NNDE|5(tC*b^=awp;kjpXH)tjc7p1M7rGW`r@ANrw_D_XZHa6pO9O2knGm)pX`sTKCxGYCfv8= z`>JD5lx~?~D(C;c(C9R7 zva(^IrWBT{_5C5Rsq0{1Hf9RKkt~y=kH0WVV2u{Hd-v|6s;AC&yMM5iR{e!d7^Hv= zG)=SFV}!}aOHR-y!Wk^ZMab4hta6p&wqs^Hp=gm)cdO>LSnl|FNZjSQ{6PVmV;0?GBZyg zT>9|o4-erkh@ca83oYJURz#y!L=d4Sa$88I>Wxu-9B2U*buy!{E-C;X6|~_3_Bvnz zYqW5By)&1>fTow%4gWeFB*o-|5y(Q`vd6{(;i zerw18ATH#se7#vBQvk>i#R;lN0jXS`%26qmQYqwx7=^r0RFMi2(#$9Yh^j~diFw_` zn(ZRH09BC+dc`fuQB=tD?ICBnrAetG4@kxAzcR9NQAHk*ke@YY=lLnBA{F$AsaSq1 z>Q-z?D5G;>Aqk_jjzR*>P&UWagmQw$-SB<5m)gwdX9?{Po2h~-s7h6-suW6ZVI2dB z!X-Nn_OA^zZHK<^p7QqwvA;T|s5FbRfq0xTN+N@@8o?l*dmgj3_W1b2Ms7j&C%jLv6D~YS11nJyPWj;a(&QxU5TWZ679 z1o`Gc&<@NON;zer_XM`8qHa}1Y*TSnuF6$~RA?kyKp=G>P!k~T1*q!hxBxwss)3hW zL{O!wR8{7bvl>O^DWz7#hHa-k{62M<5-QXTAY*zMfXae{W3ZyO2NJ$egsG5z*0ayV5{(g+fntySHVR~MB0r#){u z7!~L>*ud@*owcwh>_6o_cetjbUw^I~{p=QV0p%3lO033{r-~^nVVVSysY@@zdEYPP zS4KxC%IipDQBSI;)YIx2JRe|leLgRdKT3NnEsw_yQPbJ`!PB$@PW)=g1yk|q?1f*vT1vD z%DQx6Kvrj$dv-g;`Sxin$H|8|D6R&mV$OdcESA1ZTja9ygQr^0u!F)|^4z0Br?Dp# zZMi|zMZgk%{OmCqFT)d9k&RAwsz8{l;e}iIHU|aMsn)9h`#dfow%}#FQgGEwkZV}2 zz7w$2`sW)fC3vc<_zV7WYUGb${sLU<4e+kR)tKka#{%zB6k?z`)^lm!?I`Gh%7zOs zs}c;(oQy&zjJjTv5vt@5&2kq-mEHC9VCx!+y3j$9B)-vA{CM$+XHy)eunRxlpvwQ7 z(+Tepzau>nHZN{F8Lh_+aCWWc<~AA-0*_$5w}eMk2@`V?cnVMBK%_C#$=(I&`yiVZ zFXV+0LDWkii4@YvczG1OqE|x2tD@#Lyk@kZ6>Vro2Rgle3}6sLn8h6CvFxp26IU~i2%Tvqj+I-zm9!I z_cpKF5{VilgLQEhciw>g^0(+YpAofnU|7C@eA5M&-Q*KgtjkjxRt0(QxEiDSsUizj z213sTvuA_bi#vmnnhfz73Zo28Fn{K-4rkifM=>`A*00000@F{3cj%aFxD(g*$Z577kP&Kf!RMC{xZ%Un} zQhP@7uT@J~qoah;%%Q%~0{Pil%?C|*AUQXumufT(=?Ng^wxSX>LL*UA)l{BJCN)h> z<7xFKocd*!wS;|KD~dMyHIX@ep9xd)ky@MpKS030ZzW+!`Iayj=jPTK9NlazrTi+t zlnUo0oQxZPXP8TVOX^MJiu|>_<0sseED%k{!cFN6H1;`Flm4N25`VR3mOgCY7sl8COrpB@eT5B`tF3Ij3VF zhku=BoLK=d^nLex|3CF1|9<^v>igCHaGx8FDVKf;h|v!gfWj&`019=0!`n>#?CGtg zBLF&9dcfWj_+SCZI2hGey*Qd90AMx%5VH$_xnHsd7TdufpcB4)U-$q2Ytj|FRUNV| ze(wJ)P=LBw#^0g0-+PXI0S^2Q002-3NpJFx=>0IB5$dZz4u9090c}*2>;Zn z;s6FD4#HR10oZmGf*+UQ@Xw4La1|`Uu|I$ofJygYm4F7~7df0$>hUu^0=Tab@O&`# z$&TypZ#BryNeRvA{x2m5Er5V{;V2y!0IJz#2#IJGqLa7TBv_r?1#2M`tPg~wEvgx0 z{X|H5A_SHPZe~UJC}uwhNu1Kw27vdWkOb_W1wgI1qKFNlTw*R_eX!cSSXPZ9HcQHl zYQ!S8l$0C0NL~(RiD}W+sI`6`l{KzD5U{8j8;vy@y-jZ2J`z#DCY*qDByLQr)Jriw z3O|WBBnG>;N20}M^?icP7+MxE@oeK3fEh^yU`7y!*r0BOa!R+i)m+(Yf>6Z`zNuu+0$6Qu2r%*#gZbt`U$ROziDoYV{Cvv}ah+(gIqmsM3(Jphwss^aS8G%7#m}+1-yJ!7YCDK9y%FN2aTH;+nP9S2dBs$YQ z!m1>VZW)?Gzo^31w#^VsOxCL$X;C01>}?U+;tHs=ks}LNt42cSzKJFgt9%ODlHDO) zEE;_TJQUzRxR+D^*>gM_8$D}g8uk>e(r-0zoJDlVW_i1gBb})8S6JL3PRQ(`!dw|+}>H@K$5KY?gyyZ-FkK%E{j0Hc%6k! z0Hp0IfdnTSH1fn=dgDZ{IP7aL-$~ke>N$D}$bYv4PHS3yY|Sx!^wa4C)*<#q!V1&h z`y;9_i9fN5Q&!V+1_1hXC)cGiM@5OB)+-F5h+{Al@j}ZI&w}ypH7Ra*XYV~#zt3T8 z!(l88Ff06lftF%L2xhJZ*l?E9D;1u$%csGyN#BrDzwBQ_0!4{4fr3d~lW@bsQOF+C zpt4??85V5uSBFnwCkpd`M|gsjZhBVan6rcaWl>|-T#j49@kJ1XpHp`p!2Qm)<{->W zT#H~ZPym$;7I3s1b=(pW!oBN21RDSc2I-LuB8r9<_GKQc0r+;Xv6rQEjb;ZQd$Q1W zI@=1nqjk8`pb)0wSZ#n6R(o|5-Wsnk?M~!t?7G*}Rz*#zKbsURIiO4uu6>+{V8h@} zlkOW!^De16ig(8(d8oJf7tTe-9e|rl^6=~M4y>$qho+LT70zza9Ap6s%cc|4SFTOL zW`~?uou2+kX6|6%qc4CHQnMByl&wK*EigN)CgAALhLi+Pk`7S%o^qH5#R1?bZQ>K(033zQ zkTF(uqAt?}*e-6M!)6cD2fA48fj|@H2hKBY1_4!DV|+u)Fqu@eb~cKVbwI+64_49 zN9^oNmBLF(^#^Qv!rHdU)5d|H6e8Yid#mghmw3%TVrf?c9@>6Vlt`TiQNK);%EATD zqFv*ke|Ud~2!Dq!av}+=Wb^RdT{<1IyjZTmCc5)EJgWnM%7C8Y8YEzr?dmN_BTLse z4ACGYc&cgaGV{{L&`t&~&sT2HZ^6SWjfUCY>N!>a+!|lr41@%$LfL>5m)3+~e0-u` z(X3CY@Rp-bl0KgzLR=$ZLu+&6jIFhI4NW*2`VmdALAUPGWqra%r@u|=#>uH@fSNKp z`sRe?x<=$Jc?(B1foYd$@B=)$QQN<)7RzB+zY_g#L|sbXgf&6v>-y{OJ%-JhCkaf@ zB1b-F=B#nG9*WDJbUVej$qkSYz&A_^cw4$lNP56(1bI$EucCJlBea7!|Em@&A`ES3 zFt~L-Cp*QxH{!sQj9A5sOk%+gdS%}lNUR_GdIJz`kMkYvrNc~qFWdDu8T0;DfYDh^tYVKy?7d5f++eH` zjiO z?@&VV{6N`}!~{~z>i^*%ut{Ixa=sJ@!AOw$(xU-9R)=9N0sxx1NpVru0%?c0RK=+z zI9fr0svOY!_b5<7u#!>Y6mhQ-q$;WvKZm43hhx7cbx^R2!bOMrgt!vrdf|ng#OekO znBT3oE{n(vRfjMOVkpivSsYKeXzT10sv#)TwayF;hxe~hh4lv~n>dS;s;d~RQ}7dp zL&d(I4~=BXjO}Hgkd_y{Ij%u}s=Dr<8*T(+7o~2NDkKZ{N96{e%fW1iJ0xG*I{01w z%N8BNM8z;7ztjR@(9>BXR0G|q)(zwwBC^?v1pG3|G7InOYAKcqBn$VUVt=>{vYi!A zZ9RQ(ev4V)kblXBW1GZ4+SXh8QHUczCIxtky=RLcW0RP74eZd;JBPvRwoWO=0By@W z)b(KNMF916s09MKpL9A&Qjo+Y0o4tdY{$%2bWj0N@sh#jkz)Tc!6CV{)Q54=g@|}& zxfey53*Pu zl+SUQmvZ!w_~W+ODD)M4czgT){rihq^XkxCP&y`6~o*}dYiH^*t#vK`!3k5G>q7vh|*4KwzT|aFE%; z4JpB(mhYLwz;H{i7CMbH5;-7}0JQ`~3-#%S!I z>Q@BzQF4jV`5fPDS3ZNZJ=`uT2ycz8Z@_D~s>`;`C`odTtMm)V&C}veH^xVUQ@153 zLK%@?hlbN{XAp&m#ZlDe^YKym&6W*P^?HE2VU%kDf)%T$?4 zWr3Ad`Jws{2Sa)&AANC^yabTi!Sty5IV#}-K8=k+(K6^GwFKh|KmEojci**+xZ0Ik zwX^T;Yp3ap;;UE%Ea{aw0?kIYBv>PnL2{1=9|Lld=-5r?t5!};wW_n}%>=$B+ob^_ z1xzqAZ8Gjz$gWE$a8sl~(7j`hd*GHH(8>GF8M$*Iu*A`NX)GE0Fr>4^Kv zG0`3YwgI~6Gj7RY-$sd&muxO$Di3pmmzI-bw)9SmuQPg;Y~9ngbxOs*MkYWC6Rhz46~Tf z3?nS_Y7*t>ZiXM^Eg+hyswrYyV}e>0Vaqk)<&b(m#nFekxq>I{fh4VDyTM0v$Nh7s zp4la_BKS(hstMsf3kWoqnx+BLXlKIES*s2^R^2}b1D}Es5f*N9MBq2b7!p>Sp+V(N zO%4IhZQG{!0{Id=z@TEK+gyKgxlDP);M^HdDjz4!1Sg9k12N)$VpF!^7*~Y|hI0lL z)GaDAM8`o0cWznV<-$kD9OD%$q)-und(9za_|F4PN@d0IkD*~+)l@?g$57!wM?)a+XbiFqt-t#;G&FkS{As(M-VPqCYXGW@F(?X5WhOE zAc_seJ|JUNPibIBJex0C+TVXuy$Op#guZR+8x>RoPCcMwF)Rqx*q&h;y(?v)nALr| z<`joG{vgvy1#V9&f=O!&IS{+@EI_U*Elsz>vbjlkkM5wAB@y#sRI|S+PuNwVYp&zD zc~wxnf0F*3S_3AVCwBS0))wqa)~~ zI0Rry1J2+Bt)M%gqO4%ZOofd?xl@l|xFBZ~<2eu~3m+T@?L6~L*U97`52z z*$aBt=xq4R*=_2R100!wKC_}>UDjh}=On^%us#KIX&wbr-~m7r z&8a}!I+wnkHz7%_gR{0&T*1aOq!Yt(<-kluo9QD7SUy0&#J5WLogMwycW5!Qp(~=3 zX+F84hb~QImqIC~FYf8dw7v6u?OS-CP{#)*NF=b8I6`C|>3hG@fAQXzJ~6VpQUV?K zf^`>-H}%Aapd@B}!C{DOh*@|>E3(yixv@agcyb>QzN$wC>ntCkukQMLl1*(ks@W%N zmecDADr!eWq~beCYoSZ!&R?Fx!vAmhR7x-NytN}7D)R{jgm^%Lc!RorZZWDCYjM%H zu1(E&U8hk4sreS4k2N9VQ_TqSfKRASakYdge&6ruufs;&np9;rZt4gr*e&(zH91_e z7)eL3;Jy&+Tkto2G5sU~gnsXFZW5bea7OryO}=Untr`oQqt_WxQBC{(-QLYc9d{ zE!EO9lpwG@%cDG;Ey3q2{(#IqP(5wAY%kbqdzY6$9Ugn@%n4N(maOXC5xHC(#m2>S zWPH6kY|oqQVfN!l+bcM!+GQu>hPD5?_CZ*bc^tZwUZ(Q^z5%Q$lpY6oA(^`E4=tp% zalfo9QW=8qmWtC32>9mpkTlq6d58c~qYUlObFoviz*lhb*fI}y>bGy-W;Gh>hr0CV zVAePE(v?ytbiE3lX9cpX)V8q7QtjbVdyL0^AM|ynL@NlyFDF1^AbXc9JExSDKeA(S zyf_9chZG@BLU7qPT91^W#y4?U{hE?0ofwJHX-qb2X6UI78k+3$>0+Qd9VL%nF~YoA zpLmTQpz~9-c{+oG-OV8UGV{VcbO&J-y%^Cv#n4Fr2rLy7pm)zQf-g~1&4R#Uc$978 zjgW1Fho?)rcZgrBV>!`btK-b88*}>|AS%P-oj5P*X)9Hz3$UN#QkwwJy&FHxoMGQITc zxIyte-Y{7NBdBkS-fBr2*JUtfH|=yL^#+O>S-W_({6T=p5(l(<-Jq-Q5Y?}NZjtdQ zaOiQVy;~@Kny#v*_Y#W~-@w#!xYNxhDqc2n$ToyA8MW|fc1$>}qWn>_t>jBA{b<-^ z`jYji*Oyp^quqe^;pqBcs$lli-d~=d=G*mhp2ogw>Z(i|TNY%ApYl_iDL1`BDwx?#=8AMh4=B%50R%GtU!oz&KRYZR_81pu{4%LmL6%L9TMr~?&Vk7)fJ1h6}Rwi zXtDZV`1M=Kn&M*5R~#&oF~FChPLxXaT~lakO637mp=B%+xLLXLwR#ptq)V8wE6WDt z*w7eWI%BJSD2`_B7{poN^UJiar#-ApGHvuJ%PTU;E5>xA6Ia2((_dRZ=0AJ&y|iTb`1TSuMD*)(!_z$xpnfm{l6~L4*#FKh)2ph3lrl+*~vWqr@*mqEQ5m zftt-`jv(WLqYIQLFhCgTNMs4=A#;O$%vLt(RC%&lPUE@5eyQHpLynU+!v}1?Irg&r z{fiyVSR4h~dLvCa{7Sg>Q*(WRRsE|a7V#ZG)g~Xn<382}&?PbKzO7dkXhE%B(z-m& z(@>Wp4FiinjYkE0Tn!}e$8o`0J`Yx{70={A6`uIG6qU9KoxWXF>JD936##x0w03Sr zij}c(c!mhxDQl~jG+rwdT0BNxFi_GDid|U9{m*^&gRWujep<}`PsJ0Vpv z$Sc)=;M7AYKvgJXP6;Y_YsmkT$jgGYGOLvIL<_?vu%{&m#stXxBID}isroYY2KCz- zZcAL#Vj;A+5xAXjWRc-{K(8rB=MoAJE??0;f?|fxf3!qXH`$a;!*SivYjX24s?{Ll z@`#85pQqVxejwWVDxLKx2>_r8_&N^gz1$~JJCXFYG<(wZa;0>cSJanrW^r`F4R-j- z8Vk;T1a3A5$5c(-X-tU7`+07YIAebN_f(g14>X*yOsmi>Pgz6sd+pV9u8=0&44|93 z#K?=vORhGlk3G8IZ;|q1PT>ph%hI zgp#+YPS^86;)M^sV2|$XbP%Q=-@m5F>6}5qz&>f`b=588ukRKOsrDWKwYQv=^3plc zs!7~irH3>*?7^~l5#ZACdTDE(`mVlf_Z9c&dp9o&gb$WqB6SLy5RyEc~G0p&-oIal#+;N_vHV# z%V;6t7^)K7USH-2exLBy5Yr@7s`P0y#24u(H7*BFs2)4tQ6d>7jXDUl2H}Feejbdb z4fqW*#4~RY$Yvx(P=FYz9oQHgH2lH+=6e|CqR{X|w$Gq955e6hCeZn*s@iw2%qi`G zYh{x_i-oZzqInfR&~`*vJoBP5qi?l�?eochER7tD1=jS~pW*2NBN72s;@ox9=2^ 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 [data-streamdown="paragraph"] { @apply my-0; } [data-streamdown="horizontal-rule"] { - @apply my-4 border-primary-border; + @apply my-4 border-ink-primary/8; } [data-streamdown="strong"] { - @apply font-medium text-ink-primary; + @apply font-semibold text-ink-primary; } [data-streamdown="table-wrapper"] { - @apply my-3 overflow-x-auto; + @apply my-3 overflow-x-auto rounded-lg shadow-card; } [data-streamdown="table"] { @apply w-full text-sm; } [data-streamdown="table-header"] { - @apply border-b border-primary-border bg-primary-bg; + @apply border-ink-primary/8 border-b bg-base-bg; } [data-streamdown="table-header-cell"] { - @apply px-3 py-1.5 text-left font-medium text-ink-primary; + @apply px-3 py-2 text-left font-medium text-ink-secondary text-xs; } [data-streamdown="table-row"] { - @apply border-b border-primary-border; + @apply border-ink-primary/6 border-b last:border-0; } [data-streamdown="table-cell"] { - @apply px-3 py-1.5 text-ink-primary; + @apply px-3 py-2 text-ink-body; } [data-streamdown="image"] { @apply max-w-full rounded-md; } -/* ─── Shiki dual-theme code blocks ─── - CodeBlock highlights with { light: github-light, dark: github-dark } and - defaultColor:false, so shiki emits per-token CSS variables instead of a fixed - color. Activate light by default and swap to dark under the .dark class. Only - the text color switches — the

     keeps its own bg-secondary surface. */
    +/* Scroll masks fade the edges a scroller can still scroll past. Scroll-driven
    +   animations size each fade, so an axis that can't scroll (or a browser without
    +   scroll timelines) gets none. */
    +@property --scroll-mask-top {
    +  syntax: "";
    +  inherits: false;
    +  initial-value: 0px;
    +}
    +@property --scroll-mask-bottom {
    +  syntax: "";
    +  inherits: false;
    +  initial-value: 0px;
    +}
    +@property --scroll-mask-left {
    +  syntax: "";
    +  inherits: false;
    +  initial-value: 0px;
    +}
    +@property --scroll-mask-right {
    +  syntax: "";
    +  inherits: false;
    +  initial-value: 0px;
    +}
    +
    +@keyframes scroll-mask-top {
    +  to {
    +    --scroll-mask-top: 32px;
    +  }
    +}
    +@keyframes scroll-mask-bottom {
    +  from {
    +    --scroll-mask-bottom: 32px;
    +  }
    +}
    +@keyframes scroll-mask-left {
    +  to {
    +    --scroll-mask-left: 32px;
    +  }
    +}
    +@keyframes scroll-mask-right {
    +  from {
    +    --scroll-mask-right: 32px;
    +  }
    +}
    +
    +@utility scroll-mask-y {
    +  mask-image: linear-gradient(
    +    to bottom,
    +    transparent,
    +    #000 var(--scroll-mask-top),
    +    #000 calc(100% - var(--scroll-mask-bottom)),
    +    transparent
    +  );
    +  animation:
    +    scroll-mask-top linear both,
    +    scroll-mask-bottom linear both;
    +  animation-timeline: scroll(self y), scroll(self y);
    +  animation-range:
    +    0 32px,
    +    calc(100% - 32px) 100%;
    +}
    +
    +@utility scroll-mask {
    +  mask-image:
    +    linear-gradient(
    +      to bottom,
    +      transparent,
    +      #000 var(--scroll-mask-top),
    +      #000 calc(100% - var(--scroll-mask-bottom)),
    +      transparent
    +    ),
    +    linear-gradient(
    +      to right,
    +      transparent,
    +      #000 var(--scroll-mask-left),
    +      #000 calc(100% - var(--scroll-mask-right)),
    +      transparent
    +    );
    +  mask-composite: intersect;
    +  animation:
    +    scroll-mask-top linear both,
    +    scroll-mask-bottom linear both,
    +    scroll-mask-left linear both,
    +    scroll-mask-right linear both;
    +  animation-timeline: scroll(self y), scroll(self y), scroll(self x), scroll(self x);
    +  animation-range:
    +    0 32px,
    +    calc(100% - 32px) 100%,
    +    0 32px,
    +    calc(100% - 32px) 100%;
    +}
    +
    +/* Docs code blocks: a line-number gutter on multi-line blocks. */
    +[data-code-block] pre[data-line-numbers] code {
    +  counter-reset: line;
    +}
    +
    +[data-code-block] pre[data-line-numbers] .line::before {
    +  counter-increment: line;
    +  content: counter(line);
    +  display: inline-block;
    +  width: 3rem;
    +  padding-right: 1.25rem;
    +  text-align: right;
    +  color: #71717a;
    +  user-select: none;
    +}
    +
    +/* ─── Shiki dual-theme fallback ───
    +   Highlighting that runs with { light, dark } themes and defaultColor:false
    +   emits per-token CSS variables; activate light by default and swap under
    +   .dark. Docs code blocks use one dark theme with inline colors instead. */
     .shiki,
     .shiki span {
       color: var(--shiki-light);
    diff --git a/app/layout.tsx b/app/layout.tsx
    index 17e2d0a..9219b65 100644
    --- a/app/layout.tsx
    +++ b/app/layout.tsx
    @@ -1,5 +1,6 @@
     import type { Metadata } from "next";
    -import { IBM_Plex_Mono, Inter } from "next/font/google";
    +import { Inter } from "next/font/google";
    +import localFont from "next/font/local";
     import { Providers } from "@/components/providers";
     import "streamdown/styles.css";
     import "./globals.css";
    @@ -10,12 +11,15 @@ const inter = Inter({
       display: "swap",
     });
     
    -// IBM Plex Mono isn't a variable font — enumerate the weights actually used (regular,
    -// medium, semibold) so next/font subsets only those.
    -const ibmPlexMono = IBM_Plex_Mono({
    -  variable: "--font-ibm-plex-mono",
    -  weight: ["400", "500", "600"],
    -  subsets: ["latin"],
    +// Ioskeley Mono (OFL-1.1, github.com/ahatem/IoskeleyMono). Only the ligature
    +// build ships web fonts, so globals.css turns ligatures off for mono text.
    +const ioskeleyMono = localFont({
    +  variable: "--font-ioskeley-mono",
    +  src: [
    +    { path: "./fonts/IoskeleyMono-Regular.woff2", weight: "400", style: "normal" },
    +    { path: "./fonts/IoskeleyMono-Medium.woff2", weight: "500", style: "normal" },
    +    { path: "./fonts/IoskeleyMono-SemiBold.woff2", weight: "600", style: "normal" },
    +  ],
       display: "swap",
     });
     
    @@ -36,7 +40,7 @@ export default function RootLayout({
       return (
         
           
             {children}
    diff --git a/components/ai/ask-user.tsx b/components/ai/ask-user.tsx
    index df42d8f..2bfb3d1 100644
    --- a/components/ai/ask-user.tsx
    +++ b/components/ai/ask-user.tsx
    @@ -7,12 +7,12 @@ import {
       useAskUserOptions,
     } from "@intentface/chat/ask-user";
     import {
    -  IconCheck,
    -  IconChevronDown,
    -  IconChevronLeft,
    -  IconChevronRight,
    -  IconHelpCircle,
    -} from "@tabler/icons-react";
    +  Check,
    +  ChevronDown,
    +  ChevronLeft,
    +  ChevronRight,
    +  CircleQuestion,
    +} from "@keyline-icons/react";
     import { type ComponentProps, type RefObject, useState } from "react";
     import { Collapsible } from "@/components/ui/collapsible";
     import type { AskUserQuestion } from "@/lib/ai/types";
    @@ -55,14 +55,14 @@ const AskUserNavigation = ({ className, ...props }: AskUserNavigationProps) => (
     );
     
     const navigationButtonClasses =
    -  "flex size-6 cursor-pointer items-center justify-center rounded-md text-ink-secondary transition-colors hover:bg-tertiary-bg-hover hover:text-ink-primary disabled:pointer-events-none disabled:opacity-30";
    +  "flex size-6 cursor-pointer items-center justify-center rounded-full text-ink-secondary transition-colors hover:bg-ink-primary/5 hover:text-ink-primary focus-visible:outline-2 focus-visible:outline-accent-bg/60 disabled:pointer-events-none disabled:opacity-30";
     
     /** Navigate to the previous step. */
     type AskUserPreviousProps = ComponentProps;
     
     const AskUserPrevious = ({ className, ...props }: AskUserPreviousProps) => (
       
    -    
    +    
       
     );
     
    @@ -71,7 +71,7 @@ type AskUserNextProps = ComponentProps;
     
     const AskUserNext = ({ className, ...props }: AskUserNextProps) => (
       
    -    
    +    
       
     );
     
    @@ -106,10 +106,10 @@ const AskUserOption = ({ className, ...props }: AskUserOptionProps) => (
        {
     };
     
     const INDICATOR_CLASS = cn(
    -  "flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-tertiary-border bg-tertiary-bg text-2xs font-medium tabular-nums text-ink-secondary",
    +  "flex size-4 shrink-0 items-center justify-center rounded-[5px] bg-raised font-medium text-[10px] text-ink-secondary tabular-nums shadow-raised",
     );
     
    -const INDICATOR_SELECTED_CLASS =
    -  "border-tertiary-border-active bg-tertiary-bg-active text-ink-primary";
    +const INDICATOR_SELECTED_CLASS = "bg-accent-raised text-white shadow-accent";
     
     const AskUserOptionCheckIndicator = () => {
       const option = useAskUserOption();
    @@ -140,7 +139,7 @@ const AskUserOptionCheckIndicator = () => {
           aria-hidden="true"
           className={cn(INDICATOR_CLASS, option.selected && INDICATOR_SELECTED_CLASS)}
         >
    -      {option.selected && }
    +      {option.selected && }
         
       );
     };
    @@ -205,10 +204,10 @@ const AskUserSummary = ({ questions, answers, className, ...props }: AskUserSumm
           {...props}
         >
           
    -        
    +        
               Answered {count} {count === 1 ? "question" : "questions"}
             
    -         (
               
    - +
    {q.question} diff --git a/components/ai/attachments.tsx b/components/ai/attachments.tsx index 1c54d1f..0baf92b 100644 --- a/components/ai/attachments.tsx +++ b/components/ai/attachments.tsx @@ -1,7 +1,7 @@ "use client"; import type { AttachmentErrorCode, AttachmentItem } from "@intentface/chat/attachments"; -import { IconFile, IconPaperclip, IconX } from "@tabler/icons-react"; +import { File, Paperclip, X } from "@keyline-icons/react"; import { AnimatePresence, motion } from "motion/react"; import Image from "next/image"; import type { ComponentProps, ReactNode } from "react"; @@ -64,8 +64,8 @@ type AttachmentsItemProps = { }; const getFileIcon = (mediaType: string) => { - if (isPdfAttachment(mediaType)) return IconFile; - return IconPaperclip; + if (isPdfAttachment(mediaType)) return File; + return Paperclip; }; const AttachmentsItem = ({ item, children, className }: AttachmentsItemProps) => { @@ -87,7 +87,8 @@ const AttachmentsItem = ({ item, children, className }: AttachmentsItemProps) => isImageAttachment(mediaType) ? "image" : isPdfAttachment(mediaType) ? "pdf" : "file" } className={cn( - "group relative flex h-12 max-w-48 items-center gap-2 rounded-lg border border-secondary-border bg-secondary-bg px-2", + // Attachment chips are rounded squares, raised like the composer's buttons. + "group relative flex h-7 max-w-56 items-center gap-1.5 rounded-[7px] bg-raised pr-2 pl-1.5 shadow-raised", className, )} > @@ -96,21 +97,21 @@ const AttachmentsItem = ({ item, children, className }: AttachmentsItemProps) => width={32} height={32} alt={filename} - className="size-8 shrink-0 rounded-xs object-cover ring-1 ring-inset ring-slate-7/10" + className="size-[18px] shrink-0 rounded-[4px] object-cover ring-1 ring-ink-primary/10 ring-inset" src={item.url} /> ) : ( -
    - -
    + )} -
    - +
    + {filename.slice(0, -7)} {filename.slice(-7)} {item.fileSize != null && ( - {formatFileSize(item.fileSize)} + + {formatFileSize(item.fileSize)} + )}
    {children} @@ -135,7 +136,7 @@ const AttachmentsRemove = ({ onRemove, filename, className }: AttachmentsRemoveP size="2xs" type="button" > - + ); @@ -148,9 +149,9 @@ type AttachmentsDropzoneProps = { const dropzoneVariants = { inline: - "absolute inset-0 m-1 flex items-center justify-center rounded-xl border border-dashed border-secondary-border bg-secondary-bg", + "absolute inset-0 m-1 flex items-center justify-center rounded-lg border border-accent-bg/50 border-dashed bg-composer-bg text-accent-bg", global: - "absolute inset-0 z-50 flex items-center justify-center rounded-[inherit] border-2 border-dashed border-secondary-border bg-secondary-bg/80 backdrop-blur-xs", + "absolute inset-0 z-50 flex items-center justify-center rounded-[inherit] border-2 border-accent-bg/50 border-dashed bg-secondary-bg/80 text-accent-bg backdrop-blur-xs", }; const GLOBAL_DROPZONE_SELECTOR = '[data-slot="sidebar-inset"]'; @@ -221,7 +222,7 @@ type AttachmentsTriggerProps = ComponentProps; const AttachmentsTrigger = ({ children, className, ...props }: AttachmentsTriggerProps) => { return ( - {children ?? } + {children ?? } ); }; diff --git a/components/ai/chip.tsx b/components/ai/chip.tsx index 86333e9..d2cf53e 100644 --- a/components/ai/chip.tsx +++ b/components/ai/chip.tsx @@ -12,7 +12,7 @@ import { cn } from "@/lib/utils"; // doesn't grow the line box; `box-decoration-clone` keeps padding/bg intact if a // chip wraps; `leading-[inherit]` so it never inflates the editor's line height. export const CHIP_SURFACE_CLASS = - "box-decoration-clone inline rounded-sm border border-primary-border bg-primary-bg px-0.75 py-0.5 align-baseline font-book leading-[inherit] whitespace-nowrap text-ink-primary"; + "box-decoration-clone inline rounded bg-ink-primary/6 px-1.5 py-0.5 align-baseline font-book leading-[inherit] whitespace-nowrap text-ink-primary"; const chipVariants = cva(CHIP_SURFACE_CLASS, { variants: { diff --git a/components/ai/composer.tsx b/components/ai/composer.tsx index fca0f82..4264a8a 100644 --- a/components/ai/composer.tsx +++ b/components/ai/composer.tsx @@ -68,7 +68,16 @@ export type { export type ComposerRootProps = ComponentProps; const ComposerRoot = ({ className, ...props }: ComposerRootProps) => ( - + [data-composer-context-window][data-open]]:bg-ink-primary/[0.04] has-[>[data-composer-context-window][data-open]]:p-1 dark:has-[>[data-composer-context-window][data-open]]:bg-white/[0.02]", + className, + )} + {...props} + /> ); // --------------------------------------------------------------------------- @@ -80,10 +89,8 @@ type ComposerContainerProps = ComponentProps const ComposerContainer = ({ className, ...props }: ComposerContainerProps) => ( { const icon = chip.icon && isChipIconKey(chip.icon) ? CHIP_ICONS[chip.icon] : undefined; return ( - // The composer input uses the plain borderless chip surface; the - // bordered/filled CHIP_SURFACE_CLASS is reserved for message/docs chips. - + // One chip surface everywhere, so the badge commits without a jump. + {icon && {icon}} {chip.label} ); }} className={cn( - "max-h-32 min-h-8 overflow-y-auto py-2 px-3 text-md", + "max-h-32 min-h-12 overflow-y-auto px-2.5 pt-2.5 pb-1 text-md", "mask-[linear-gradient(to_bottom,transparent,black_16px,black_calc(100%-16px),transparent)]", // The editor element — engine-owned DOM, out of JSX reach. - "**:data-composer-editor:w-full **:data-composer-editor:max-w-none **:data-composer-editor:font-book **:data-composer-editor:leading-[1.7] [&_[data-composer-editor]:focus]:outline-none", - // Active-prefix badge: the composer's own borderless surface (matching the - // committed chip above, not the bordered CHIP_SURFACE_CLASS used in - // messages/docs) so the badge and the chip it becomes share one baseline — - // no jump on commit. - "**:data-command-badge:box-decoration-clone **:data-command-badge:inline **:data-command-badge:rounded-sm **:data-command-badge:px-0.75 **:data-command-badge:py-0.5 **:data-command-badge:align-baseline **:data-command-badge:font-book **:data-command-badge:leading-[inherit] **:data-command-badge:whitespace-nowrap **:data-command-badge:bg-primary-bg-hover **:data-command-badge:text-ink-primary", + "**:data-composer-editor:w-full **:data-composer-editor:max-w-none **:data-composer-editor:font-book **:data-composer-editor:leading-6 [&_[data-composer-editor]:focus]:outline-none", + // Active-prefix badge: the same surface as the committed chip above, so + // the badge and the chip it becomes share one baseline — no jump on commit. + "**:data-command-badge:box-decoration-clone **:data-command-badge:inline **:data-command-badge:rounded **:data-command-badge:px-1.5 **:data-command-badge:py-0.5 **:data-command-badge:align-baseline **:data-command-badge:font-book **:data-command-badge:leading-[inherit] **:data-command-badge:whitespace-nowrap **:data-command-badge:bg-ink-primary/6 **:data-command-badge:text-ink-primary", // The badge's hint element — ghost-text completion or the empty-query // placeholder (the package renders whichever applies into one slot). "**:data-command-hint:pointer-events-none **:data-command-hint:whitespace-nowrap **:data-command-hint:text-ink-tertiary", @@ -243,9 +247,7 @@ const ComposerPlaceholder = ({ placeholder, children, className }: ComposerPlace const { currentItem, key } = useLoop(loopItems); if (!isLooping && items.length === 1) { - return ( -
    {items[0]}
    - ); + return
    {items[0]}
    ; } if (!isLooping && items.length === 0) return null; @@ -259,7 +261,7 @@ const ComposerPlaceholder = ({ placeholder, children, className }: ComposerPlace animate={{ opacity: 1, y: 0, filter: "blur(0px)" }} exit={{ opacity: 0, y: "-100%", filter: "blur(4px)" }} transition={{ duration: 0.3, ease: "easeOut" }} - className={cn("text-ink-tertiary font-book leading-[1.7]", className)} + className={cn("text-ink-tertiary font-book leading-6", className)} > {typeof items[0] === "string" ? currentItem : items[key % items.length]} @@ -277,11 +279,9 @@ type ComposerContextWindowProps = ComponentProps ( ) => ( - + ); type ComposerSubmitProps = ComponentProps & { @@ -318,6 +321,7 @@ const ComposerSubmit = ({ ( // coordinates); portaled to the body, so it never reserves layout in the composer. // Match the composer Container's width via the positioner's --anchor-width var. "absolute z-50 w-(--anchor-width) overflow-hidden", - "rounded-4xl border border-primary-border bg-primary-bg [corner-shape:squircle]", + "rounded-xl bg-primary-bg shadow-composer", "transition-[opacity,transform] duration-150 ease-out", "data-starting-style:opacity-0 data-ending-style:opacity-0", // Slide from the anchored edge: default (above) drops in from below; flipped @@ -395,7 +399,7 @@ const ComposerPopover = ({ className, ...props }: ComposerPopoverProps) => { // off the anchor token with a stronger shadow. `absolute` is the base positioning // context (the positioner then writes left/top in page coordinates); z-50 keeps // the portaled popover above the thread. - "absolute z-50 w-72 overflow-hidden border border-primary-border bg-primary-bg rounded-4xl shadow-lg [corner-shape:squircle]", + "absolute z-50 w-72 overflow-hidden rounded-xl bg-primary-bg shadow-composer", "transition-[opacity,transform,filter] duration-150 ease-out", "data-closed:opacity-0 data-closed:blur-[3px]", // Slide from the anchored edge — opens upward by default, downward when flipped. @@ -470,7 +474,7 @@ const ComposerCommandEmpty = ({ "hidden group-data-empty/composer-command-list:flex", // Shown only when nothing matches, where it acts as the single highlighted // option whose selection dismisses — so it carries the highlight styling. - "items-center gap-2 rounded-lg bg-primary-bg-hover px-3 h-8 text-sm text-ink-primary", + "items-center gap-2 rounded-lg bg-ink-primary/5 px-3 h-8 text-sm text-ink-primary", className, )} {...props} @@ -497,9 +501,9 @@ type ComposerCommandItemProps = ComponentProps ( ) => ( ); diff --git a/components/ai/message.tsx b/components/ai/message.tsx index f10bf51..ee06b3a 100644 --- a/components/ai/message.tsx +++ b/components/ai/message.tsx @@ -77,16 +77,15 @@ const MessageContent = ({ className, ...props }: ComponentProps<"div">) => (
    ( } > {children} @@ -183,7 +182,7 @@ const MessageText = ({ children, className }: MessageTextProps) => ( const MessageError = ({ children, className, ...props }: ComponentProps<"div">) => (
    ) => ( className={cn("flex w-full justify-center", className)} {...props} > - + Stopped @@ -225,7 +224,7 @@ const MessageStopped = ({ className, ...props }: ComponentProps<"div">) => ( const MessageLoading = ({ className, ...props }: ComponentProps<"div">) => (
    Loading... @@ -283,7 +282,7 @@ const MessageAttachment = ({ attachment, className, ...props }: MessageAttachmen return (
    @@ -310,12 +309,12 @@ const MessageAttachment = ({ attachment, className, ...props }: MessageAttachmen ) : ( -
    - +
    +
    )}
    - + {filename.slice(0, -7)} {filename.slice(-7)} @@ -383,7 +382,7 @@ const MessageSelection = ({ onAdd, className }: MessageSelectionProps) => { initialFocus={false} finalFocus={false} className={cn( - "flex items-center gap-1 rounded-full border border-primary-border bg-primary-bg p-0.5 shadow-md outline-none", + "flex items-center gap-1 rounded-full bg-primary-bg p-0.5 shadow-overlay outline-none", "data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95", "data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", "duration-100", @@ -396,7 +395,7 @@ const MessageSelection = ({ onAdd, className }: MessageSelectionProps) => { type="button" variant="ghost" size="sm" - className="gap-1.5 rounded-full" + className="gap-1.5" onClick={() => { if (selection) onAdd(selection.text); window.getSelection()?.removeAllRanges(); @@ -432,18 +431,20 @@ const MessageSource = ({ target="_blank" rel="noopener noreferrer" className={cn( - "inline-flex items-center gap-1.5 rounded-md border border-primary-border bg-primary-bg px-2 py-1 text-xs text-ink-secondary transition-colors hover:bg-primary-bg-hover", + "inline-flex h-6 items-center gap-1.5 rounded-full bg-raised pr-2 pl-1 font-medium text-ink-body text-xs shadow-raised transition-colors hover:bg-raised-hover focus-visible:outline-2 focus-visible:outline-accent-bg/60 focus-visible:outline-offset-2", className, )} {...props} > - + + + {domain} ); diff --git a/components/ai/reasoning.tsx b/components/ai/reasoning.tsx index 06c6425..4b0f896 100644 --- a/components/ai/reasoning.tsx +++ b/components/ai/reasoning.tsx @@ -1,7 +1,7 @@ "use client"; import { Reasoning as ReasoningPrimitive, useReasoning } from "@intentface/chat/reasoning"; -import { IconBrain, IconChevronDown } from "@tabler/icons-react"; +import { Brain, ChevronDown } from "@keyline-icons/react"; import { AnimatePresence, motion } from "motion/react"; import { type ComponentProps, memo, type ReactNode } from "react"; import { Markdown } from "@/components/ui/markdown"; @@ -67,15 +67,15 @@ const ReasoningTrigger = memo( return ( {children ?? ( <> -
    - +
    + {component}
    - )} diff --git a/components/ai/steps.tsx b/components/ai/steps.tsx index 4064f3b..923280e 100644 --- a/components/ai/steps.tsx +++ b/components/ai/steps.tsx @@ -59,7 +59,7 @@ const StepsPanel = ({ className, children, ...props }: StepsPanelProps) => ( // The rail: a nested item's panel indents behind a vertical line, so // depth reads visually without any depth counter. `[data-nested]` is set // by the primitive on items that sit inside another item. - "in-data-nested:ml-2 in-data-nested:border-l in-data-nested:border-slate-6 in-data-nested:pl-4", + "in-data-nested:ml-2 in-data-nested:border-ink-primary/10 in-data-nested:border-l in-data-nested:pl-4", className, )} {...props} @@ -82,7 +82,7 @@ const StepsIcon = ({ className, ...props }: StepsIconProps) => ( "flex size-4 shrink-0 items-center justify-center", "data-[status=complete]:text-ink-secondary", "data-[status=active]:text-ink-primary", - "data-[status=pending]:text-slate-9", + "data-[status=pending]:text-ink-tertiary", className, )} {...props} @@ -99,7 +99,7 @@ const StepsLabel = ({ className, ...props }: StepsLabelProps) => ( "text-sm text-left", "data-[status=complete]:text-ink-secondary", "data-[status=active]:font-medium data-[status=active]:text-ink-primary", - "data-[status=pending]:text-slate-9", + "data-[status=pending]:text-ink-tertiary", className, )} {...props} diff --git a/components/ai/thread.tsx b/components/ai/thread.tsx index fe92a5d..cfc4a3f 100644 --- a/components/ai/thread.tsx +++ b/components/ai/thread.tsx @@ -73,7 +73,7 @@ ThreadOverlay.displayName = "ThreadOverlay"; export type ThreadViewportProps = ComponentProps<"div">; const ThreadViewport = ({ children, className, ...props }: ThreadViewportProps) => ( - +
    transition={{ duration: 0.2, ease: "easeOut" }} {...props} > - diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx index 6369528..ae656fd 100644 --- a/components/app-sidebar.tsx +++ b/components/app-sidebar.tsx @@ -1,10 +1,11 @@ "use client"; -import { Bin, BookOpen, MoreVertical, Plus } from "@keyline-icons/react"; +import { Bin, BookOpen, MoreVertical, SquarePen } from "@keyline-icons/react"; // Keyline has no brand icons, so these two stay on Tabler. import { IconBrandGithub, IconBrandNpm } from "@tabler/icons-react"; import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; -import { IntentfaceLogo } from "@/components/icons/intentface-logo"; +import { LogoTile } from "@/components/icons/logo-tile"; +import { IconButton } from "@/components/ui/icon-button"; import { Sidebar } from "@/components/ui/sidebar"; import { deleteChatInstance } from "@/lib/chat-instance"; import { useChatStore } from "@/lib/store/chat"; @@ -27,26 +28,21 @@ export const AppSidebar = () => { return ( - - - + + + + intentface/chat + + + + + New chat + - - - - - - New Chat - - } - /> - - - Threads @@ -87,47 +83,48 @@ export const AppSidebar = () => { - - - - - - Docs - - } - /> - - - - - GitHub - - } - /> - - - - - npm - - } - /> - - + + + + Docs + +
    + + + + } + /> + + + + } + /> +
    ); diff --git a/components/chat.tsx b/components/chat.tsx index c92c696..b255be4 100644 --- a/components/chat.tsx +++ b/components/chat.tsx @@ -10,17 +10,18 @@ import { } from "@intentface/chat/message-utils"; import { isToolPart, type ToolPart, type UnknownPart } from "@intentface/chat/types"; import { - IconAlertTriangle, - IconBrain, - IconCheck, - IconChevronDown, - IconCircle, - IconHelpCircle, - IconQuote, - IconRefresh, - IconSandbox, - IconX, -} from "@tabler/icons-react"; + Brain, + Check, + ChevronDown, + Circle, + CircleQuestion, + Quote, + RefreshCw, + TriangleAlert, + X, +} from "@keyline-icons/react"; +// Keyline has no sandbox icon, so this one stays on Tabler. +import { IconSandbox } from "@tabler/icons-react"; import type { ChatStatus } from "ai"; import { AnimatePresence, motion, stagger } from "motion/react"; import { useRouter } from "next/navigation"; @@ -35,7 +36,6 @@ import { useRef, useState, } from "react"; -import { CHIP_SURFACE_CLASS } from "@/components/ai/chip"; import { type CommandItemData, Composer, @@ -70,7 +70,7 @@ import { useModelStore } from "@/lib/store/model"; import { usePlaygroundStore } from "@/lib/store/playground"; import { useSettingsStore } from "@/lib/store/settings"; import { cn } from "@/lib/utils"; -import { IntentfaceLogo } from "./icons/intentface-logo"; +import { LogoTile } from "./icons/logo-tile"; import { TextShimmer } from "./ui/text-shimmer"; type ChatSelection = { @@ -130,10 +130,10 @@ export const useChatMessages = (): ChatMessagesValue => { type IconComponent = React.ComponentType<{ className?: string }>; const statusIcons: Record = { - complete: IconCheck, - active: IconCircle, - pending: IconCircle, - error: IconAlertTriangle, + complete: Check, + active: Circle, + pending: Circle, + error: TriangleAlert, }; // A timeline row: static when it has no detail, collapsible (icon morphs to a @@ -155,14 +155,14 @@ const TimelineStep = ({ const iconClasses = cn( status === "complete" && "text-ink-secondary", status === "active" && "text-ink-primary", - status === "pending" && "text-slate-9", + status === "pending" && "text-ink-tertiary", status === "error" && "text-red-500", ); const labelClasses = cn( "text-sm text-left", status === "active" && "text-ink-primary font-medium", status === "complete" && "text-ink-secondary", - status === "pending" && "text-slate-9", + status === "pending" && "text-ink-tertiary", status === "error" && "text-red-500", ); @@ -188,7 +188,7 @@ const TimelineStep = ({ - + {label} @@ -209,7 +209,7 @@ const TimelineToolCall = ({ part }: { part: ToolPart }) => { {sources.map((source, index) => ( {source.domain} @@ -224,7 +224,7 @@ const TimelineAskUser = ({ part }: { part: ToolPart }) => { const { label, status, questions, answers, isComplete } = getAskUserStepInfo(part); return ( - +
    {questions.map((q) => (
    @@ -360,7 +360,7 @@ const InterleavedSteps = ({ {header} - + {segments.map((seg, i) => { @@ -376,7 +376,7 @@ const InterleavedSteps = ({ key={`r-${i}-${j}`} label={section.header ?? "Thinking"} status={streaming && j === sections.length - 1 ? "active" : "complete"} - icon={IconBrain} + icon={Brain} > {section.body && ( @@ -525,7 +525,7 @@ const ChatMessageItem = memo( onClick={() => regenerate({ messageId: message.id })} tooltip="Regenerate" > - + )} @@ -961,30 +961,24 @@ const ChatInputInner = memo(({ panelState, status }: ChatInputInnerProps) => { {showContextStrip && ( - - + + Playground )} {selections.length > 0 && ( -
    - +
    + {selections.length} selection{selections.length === 1 ? "" : "s"}
    )} @@ -1024,7 +1018,7 @@ const ChatInputInner = memo(({ panelState, status }: ChatInputInnerProps) => { ) : ( -
    +
    @@ -1060,13 +1054,16 @@ const ChatPlaceholder = () => { className="flex flex-col items-center justify-center gap-4" > - +
    - + Intentface Chat - + Start a conversation
    @@ -1089,27 +1086,30 @@ const ChatDefaultLayout = memo(() => { {/* Auto-scroll behavior is driven by the user's setting: "bottom" lands the newest turn at the bottom and follows, "jump" lands it at the top without following, "follow" lands at the top and follows, "off" disables it. */} - -
    - {showOverlays && } - - {isEmpty ? ( - - - - ) : ( - - )} - - - {showScrollButton && } - - - {showOverlays && } - {/* Rendered last so the card triggers come after the composer in tab - order; absolute positioning puts them in the top-right regardless. */} + {/* A row, so the settings card pushes the thread over instead of covering it. */} +
    + +
    + {showOverlays && } + + {isEmpty ? ( + + + + ) : ( + + )} + + + {showScrollButton && } + + + {showOverlays && } + + {/* Rendered last so the settings come after the composer in tab order; + the gear is positioned in the top-right regardless. */} - +
    ); }); diff --git a/components/composer-tools.tsx b/components/composer-tools.tsx index 4021509..01bfdba 100644 --- a/components/composer-tools.tsx +++ b/components/composer-tools.tsx @@ -20,14 +20,18 @@ export const ActiveTools = ({ tools, onToolsChange }: ToolToggleProps) => { )} @@ -35,14 +39,18 @@ export const ActiveTools = ({ tools, onToolsChange }: ToolToggleProps) => { )}
    @@ -56,7 +64,7 @@ export const ToolsMenu = ({ tools, onToolsChange }: ToolToggleProps) => { + } diff --git a/components/docs/attributes-table.tsx b/components/docs/attributes-table.tsx index 7681770..76187c3 100644 --- a/components/docs/attributes-table.tsx +++ b/components/docs/attributes-table.tsx @@ -1,9 +1,5 @@ -"use client"; - -import { ChevronDown } from "@keyline-icons/react"; -import { motion } from "motion/react"; -import { type ReactNode, useState } from "react"; -import { cn } from "@/lib/utils"; +import type { ReactNode } from "react"; +import { ReferenceTable } from "./reference-table"; export type AttributeRow = { attribute: string; @@ -16,115 +12,26 @@ type AttributesTableProps = { }; // Hand-authored data-attribute reference — the styling hooks a part emits. -// Built exactly like PropsTable: collapsed shows the attribute and its values, -// expanding reveals the description. The two sit next to each other in every -// API reference, so they read as one control rather than two. -export const AttributesTable = ({ rows }: AttributesTableProps) => { - const hasValues = rows.some((row) => row.values); - - return ( -
    - - - - - - - - - - - - - - - {rows.map((row) => ( - - ))} - -
    AttributeValues - Details -
    -
    - ); -}; - -const AttributeTableRow = ({ row, hasValues }: { row: AttributeRow; hasValues: boolean }) => { - const [open, setOpen] = useState(false); - - return ( - <> - setOpen((current) => !current)} - > - - {row.attribute} - - - {row.values ? ( - {row.values} - ) : ( - {hasValues ? "—" : ""} - )} - - -
    - +// Descriptions are short, so every row shows its own: no expanding. Values, +// when an attribute has them, sit under its name. +export const AttributesTable = ({ rows }: AttributesTableProps) => ( + + {rows.map((row) => ( + + +
    + + {row.attribute} + + {row.values && ( + + {row.values} + + )}
    + {row.description} - - - -
    - - {row.attribute} - - - {row.description} - - - {row.values ? ( - {row.values} - ) : ( - — - )} - -
    -
    - - - - ); -}; - -// Mirrors PropsTable's detail grid, so an expanded attribute and an expanded -// prop line up with each other down the page. -const DetailRow = ({ label, children }: { label: string; children: ReactNode }) => ( -
    -
    {label}
    -
    {children}
    -
    + ))} +
    ); diff --git a/components/docs/code-block.tsx b/components/docs/code-block.tsx index f052256..ebeaea7 100644 --- a/components/docs/code-block.tsx +++ b/components/docs/code-block.tsx @@ -1,28 +1,30 @@ import { highlight } from "fumadocs-core/highlight"; import type { ReactNode } from "react"; +import { codeTheme } from "@/lib/docs/code-theme"; import { cn } from "@/lib/utils"; +import { CodeFrame, CodeTab } from "./code-frame"; type CodeBlockProps = { code: string; lang?: string; - /** Small label shown above the block (e.g. a target file path). */ + /** The tab label, usually a file path. Falls back to the language. */ title?: ReactNode; className?: string; }; -// Server-side shiki highlight. Emits dual-theme spans (--shiki / --shiki-dark); -// the `.dark` activation rule lives in globals.css under the shiki section. -export const CodeBlock = async ({ code, lang = "tsx", title, className }: CodeBlockProps) => { - const rendered = await highlight(code, { +/** Server-side shiki highlight into a bare
    , for any code chrome to wrap. */
    +export const highlightCode = (code: string, lang = "tsx") =>
    +  highlight(code, {
         lang,
    -    themes: { light: "github-light", dark: "github-dark" },
    -    defaultColor: false,
    +    theme: codeTheme,
         components: {
    -      pre: ({ className: preClassName, ...props }) => (
    +      pre: ({ className, ...props }) => (
             
    @@ -30,14 +32,12 @@ export const CodeBlock = async ({ code, lang = "tsx", title, className }: CodeBl
         },
       });
     
    -  return (
    -    
    - {title && ( -
    - {title} -
    - )} -
    pre]:rounded-t-none")}>{rendered}
    -
    - ); -}; +export const CodeBlock = async ({ code, lang = "tsx", title, className }: CodeBlockProps) => ( + {title ?? lang}} + code={code} + className={className} + > + {await highlightCode(code, lang)} + +); diff --git a/components/docs/code-files.tsx b/components/docs/code-files.tsx new file mode 100644 index 0000000..e73c2f2 --- /dev/null +++ b/components/docs/code-files.tsx @@ -0,0 +1,33 @@ +"use client"; + +import type { ReactNode } from "react"; +import { useState } from "react"; +import { CodeFrame, CodeTab } from "./code-frame"; + +export type CodeFileEntry = { + name: string; + source: string; + /** Pre-highlighted source, rendered on the server. */ + code: ReactNode; +}; + +// Client shell for a multi-file block: one tab per file. The server highlights +// every file up front; this only picks which one shows and gets copied. +export const CodeFiles = ({ files, className }: { files: CodeFileEntry[]; className?: string }) => { + const [name, setName] = useState(files[0].name); + const current = files.find((file) => file.name === name) ?? files[0]; + + return ( + ( + setName(file.name)}> + {file.name} + + ))} + > + {current.code} + + ); +}; diff --git a/components/docs/code-frame.tsx b/components/docs/code-frame.tsx new file mode 100644 index 0000000..5c706b6 --- /dev/null +++ b/components/docs/code-frame.tsx @@ -0,0 +1,87 @@ +"use client"; + +import { Check, Copy } from "@keyline-icons/react"; +import type { ReactNode } from "react"; +import { useCopy } from "@/hooks/use-copy"; +import { cn } from "@/lib/utils"; + +/** + * The dark code chrome shared by every block in the docs: a header of file (or + * package-manager) tabs with a copy button, over an inset code panel. Dark in + * both themes, so the tokens are fixed rather than seed-derived. + */ +export const CodeFrame = ({ + tabs, + code, + className, + children, +}: { + tabs: ReactNode; + /** What the copy button copies. */ + code: string; + className?: string; + children: ReactNode; +}) => ( +
    +
    +
    {tabs}
    + +
    +
    + {children} +
    +
    +); + +/** A header tab. Without `onClick` it is a plain label (a single file's name). */ +export const CodeTab = ({ + active = true, + onClick, + children, +}: { + active?: boolean; + onClick?: () => void; + children: ReactNode; +}) => { + const className = cn( + "flex h-full shrink-0 items-center font-medium font-mono text-xs transition-colors", + active + ? "text-white/92 shadow-[inset_0_-1px_0_rgb(255_255_255/0.92)]" + : "text-white/50 hover:text-white/80", + ); + + return onClick ? ( + + ) : ( + {children} + ); +}; + +const CodeCopyButton = ({ code }: { code: string }) => { + const { copy, copied } = useCopy(); + const isCopied = copied === code; + + return ( + + ); +}; diff --git a/components/docs/component-preview-frame.tsx b/components/docs/component-preview-frame.tsx index 5b7e1e9..9b4ebe9 100644 --- a/components/docs/component-preview-frame.tsx +++ b/components/docs/component-preview-frame.tsx @@ -1,6 +1,10 @@ "use client"; +import { RotateCcw } from "@keyline-icons/react"; +import { motion, useReducedMotion } from "motion/react"; import { type ReactNode, useState } from "react"; +import { IconButton } from "@/components/ui/icon-button"; +import { useMeasure } from "@/hooks/use-measure"; import { cn } from "@/lib/utils"; type ComponentPreviewFrameProps = { @@ -8,35 +12,109 @@ type ComponentPreviewFrameProps = { code: ReactNode; }; +type View = "preview" | "code"; + +const SWITCH_TRANSITION = { duration: 0.3, ease: [0.32, 0.72, 0, 1] } as const; +const INSTANT = { duration: 0 } as const; +const SHOWN = { opacity: 1, filter: "blur(0px)", transitionEnd: { filter: "none" } }; +const HIDDEN = { opacity: 0, filter: "blur(4px)" }; + // Client shell for the preview/code toggle. The server component highlights the -// source and renders the demo; this only owns the tab state. +// source and renders the demo; this owns the tab state and the replay remount. +// One card holds both views: they cross-dissolve inside it while the card eases +// between their heights, and the demo stays mounted, keeping its state. export const ComponentPreviewFrame = ({ preview, code }: ComponentPreviewFrameProps) => { - const [tab, setTab] = useState<"preview" | "code">("preview"); + const [tab, setTab] = useState("preview"); + const [run, setRun] = useState(0); + // Both views are measured, so a switch knows its target height up front. + const [previewRef, previewBounds] = useMeasure(); + const [codeRef, codeBounds] = useMeasure(); + // Only a switch eases; a demo growing on its own is followed instantly. + const [switching, setSwitching] = useState(false); + const reduceMotion = useReducedMotion(); + + const height = (tab === "preview" ? previewBounds : codeBounds).height; + const paneTransition = reduceMotion ? INSTANT : SWITCH_TRANSITION; + + const select = (next: View) => { + if (next === tab) return; + setSwitching(true); + setTab(next); + }; return ( -
    -
    +
    +
    {(["preview", "code"] as const).map((value) => ( ))}
    - {tab === "preview" ? ( -
    {preview}
    - ) : ( -
    {code}
    - )} + {/* Clips only mid-switch, so a demo's own popups can spill out otherwise. */} + setSwitching(false)} + className={cn( + "relative rounded-xl bg-primary-bg shadow-card", + switching && "overflow-hidden", + )} + > + + {/* Replay remounts the demo, so animations and seeded state start over. */} + setRun((current) => current + 1)} + className="absolute top-2 right-2" + > + + +
    + {preview} +
    +
    + + {code} + +
    ); }; + +// The active view sits in flow; the other lies over it, faded out. +const paneClass = (active: boolean) => + active ? "relative" : "pointer-events-none absolute inset-x-0 top-0"; diff --git a/components/docs/demo.tsx b/components/docs/demo.tsx index cba4c8a..54d9e7e 100644 --- a/components/docs/demo.tsx +++ b/components/docs/demo.tsx @@ -1,7 +1,7 @@ -import { readFile } from "node:fs/promises"; -import path from "node:path"; import type { ReactNode } from "react"; -import { CodeBlock } from "./code-block"; +import { languageOf, readDemoFiles } from "@/lib/docs/demo-files"; +import { highlightCode } from "./code-block"; +import { CodeFiles } from "./code-files"; import { ComponentPreviewFrame } from "./component-preview-frame"; type DemoProps = { @@ -10,15 +10,18 @@ type DemoProps = { file: string; }; -// Server component: renders a colocated demo and shows that same file's source, -// read from disk at build time — the file that runs is the file displayed. +// Server component: renders a colocated demo and shows its source, read from +// disk at build time — the files that run are the files displayed. A demo split +// across local imports shows one tab per file. export const Demo = async ({ component, file }: DemoProps) => { - const source = await readFile(path.join(process.cwd(), "content", "docs", file), "utf8"); - - return ( - } - /> + const files = await readDemoFiles(file); + const entries = await Promise.all( + files.map(async ({ name, file: filePath, source }) => ({ + name, + source: source.trimEnd(), + code: await highlightCode(source.trimEnd(), languageOf(filePath)), + })), ); + + return } />; }; diff --git a/components/docs/docs-search.tsx b/components/docs/docs-search.tsx index 86bbf4c..d83314a 100644 --- a/components/docs/docs-search.tsx +++ b/components/docs/docs-search.tsx @@ -1,20 +1,155 @@ "use client"; -import { Search } from "@keyline-icons/react"; +import { + AlignLeft, + ArrowDown, + ArrowUp, + CornerDownLeft, + FileText, + Hash, + Search, +} from "@keyline-icons/react"; import { useDocsSearch } from "fumadocs-core/search/client"; import Link from "next/link"; -import { useEffect, useState } from "react"; +import { useRouter } from "next/navigation"; +import { type KeyboardEvent, type ReactNode, useEffect, useId, useState } from "react"; import { Dialog } from "@/components/ui/dialog"; import { IconButton } from "@/components/ui/icon-button"; +import { Kbd } from "@/components/ui/kbd"; import { cn } from "@/lib/utils"; -export const DocsSearch = () => { +type SearchResult = { + id: string; + url: string; + type: "page" | "heading" | "text"; + content: string; + breadcrumbs?: string[]; +}; + +type ResultSection = { label: string; items: SearchResult[] }; + +/* + * ⌘K palette over the static Orama index (/api/search). Results arrive flat — + * a page followed by its matching headings and text — so they are grouped by + * the page's section, and arrow keys walk the flat order across groups. + */ + +// A page opens a section named after its breadcrumb; headings and text follow +// the page they belong to. +const toSections = (results: SearchResult[]): ResultSection[] => { + const sections: ResultSection[] = []; + + for (const result of results) { + const last = sections.at(-1); + const label = result.type === "page" ? (result.breadcrumbs?.at(-1) ?? "Docs") : last?.label; + + if (last && last.label === label) last.items.push(result); + else sections.push({ label: label ?? "Docs", items: [result] }); + } + + return sections; +}; + +// Orama marks matches with ; content keeps markdown backticks. Render +// both — never the raw tags. +const Highlighted = ({ content }: { content: string }) => { + const marked = (text: string, keyPrefix: string) => + text.split(/(.*?<\/mark>)/g).map((part, index) => + part.startsWith("") ? ( + + {part.slice(6, -7)} + + ) : ( + part + ), + ); + + return content.split(/(`[^`]+`)/g).map((part, index) => + part.startsWith("`") && part.endsWith("`") && part.length > 1 ? ( + + {marked(part.slice(1, -1), String(index))} + + ) : ( + marked(part, String(index)) + ), + ); +}; + +const ResultRow = ({ + result, + section, + isActive, + optionId, + onActivate, + onSelect, +}: { + result: SearchResult; + section: string; + isActive: boolean; + optionId: string; + onActivate: () => void; + onSelect: () => void; +}) => { + const isPage = result.type === "page"; + + return ( + element?.scrollIntoView({ block: "nearest" }) : undefined} + className={cn( + "flex items-center gap-2.5 rounded-[10px] pr-2 outline-none", + isPage ? "h-11 pl-2" : "h-9 pl-[46px]", + isActive && "bg-ink-primary/5", + )} + > + {isPage ? ( + + + + ) : result.type === "heading" ? ( + + ) : ( + + )} + + + + {isPage && {section}} + {isActive && ( + + + + )} + + ); +}; + +export type SearchSuggestion = { url: string; title: string }; + +export const DocsSearch = ({ suggestions = [] }: { suggestions?: SearchSuggestion[] }) => { const [open, setOpen] = useState(false); // The "fetch" preset queries the /api/search route handler (createFromSource). const { search, setSearch, query } = useDocsSearch({ type: "fetch" }); + const router = useRouter(); + const listId = useId(); + + // The highlight belongs to the query it was made for; a new query starts at the top. + const [active, setActive] = useState({ search: "", index: 0 }); useEffect(() => { - const onKey = (event: KeyboardEvent) => { + const onKey = (event: globalThis.KeyboardEvent) => { if (event.key === "k" && (event.metaKey || event.ctrlKey)) { event.preventDefault(); setOpen((value) => !value); @@ -24,61 +159,160 @@ export const DocsSearch = () => { return () => window.removeEventListener("keydown", onKey); }, []); - const results = Array.isArray(query.data) ? query.data : []; + // An empty query is primed with the primitives, so the palette never opens blank. + const results = + search.length === 0 + ? suggestions.map( + (suggestion): SearchResult => ({ + id: suggestion.url, + url: suggestion.url, + type: "page", + content: suggestion.title, + breadcrumbs: ["Primitives"], + }), + ) + : Array.isArray(query.data) + ? (query.data as SearchResult[]) + : []; + const sections = toSections(results); + const flat = sections.flatMap((section) => + section.items.map((result) => ({ result, section: section.label })), + ); + const activeIndex = active.search === search ? Math.min(active.index, flat.length - 1) : 0; + const optionId = (index: number) => `${listId}-option-${index}`; + + const close = () => setOpen(false); + + const handleKeyDown = (event: KeyboardEvent) => { + if (flat.length === 0) return; + switch (event.key) { + case "ArrowDown": + event.preventDefault(); + setActive({ search, index: (activeIndex + 1) % flat.length }); + break; + case "ArrowUp": + event.preventDefault(); + setActive({ search, index: (activeIndex - 1 + flat.length) % flat.length }); + break; + case "Enter": + event.preventDefault(); + router.push(flat[activeIndex].result.url); + close(); + break; + } + }; + + let body: ReactNode; + switch (true) { + case search.length === 0 && flat.length === 0: + body = Search pages, headings and text.; + break; + case flat.length === 0 && query.isLoading: + body = Searching…; + break; + case flat.length === 0: + body = No results for “{search}”.; + break; + default: { + let index = -1; + body = sections.map((section, sectionIndex) => ( +
    +
    + {section.label} +
    + {section.items.map((result) => { + index += 1; + const rowIndex = index; + return ( + setActive({ search, index: rowIndex })} + onSelect={close} + /> + ); + })} +
    + )); + } + } return ( } /> - + Search documentation -
    - +
    + setSearch(event.target.value)} - placeholder="Search documentation..." - className="w-full bg-transparent py-3 text-ink-primary text-sm outline-none placeholder:text-ink-tertiary" + onKeyDown={handleKeyDown} + placeholder="Search documentation…" + role="combobox" + aria-expanded={flat.length > 0} + aria-controls={listId} + aria-activedescendant={flat.length > 0 ? optionId(activeIndex) : undefined} + className="h-full flex-1 bg-transparent text-ink-primary text-xl outline-none placeholder:text-ink-tertiary" /> + Esc +
    +
    + {body}
    -
    - {results.length === 0 ? ( -

    - {search ? "No results found." : "Type to search."} -

    - ) : ( -
      - {results.map((result) => ( -
    • - setOpen(false)} - className={cn( - "block rounded-md px-3 py-2 text-sm transition-colors hover:bg-secondary-bg-hover", - result.type === "page" - ? "font-medium text-ink-primary" - : "pl-6 text-ink-secondary", - )} - > - {result.content} - -
    • - ))} -
    - )} +
    + + + + + + + + + + Navigate + + + + + + Open + + + Esc + Close +
    ); }; + +const PaletteNote = ({ children }: { children: ReactNode }) => ( +

    {children}

    +); diff --git a/components/docs/docs-shell.tsx b/components/docs/docs-shell.tsx new file mode 100644 index 0000000..ef44a8e --- /dev/null +++ b/components/docs/docs-shell.tsx @@ -0,0 +1,34 @@ +"use client"; + +import type { ComponentProps, ReactNode } from "react"; +import { Sidebar } from "@/components/ui/sidebar"; +import { DocsSidebar } from "./docs-sidebar"; + +/** + * The docs on the same shell as the playground: collapsible sidebar, mobile + * drawer and the panel inset. A client component for the same reason as + * ChatShell — `Sidebar` is an `Object.assign` compound, which a server + * component would read as a proxy. + * + * Docs stay statically rendered, so the sidebar starts open rather than + * restoring the cookie; the layout it writes is still shared with the chat. + */ +export const DocsShell = ({ + tree, + children, +}: { + tree: ComponentProps["tree"]; + children: ReactNode; +}) => ( + + + + + {/* The panel scrolls, not the window, so the frame stays put around it. */} +
    + {children} +
    +
    +
    +
    +); diff --git a/components/docs/docs-sidebar.tsx b/components/docs/docs-sidebar.tsx index 8463434..b66c432 100644 --- a/components/docs/docs-sidebar.tsx +++ b/components/docs/docs-sidebar.tsx @@ -1,29 +1,25 @@ "use client"; -import { ChevronDown } from "@keyline-icons/react"; // Keyline has no brand or sandbox icons, so these stay on Tabler. import { IconBrandGithub, IconBrandNpm, IconSandbox } from "@tabler/icons-react"; import Link from "next/link"; import { usePathname } from "next/navigation"; -import { type ReactNode, useEffect, useMemo, useState } from "react"; -import { IntentfaceLogo } from "@/components/icons/intentface-logo"; -import { Collapsible } from "@/components/ui/collapsible"; -import { cn } from "@/lib/utils"; -import { DocsSearch } from "./docs-search"; +import type { ReactNode } from "react"; +import { LogoTile } from "@/components/icons/logo-tile"; +import { IconButton } from "@/components/ui/icon-button"; +import { Sidebar } from "@/components/ui/sidebar"; +import { DocsSearch, type SearchSuggestion } from "./docs-search"; import { DocsThemeToggle } from "./docs-theme-toggle"; // Structural mirror of fumadocs' page-tree nodes (typeof source.pageTree). We -// only render the two node shapes our docs use: pages and one level of folder. +// only render the node shapes our docs use: pages, separators and one level of folder. type TreeItem = { type: "page"; name: ReactNode; url: string }; -type TreeFolder = { - type: "folder"; - name: ReactNode; - index?: TreeItem; - children: TreeNode[]; -}; +type TreeFolder = { type: "folder"; name: ReactNode; children: TreeNode[] }; type TreeSeparator = { type: "separator"; name?: ReactNode }; type TreeNode = TreeItem | TreeFolder | TreeSeparator; +type NavGroup = { label?: ReactNode; items: TreeItem[] }; + type DocsSidebarProps = { tree: { children: TreeNode[] }; }; @@ -32,148 +28,139 @@ type DocsSidebarProps = { // out for a release or two. const NEW_PAGES = new Set(["/primitives/shell", "/primitives/nav", "/primitives/tabs"]); -const NavLink = ({ url, name }: { url: string; name: ReactNode }) => { - const pathname = usePathname(); - const isActive = pathname === url; - return ( - - {name} - {NEW_PAGES.has(url) && ( - - New - - )} - - ); -}; +// A separator opens a labelled group for the root pages after it; a folder is a +// group of its own. +const toGroups = (nodes: TreeNode[]): NavGroup[] => { + const groups: NavGroup[] = []; + let open: NavGroup | null = null; -const hasActiveNode = (nodes: TreeNode[], pathname: string): boolean => - nodes.some((child) => { - if (child.type === "page") return child.url === pathname; - if (child.type === "folder") { - if (child.index?.url === pathname) return true; - return hasActiveNode(child.children, pathname); + for (const node of nodes) { + switch (node.type) { + case "separator": + open = { label: node.name, items: [] }; + groups.push(open); + break; + case "folder": + groups.push({ + label: node.name, + items: node.children.filter((child): child is TreeItem => child.type === "page"), + }); + open = null; + break; + case "page": + if (!open) { + open = { items: [] }; + groups.push(open); + } + open.items.push(node); + break; } - return false; - }); + } -const TreeFolderNode = ({ node, index }: { node: TreeFolder; index: number }) => { - const pathname = usePathname(); - const containsActive = useMemo( - () => hasActiveNode(node.children, pathname) || node.index?.url === pathname, - [node, pathname], - ); - const [open, setOpen] = useState(true); + return groups; +}; - useEffect(() => { - if (containsActive) setOpen(true); - }, [containsActive]); +// The search palette opens on these before anything is typed. +const toSuggestions = (groups: NavGroup[]): SearchSuggestion[] => + groups + .flatMap((group) => group.items) + .filter((item) => item.url.startsWith("/primitives/")) + .map((item) => ({ + url: item.url, + title: typeof item.name === "string" ? item.name : item.url, + })); + +const NavLink = ({ item }: { item: TreeItem }) => { + const pathname = usePathname(); return ( -
  • - - - {node.name} - + + {item.name} + {NEW_PAGES.has(item.url) && ( + + New + )} - /> - - - - - -
  • + + } + /> + ); }; -const TreeNodes = ({ nodes }: { nodes: TreeNode[] }) => ( -
      - {nodes.map((node, index) => { - if (node.type === "separator") { - return ( -
    • - {node.name} -
    • - ); - } - if (node.type === "folder") { - return ; - } - return ( -
    • - -
    • - ); - })} -
    +const FooterLink = ({ href, label, icon }: { href: string; label: string; icon: ReactNode }) => ( + + {icon} + + } + /> ); -const ExternalLink = ({ href, icon, label }: { href: string; icon: ReactNode; label: string }) => ( - - {icon} - {label} - -); +export const DocsSidebar = ({ tree }: DocsSidebarProps) => { + const groups = toGroups(tree.children); -export const DocsSidebar = ({ tree }: DocsSidebarProps) => ( - -); + Playground + +
    + } + /> + } + /> + +
    + + + ); +}; diff --git a/components/docs/docs-theme-toggle.tsx b/components/docs/docs-theme-toggle.tsx index d3a091b..a573ca5 100644 --- a/components/docs/docs-theme-toggle.tsx +++ b/components/docs/docs-theme-toggle.tsx @@ -5,7 +5,7 @@ import { IconButton } from "@/components/ui/icon-button"; import { useInterfaceTheme } from "@/hooks/use-interface-theme"; /** - * A single button rather than a three-way control: the sidebar header has room + * A single button rather than a three-way control: the sidebar footer has room * for one affordance, and "system" is the starting mode, not a destination * anyone picks from here. It flips whichever mode is resolved, so the first * press always changes what you see. @@ -17,10 +17,10 @@ export const DocsThemeToggle = () => { return ( setMode(next)} - className="rounded-full" + className="rounded-md" > {resolvedMode === "dark" ? : } diff --git a/components/docs/docs-toc.tsx b/components/docs/docs-toc.tsx index b210687..7b69c63 100644 --- a/components/docs/docs-toc.tsx +++ b/components/docs/docs-toc.tsx @@ -52,25 +52,33 @@ export const DocsTOC = ({ items }: DocsTOCProps) => { const linkClass = (isActive: boolean, depth = 2) => cn( - "-ml-px border-transparent border-l py-1 text-sm transition-colors", - depth >= 3 ? "pl-6" : "pl-4", + "flex h-7 min-w-0 shrink-0 items-center text-sm transition-colors", + depth >= 3 ? "pl-[26px]" : "pl-3.5", + // The active entry draws its own 2px ink rule over the 1px rail. isActive - ? "border-accent-bg font-medium text-ink-primary" - : "text-ink-tertiary hover:text-ink-secondary", + ? "font-medium text-ink-primary shadow-[inset_2px_0_0_var(--color-ink-primary)]" + : "text-ink-secondary hover:text-ink-primary", ); return ( -
    + ); +}; diff --git a/components/docs/props-table.tsx b/components/docs/props-table.tsx index 91640a6..5a9aa43 100644 --- a/components/docs/props-table.tsx +++ b/components/docs/props-table.tsx @@ -4,6 +4,7 @@ import { ChevronDown } from "@keyline-icons/react"; import { motion } from "motion/react"; import { type ReactNode, useState } from "react"; import { cn } from "@/lib/utils"; +import { ReferenceTable } from "./reference-table"; export type PropRow = { name: string; @@ -17,31 +18,22 @@ type PropsTableProps = { }; // Hand-authored prop reference. Rows are collapsible — collapsed shows the prop, -// type, and default (type truncated); expanding reveals the description and the -// full untruncated type. Columns are fixed-width so they stay consistent across -// every table on the page. +// its type (truncated) and default; expanding reveals the description and the +// full type. Columns are fixed-width so they line up across every table on the +// page, AttributesTable included. export const PropsTable = ({ rows }: PropsTableProps) => ( -
    - - - - - - - - - - - - - - - {rows.map((row) => ( - - ))} - -
    PropTypeDefault
    -
    + + {rows.map((row) => ( + + ))} + ); const PropsRow = ({ row }: { row: PropRow }) => { @@ -50,73 +42,63 @@ const PropsRow = ({ row }: { row: PropRow }) => { return ( <> setOpen((current) => !current)} > - - {row.name} + + {row.name} - - {row.type} + + {row.type} - -
    - {row.default ? ( - {row.default} - ) : ( - — - )} - -
    + + {row.default ? ( + {row.default} + ) : ( + — + )} + + + - + -
    - - {row.name} - - - {row.description} - - - - {row.type} - - - - {row.default ? ( - {row.default} - ) : ( - — - )} - -
    +
    +
    {row.description}
    + + {row.type} + +
    @@ -124,12 +106,13 @@ const PropsRow = ({ row }: { row: PropRow }) => { ); }; -// Mirror the collapsed row's column grid (first col 28%, matching the ): the -// label sits under the "Prop" column and its value under "Type", each with the cells' -// px-4 so the detail lines up with the row above it. -const DetailRow = ({ label, children }: { label: string; children: ReactNode }) => ( -
    -
    {label}
    -
    {children}
    -
    +const TypeChip = ({ className, children }: { className?: string; children: ReactNode }) => ( + + {children} + ); diff --git a/components/docs/reference-table.tsx b/components/docs/reference-table.tsx new file mode 100644 index 0000000..16f2ba6 --- /dev/null +++ b/components/docs/reference-table.tsx @@ -0,0 +1,67 @@ +import type { ReactNode } from "react"; + +type Column = { + label: string; + /** A width class for the column, e.g. "w-[30%]". Omit for the flexible column. */ + width?: string; + /** Screen-reader only label (e.g. the expand-toggle column). */ + srOnly?: boolean; +}; + +/** + * The frame every API reference table shares, built two-tone like a code block: + * column labels sit in an outer tray and the rows in an inset panel with its own + * edge. An expanded row takes the tray colour, so it reads as part of the frame. + * The visual header is a separate, hidden table on the same column widths; the + * real lives with the rows for assistive tech. + */ +export const ReferenceTable = ({ + columns, + children, +}: { + columns: Column[]; + children: ReactNode; +}) => { + const colgroup = ( + + {columns.map((column) => ( + + ))} + + ); + + return ( +
    + + {colgroup} + + + {columns.map((column) => ( + + ))} + + + +
    + {/* Dark draws its edge on an overlay: an inset shadow sits under the rows, + so an expanded row's background would paint over it. */} + + {colgroup} + + + {columns.map((column) => ( + + ))} + + + {children} +
    {column.label}
    +
    +
    + ); +}; diff --git a/components/docs/values-table.tsx b/components/docs/values-table.tsx index 9f5fce3..a19d0b4 100644 --- a/components/docs/values-table.tsx +++ b/components/docs/values-table.tsx @@ -1,4 +1,5 @@ import type { ReactNode } from "react"; +import { ReferenceTable } from "./reference-table"; export type ValueRow = { value: string; @@ -15,35 +16,21 @@ type ValuesTableProps = { // every other row). Fixed-width columns and chrome match PropsTable / // AttributesTable so the tables stay visually aligned down the page. export const ValuesTable = ({ rows }: ValuesTableProps) => ( -
    - - - - - - - - - - - - - {rows.map((row) => ( - - - - - ))} - -
    ValueDescription
    -
    - {row.value} - {row.default ? ( - - default - - ) : null} -
    -
    {row.description}
    -
    + + {rows.map((row) => ( + + +
    + {row.value} + {row.default ? ( + + default + + ) : null} +
    + + {row.description} + + ))} +
    ); diff --git a/components/icons/intentface-logo.tsx b/components/icons/intentface-logo.tsx deleted file mode 100644 index fdda4a8..0000000 --- a/components/icons/intentface-logo.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import type { SVGProps } from "react"; - -export const IntentfaceLogo = (props: SVGProps) => { - return ( -