@vvedantb/ui 0.39.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -1
- package/package.json +4 -3
- package/src/ai-elements/__snapshots__/queue.test.tsx.snap +3 -3
- package/src/ai-elements/activity-shared.tsx +1 -103
- package/src/ai-elements/activity-step-label.ts +1 -1
- package/src/ai-elements/activity-step-types.ts +107 -0
- package/src/ai-elements/activity-tasks-utils.ts +1 -1
- package/src/ai-elements/activity-tasks.tsx +14 -10
- package/src/ai-elements/queue.tsx +1 -1
- package/src/ai-elements/trace.tsx +3 -2
- package/src/client.ts +3 -0
- package/src/icons/nav-icon-base.tsx +1 -1
- package/src/index.ts +3 -0
- package/src/marketing/ProductHero.tsx +129 -0
- package/src/marketing/SiteFooter.tsx +2 -1
- package/src/marketing/marketing-classes.ts +3 -0
- package/src/marketing/projectV.ts +2 -0
- package/src/ui/__snapshots__/alt-wrappers.test.tsx.snap +3 -3
- package/src/ui/__snapshots__/sonner-dom.test.tsx.snap +1 -1
- package/src/ui/button.tsx +1 -1
- package/src/ui/clear-input.tsx +1 -1
- package/src/ui/command.tsx +1 -1
- package/src/ui/input.tsx +1 -1
- package/src/ui/search-input.tsx +1 -1
- package/src/ui/select.tsx +1 -1
- package/src/ui/sonner.tsx +11 -0
- package/src/ui/textarea.tsx +1 -1
- package/tokens/src/css/base.css +23 -0
- package/tokens/src/css/markdown.css +4 -2
- package/tokens/src/css/marquee.css +8 -5
- package/tokens/src/css/nav-icons.css +121 -152
- package/tokens/src/css/scrollbar-thin.css +17 -13
- package/tokens/src/css/tabs-pills.css +9 -7
- package/tokens/src/css/tabs.css +5 -1
- package/tokens/src/css/utilities.css +2 -2
- package/tokens/src/tokens.css +8 -6
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Shared React 19 web UI. Source-exported: no build step.
|
|
|
4
4
|
|
|
5
5
|
| Import | What it is |
|
|
6
6
|
| --- | --- |
|
|
7
|
-
| `@vvedantb/ui` | The main JavaScript entry. Primitives (Radix-based), AI elements, audio (`playChime`, `useReplyChime`, `playTone`), `toast` and `SonnerToaster`, the composer (`InputArea`, deprecated 0.3 `Composer`), shell (`SidebarHeader`, `SidebarUpgradeCard`, `PillTabs`, `SessionsHoverCard`, and the app shell: `AppShell`, `AppSidebar`, `SidebarRail`, `RailTile`, `SidebarPanel`, `SidebarAccountMenu`, `SignOutDialog` and related helpers), app helpers (confirm skip, update watcher, settings chrome, `useStableAuth`, and from 0.8.0 `createThemeProvider`, `createPageTitleContext`, `PageMotionProvider` and `formatCompactRelativeTime`), marketing pieces from 0.9.0 (`createLandingKit` and the `Landing*` parts, `SiteFooter`, `PricingModal`), animated nav icons from 0.11.0 (`MemoryIcon`, `BoardIcon`, ... and `NavIconBase`; `SettingsIcon` `variant` from 0.12.0), artifact viewers from 0.13.0 (`ArtifactFrame`, `ArtifactList`, `ArtifactViewer`, ...), date pickers from 0.14.0 (`Calendar`, `DatePicker`, `DateTimePicker`, `MonthPicker`), `cn`, and the native tokens `tokens` and `Tokens`. See `app/README.md` in the repository for the app helpers. |
|
|
7
|
+
| `@vvedantb/ui` | The main JavaScript entry. Primitives (Radix-based), AI elements, audio (`playChime`, `useReplyChime`, `playTone`), `toast` and `SonnerToaster`, the composer (`InputArea`, deprecated 0.3 `Composer`), shell (`SidebarHeader`, `SidebarUpgradeCard`, `PillTabs`, `SessionsHoverCard`, and the app shell: `AppShell`, `AppSidebar`, `SidebarRail`, `RailTile`, `SidebarPanel`, `SidebarAccountMenu`, `SignOutDialog` and related helpers), app helpers (confirm skip, update watcher, settings chrome, `useStableAuth`, and from 0.8.0 `createThemeProvider`, `createPageTitleContext`, `PageMotionProvider` and `formatCompactRelativeTime`), marketing pieces from 0.9.0 (`createLandingKit` and the `Landing*` parts, `SiteFooter`, `PricingModal`; `ProductHero` and `PROJECT_V_HOME_URL` in the next release), animated nav icons from 0.11.0 (`MemoryIcon`, `BoardIcon`, ... and `NavIconBase`; `SettingsIcon` `variant` from 0.12.0), artifact viewers from 0.13.0 (`ArtifactFrame`, `ArtifactList`, `ArtifactViewer`, ...), date pickers from 0.14.0 (`Calendar`, `DatePicker`, `DateTimePicker`, `MonthPicker`), `cn`, and the native tokens `tokens` and `Tokens`. See `app/README.md` in the repository for the app helpers. |
|
|
8
8
|
| `@vvedantb/ui/client` | The root without `@vvedantb/server`, convex or Clerk, for Chrome extensions (0.28.0). Leaves out the artifact viewers, `ConvexClerkProvider`, `useStableAuth`, `createUseStableAuth`, `resetStableAuthSession` and `useEnsureUser`. See [Chrome extensions](#chrome-extensions-0280). |
|
|
9
9
|
| `@vvedantb/ui/brand` | App icons (`Icon*`, `APP_ICONS`), `AppWordmark`, deprecated `AppMark`, raw SVG strings and `FAMILY_APPS`. Also in the root and `/client`. |
|
|
10
10
|
| `@vvedantb/ui/logos` | Third-party brand logos (`GitHubIcon`, `GoogleDriveIcon`, `SlackIcon`, `ClaudeIcon`, `VercelIcon`, ...) and `LogoProps` (0.36.0). Also in the root and `/client`. See [Third-party logos](#third-party-logos-0360). |
|
|
@@ -954,6 +954,57 @@ links under a separator. Set `app` for the Project V footer (0.37.0):
|
|
|
954
954
|
|
|
955
955
|
**Deprecated (no `app`):** `brand`, `socials`, `name` and `legalLinks` are required, and the footer renders as before: the brand sits in the Michroma wrapper, with no product-of line and no Apps column. `actions`, `includeAppsColumn` and `showProductOf` do nothing. Set `app` instead.
|
|
956
956
|
|
|
957
|
+
### `ProductHero`
|
|
958
|
+
|
|
959
|
+
One hero for every product landing page: copy first, then a concept visual on mobile, side by side from `lg`.
|
|
960
|
+
It sits in `landingShellClass` width. The title is the only `h1` and uses the `PageTitle` contract
|
|
961
|
+
(`pageTitleClass`: Instrument Sans, weight 600, `leading-tight`, `tracking-tight`) at `text-4xl sm:text-5xl lg:text-6xl`.
|
|
962
|
+
Actions are pill `Button`s. The only motion `ProductHero` adds is the `userCount` dot pulse, which stops under `prefers-reduced-motion: reduce`.
|
|
963
|
+
|
|
964
|
+
```tsx
|
|
965
|
+
<ProductHero
|
|
966
|
+
title="Make a bot. Keep the chat going."
|
|
967
|
+
tagline="Each bot has its own ongoing chat and its own memory. vibot is your default bot. It sends each message to the bot that should answer."
|
|
968
|
+
primaryCta={{ label: "Try vibot free", href: "/sign-up" }}
|
|
969
|
+
signIn={{ href: "/sign-in" }}
|
|
970
|
+
visual={<OrbitRings />}
|
|
971
|
+
visualLabel="Rings orbiting a bot"
|
|
972
|
+
userCount={userCount} // undefined while loading
|
|
973
|
+
/>
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
Velth has no Sign in, so it sets no `signIn`:
|
|
977
|
+
|
|
978
|
+
```tsx
|
|
979
|
+
const V_STORE_DOWNLOAD_URL = "https://projectv.uk/download/v-store";
|
|
980
|
+
|
|
981
|
+
<ProductHero
|
|
982
|
+
title="Your health, your control"
|
|
983
|
+
tagline="..."
|
|
984
|
+
primaryCta={{ label: "Try the demo", href: "#demo" }}
|
|
985
|
+
secondaryCta={{ label: "Download on V Store", href: V_STORE_DOWNLOAD_URL, rel: "nofollow" }}
|
|
986
|
+
visual={<OrbitRings />}
|
|
987
|
+
/>
|
|
988
|
+
```
|
|
989
|
+
|
|
990
|
+
#### Feeding `userCount`
|
|
991
|
+
|
|
992
|
+
The package does no fetching. The app calls a Convex action that wraps the Clerk backend SDK `clerk.users.getCount()` (it needs `CLERK_SECRET_KEY` on the server), once on mount or cached server-side. Pass `undefined` while loading and the positive number when it resolves. The row stays hidden for `undefined`, `null` and values of 0 or less, so a loading `0` never flashes "0+ people".
|
|
993
|
+
|
|
994
|
+
| Prop | |
|
|
995
|
+
| --- | --- |
|
|
996
|
+
| `title`, `tagline` | Nodes. |
|
|
997
|
+
| `primaryCta` | `{ label, href?, rel?, target?, onClick?, variant? }`. With `href` it renders a plain `a` (no framework link), and `rel` and `target` pass through to it. Otherwise it renders a `button`. Variant default `"default"`. |
|
|
998
|
+
| `secondaryCta` | Same shape. Optional. Variant default `"outline"`. |
|
|
999
|
+
| `signIn` | `{ href?, onClick? }`. Renders exactly one "Sign in" control (`secondary` variant). Omit it for none. Do not also put a Sign in in the page nav. |
|
|
1000
|
+
| `visual` | Node. An animated concept visual in the style of https://projectv.uk (ring, orbit, particles). **Not** an app replica or screenshot. If it animates, it must respect `prefers-reduced-motion`. |
|
|
1001
|
+
| `visualLabel` | Gives the visual region `role="img"` and this name. Without it the region is `aria-hidden`. |
|
|
1002
|
+
| `userCount` | Optional number. Shows "Free to use · {n}+ people already here" under the actions, with a green dot that pulses unless `prefers-reduced-motion: reduce`. `n` is formatted (`1284` is "1,284"). Hidden when `undefined`, `null` or 0 or less. See [Feeding `userCount`](#feeding-usercount). |
|
|
1003
|
+
| `showProductOf` | Default `true`: "a product of Project V" linking to `PROJECT_V_HOME_URL` (`https://projectv.uk`, new tab). The link target is fixed: no prop changes it. `false` hides the whole line. The text names no app, unlike `SiteFooter`. |
|
|
1004
|
+
| `className` | Added to the section. |
|
|
1005
|
+
|
|
1006
|
+
`SiteFooter` uses the same `PROJECT_V_HOME_URL`. A runnable playground is in `examples/product-hero/`.
|
|
1007
|
+
|
|
957
1008
|
### `PageTitle` and `PageHeader`
|
|
958
1009
|
|
|
959
1010
|
`PageTitle` is an `h1` with `text-xl font-semibold leading-tight tracking-tight` (`pageTitleClass`): Instrument Sans, 20px, weight 600, never lighter. `PageHeader` is a title row: `title` in a `PageTitle`, an optional `action` slot, and no safe-area padding.
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vvedantb/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Shared React 19 UI for web apps: one main JavaScript entry (primitives, shell pieces, app helpers including the Convex and Clerk provider, VITE env parsing and ensure-user, artifact viewers over the @vvedantb/server artifacts core, native tokens), third-party brand logos (also @vvedantb/ui/logos), motion-driven animated SVG icons (@vvedantb/ui/icons/animated), a client entry without @vvedantb/server, convex or Clerk for Chrome extensions, design-token CSS, shared Tailwind v4 CSS, a Tailwind preset and packaged Instrument Sans fonts.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"publishConfig": {
|
|
8
|
-
"access": "public"
|
|
8
|
+
"access": "public",
|
|
9
|
+
"provenance": true
|
|
9
10
|
},
|
|
10
11
|
"repository": {
|
|
11
12
|
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/vvedantb/
|
|
13
|
+
"url": "git+https://github.com/vvedantb/packages.git",
|
|
13
14
|
"directory": "packages/ui"
|
|
14
15
|
},
|
|
15
16
|
"exports": {
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`vibot Queue widget DOM > renders the closed widget 1`] = `"<div class="w-full overflow-hidden" style="height: auto; opacity: 1;"><button type="button" class="flex items-center justify-between w-full px-4 py-2.5 bg-surface-secondary text-foreground border-0 shadow-none backdrop-blur-none transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-tertiary rounded-t-2xl group"><div class="flex items-center gap-2"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-stack-2 text-muted-foreground"><path d="M12 4l-8 4l8 4l8 -4l-8 -4"></path><path d="M4 12l8 4l8 -4"></path><path d="M4 16l8 4l8 -4"></path></svg><span class="text-sm font-medium text-foreground">Queued Messages</span><div class="inline-flex items-center gap-1 rounded-full border px-2.5 py-1 font-medium tracking-normal transition-colors focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2 focus:ring-offset-background border-separator bg-default text-default-foreground text-xs">3</div></div><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-down text-muted-foreground transition-transform duration-200 ease-out"><path d="M6 9l6 6l6 -6"></path></svg></button></div>"`;
|
|
4
4
|
|
|
5
|
-
exports[`vibot Queue widget DOM > renders the editing state, then saves the trimmed text 1`] = `"<div class="group relative p-2.5 rounded-lg transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-secondary"><div class="flex flex-col gap-2"><textarea class="flex w-full max-sm:min-w-0 rounded-field border border-border bg-field-background px-3.5 py-2.5 sm:text-sm placeholder:text-field-placeholder disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-hidden focus-visible:border-focus-border focus-visible:ring-1 focus-visible:ring-focus-ring min-h-[60px]
|
|
5
|
+
exports[`vibot Queue widget DOM > renders the editing state, then saves the trimmed text 1`] = `"<div class="group relative p-2.5 rounded-lg transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-secondary"><div class="flex flex-col gap-2"><textarea class="flex w-full max-sm:min-w-0 rounded-field border border-border bg-field-background px-3.5 py-2.5 text-base sm:pointer-fine:text-sm placeholder:text-field-placeholder disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-hidden focus-visible:border-focus-border focus-visible:ring-1 focus-visible:ring-focus-ring min-h-[60px]">Draft</textarea><div class="flex justify-end gap-2"><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] active:duration-[var(--motion-fast,150ms)] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 text-muted-foreground hover:bg-surface-tertiary hover:text-foreground text-xs max-sm:hit-target rounded-full h-7 px-2"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-x"><path d="M18 6l-12 12"></path><path d="M6 6l12 12"></path></svg><span class="ml-1 text-xs">Cancel</span></button><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] active:duration-[var(--motion-fast,150ms)] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:-translate-y-0.5 hover:opacity-90 text-xs max-sm:hit-target rounded-full h-7 px-2"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-check"><path d="M5 12l5 5l10 -10"></path></svg><span class="ml-1 text-xs">Save</span></button></div></div></div>"`;
|
|
6
6
|
|
|
7
|
-
exports[`vibot Queue widget DOM > renders the editing state, then saves the trimmed text 2`] = `"<div class="group relative p-2.5 rounded-lg transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-secondary"><div class="flex items-center gap-2"><p class="text-sm text-foreground/90 flex-1 truncate">Draft</p><div class="flex items-center gap-1.5 shrink-0"></div><div class="flex items-center gap-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 text-muted-foreground hover:bg-surface-tertiary hover:text-foreground text-xs max-sm:hit-target rounded-full h-6 w-6 p-0"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-edit"><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415"></path><path d="M16 5l3 3"></path></svg></button><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 hover:bg-surface-tertiary text-xs max-sm:hit-target rounded-full h-6 w-6 p-0 text-danger hover:text-danger"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-trash"><path d="M4 7l16 0"></path><path d="M10 11l0 6"></path><path d="M14 11l0 6"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"></path><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path></svg></button></div></div></div>"`;
|
|
7
|
+
exports[`vibot Queue widget DOM > renders the editing state, then saves the trimmed text 2`] = `"<div class="group relative p-2.5 rounded-lg transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-secondary"><div class="flex items-center gap-2"><p class="text-sm text-foreground/90 flex-1 truncate">Draft</p><div class="flex items-center gap-1.5 shrink-0"></div><div class="flex items-center gap-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] active:duration-[var(--motion-fast,150ms)] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 text-muted-foreground hover:bg-surface-tertiary hover:text-foreground text-xs max-sm:hit-target rounded-full h-6 w-6 p-0"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-edit"><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415"></path><path d="M16 5l3 3"></path></svg></button><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] active:duration-[var(--motion-fast,150ms)] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 hover:bg-surface-tertiary text-xs max-sm:hit-target rounded-full h-6 w-6 p-0 text-danger hover:text-danger"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-trash"><path d="M4 7l16 0"></path><path d="M10 11l0 6"></path><path d="M14 11l0 6"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"></path><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path></svg></button></div></div></div>"`;
|
|
8
8
|
|
|
9
9
|
exports[`vibot Queue widget DOM > renders the header with a custom class 1`] = `"<button type="button" class="flex items-center justify-between w-full px-4 py-2.5 bg-surface-secondary text-foreground border-0 shadow-none backdrop-blur-none transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-tertiary rounded-t-2xl group x"><div class="flex items-center gap-2"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-stack-2 text-muted-foreground"><path d="M12 4l-8 4l8 4l8 -4l-8 -4"></path><path d="M4 12l8 4l8 -4"></path><path d="M4 16l8 4l8 -4"></path></svg><span class="text-sm font-medium text-foreground">Queued Messages</span><div class="inline-flex items-center gap-1 rounded-full border px-2.5 py-1 font-medium tracking-normal transition-colors focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2 focus:ring-offset-background border-separator bg-default text-default-foreground text-xs">1</div></div><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-down text-muted-foreground transition-transform duration-200 ease-out"><path d="M6 9l6 6l6 -6"></path></svg></button>"`;
|
|
10
10
|
|
|
11
|
-
exports[`vibot Queue widget DOM > renders the open widget 1`] = `"<div class="w-full overflow-hidden mb-2" style="height: auto; opacity: 1;"><button type="button" class="flex items-center justify-between w-full px-4 py-2.5 bg-surface-secondary text-foreground border-0 shadow-none backdrop-blur-none transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-tertiary rounded-t-2xl group"><div class="flex items-center gap-2"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-stack-2 text-muted-foreground"><path d="M12 4l-8 4l8 4l8 -4l-8 -4"></path><path d="M4 12l8 4l8 -4"></path><path d="M4 16l8 4l8 -4"></path></svg><span class="text-sm font-medium text-foreground">Queued Messages</span><div class="inline-flex items-center gap-1 rounded-full border px-2.5 py-1 font-medium tracking-normal transition-colors focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2 focus:ring-offset-background border-separator bg-default text-default-foreground text-xs">3</div></div><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-down text-muted-foreground transition-transform duration-200 ease-out rotate-180"><path d="M6 9l6 6l6 -6"></path></svg></button><div class="overflow-hidden" style="height: auto; opacity: 1;"><div class="bg-surface-secondary text-foreground border-0 shadow-none backdrop-blur-none rounded-b-2xl"><div dir="ltr" data-slot="scroll-area" class="relative max-h-[240px]" style="position: relative; --radix-scroll-area-corner-width: 0px; --radix-scroll-area-corner-height: 0px;"><style>[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}</style><div data-radix-scroll-area-viewport="" data-slot="scroll-area-viewport" class="size-full rounded-[inherit] outline-hidden" style="overflow-x: hidden; overflow-y: scroll;"><div style="min-width: 100%; display: table;"><div class="p-2 space-y-1.5"><div class="group relative p-2.5 rounded-lg transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-secondary"><div class="flex items-center gap-2"><img alt="Ada" class="size-5 rounded-full shrink-0" src="https://example.com/ada.png"><p class="text-sm text-foreground/90 flex-1 truncate">Fix the build</p><div class="flex items-center gap-1.5 shrink-0"><div class="inline-flex items-center gap-1 rounded-full border py-1 font-medium tracking-normal transition-colors focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2 focus:ring-offset-background border-separator bg-transparent text-muted-foreground text-xs h-5 px-1.5">claude-sonnet</div><div class="inline-flex items-center gap-1 rounded-full border py-1 font-medium tracking-normal transition-colors focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2 focus:ring-offset-background border-separator bg-transparent text-muted-foreground text-xs h-5 px-1.5">Terse</div></div><div class="flex items-center gap-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 text-muted-foreground hover:bg-surface-tertiary hover:text-foreground text-xs max-sm:hit-target rounded-full h-6 w-6 p-0"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-edit"><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415"></path><path d="M16 5l3 3"></path></svg></button><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 hover:bg-surface-tertiary text-xs max-sm:hit-target rounded-full h-6 w-6 p-0 text-danger hover:text-danger"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-trash"><path d="M4 7l16 0"></path><path d="M10 11l0 6"></path><path d="M14 11l0 6"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"></path><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path></svg></button></div></div></div><div class="group relative p-2.5 rounded-lg transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-secondary extra"><div class="flex items-center gap-2"><p class="text-sm text-foreground/90 flex-1 truncate">Plain</p><div class="flex items-center gap-1.5 shrink-0"><div class="inline-flex items-center gap-1 rounded-full border py-1 font-medium tracking-normal transition-colors focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2 focus:ring-offset-background border-separator bg-transparent text-muted-foreground text-xs h-5 px-1.5">Bob</div></div><div class="flex items-center gap-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 text-muted-foreground hover:bg-surface-tertiary hover:text-foreground text-xs max-sm:hit-target rounded-full h-6 w-6 p-0"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-edit"><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415"></path><path d="M16 5l3 3"></path></svg></button><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 hover:bg-surface-tertiary text-xs max-sm:hit-target rounded-full h-6 w-6 p-0 text-danger hover:text-danger"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-trash"><path d="M4 7l16 0"></path><path d="M10 11l0 6"></path><path d="M14 11l0 6"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"></path><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path></svg></button></div></div></div><div class="group relative p-2.5 rounded-lg transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-secondary"><div class="flex items-center gap-2"><p class="text-sm text-foreground/90 flex-1 truncate">Bare</p><div class="flex items-center gap-1.5 shrink-0"></div><div class="flex items-center gap-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 text-muted-foreground hover:bg-surface-tertiary hover:text-foreground text-xs max-sm:hit-target rounded-full h-6 w-6 p-0"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-edit"><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415"></path><path d="M16 5l3 3"></path></svg></button><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 hover:bg-surface-tertiary text-xs max-sm:hit-target rounded-full h-6 w-6 p-0 text-danger hover:text-danger"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-trash"><path d="M4 7l16 0"></path><path d="M10 11l0 6"></path><path d="M14 11l0 6"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"></path><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path></svg></button></div></div></div></div></div></div></div></div></div></div>"`;
|
|
11
|
+
exports[`vibot Queue widget DOM > renders the open widget 1`] = `"<div class="w-full overflow-hidden mb-2" style="height: auto; opacity: 1;"><button type="button" class="flex items-center justify-between w-full px-4 py-2.5 bg-surface-secondary text-foreground border-0 shadow-none backdrop-blur-none transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-tertiary rounded-t-2xl group"><div class="flex items-center gap-2"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-stack-2 text-muted-foreground"><path d="M12 4l-8 4l8 4l8 -4l-8 -4"></path><path d="M4 12l8 4l8 -4"></path><path d="M4 16l8 4l8 -4"></path></svg><span class="text-sm font-medium text-foreground">Queued Messages</span><div class="inline-flex items-center gap-1 rounded-full border px-2.5 py-1 font-medium tracking-normal transition-colors focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2 focus:ring-offset-background border-separator bg-default text-default-foreground text-xs">3</div></div><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-down text-muted-foreground transition-transform duration-200 ease-out rotate-180"><path d="M6 9l6 6l6 -6"></path></svg></button><div class="overflow-hidden" style="height: auto; opacity: 1;"><div class="bg-surface-secondary text-foreground border-0 shadow-none backdrop-blur-none rounded-b-2xl"><div dir="ltr" data-slot="scroll-area" class="relative max-h-[240px]" style="position: relative; --radix-scroll-area-corner-width: 0px; --radix-scroll-area-corner-height: 0px;"><style>[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}</style><div data-radix-scroll-area-viewport="" data-slot="scroll-area-viewport" class="size-full rounded-[inherit] outline-hidden" style="overflow-x: hidden; overflow-y: scroll;"><div style="min-width: 100%; display: table;"><div class="p-2 space-y-1.5"><div class="group relative p-2.5 rounded-lg transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-secondary"><div class="flex items-center gap-2"><img alt="Ada" class="size-5 rounded-full shrink-0" src="https://example.com/ada.png"><p class="text-sm text-foreground/90 flex-1 truncate">Fix the build</p><div class="flex items-center gap-1.5 shrink-0"><div class="inline-flex items-center gap-1 rounded-full border py-1 font-medium tracking-normal transition-colors focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2 focus:ring-offset-background border-separator bg-transparent text-muted-foreground text-xs h-5 px-1.5">claude-sonnet</div><div class="inline-flex items-center gap-1 rounded-full border py-1 font-medium tracking-normal transition-colors focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2 focus:ring-offset-background border-separator bg-transparent text-muted-foreground text-xs h-5 px-1.5">Terse</div></div><div class="flex items-center gap-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] active:duration-[var(--motion-fast,150ms)] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 text-muted-foreground hover:bg-surface-tertiary hover:text-foreground text-xs max-sm:hit-target rounded-full h-6 w-6 p-0"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-edit"><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415"></path><path d="M16 5l3 3"></path></svg></button><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] active:duration-[var(--motion-fast,150ms)] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 hover:bg-surface-tertiary text-xs max-sm:hit-target rounded-full h-6 w-6 p-0 text-danger hover:text-danger"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-trash"><path d="M4 7l16 0"></path><path d="M10 11l0 6"></path><path d="M14 11l0 6"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"></path><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path></svg></button></div></div></div><div class="group relative p-2.5 rounded-lg transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-secondary extra"><div class="flex items-center gap-2"><p class="text-sm text-foreground/90 flex-1 truncate">Plain</p><div class="flex items-center gap-1.5 shrink-0"><div class="inline-flex items-center gap-1 rounded-full border py-1 font-medium tracking-normal transition-colors focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2 focus:ring-offset-background border-separator bg-transparent text-muted-foreground text-xs h-5 px-1.5">Bob</div></div><div class="flex items-center gap-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] active:duration-[var(--motion-fast,150ms)] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 text-muted-foreground hover:bg-surface-tertiary hover:text-foreground text-xs max-sm:hit-target rounded-full h-6 w-6 p-0"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-edit"><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415"></path><path d="M16 5l3 3"></path></svg></button><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] active:duration-[var(--motion-fast,150ms)] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 hover:bg-surface-tertiary text-xs max-sm:hit-target rounded-full h-6 w-6 p-0 text-danger hover:text-danger"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-trash"><path d="M4 7l16 0"></path><path d="M10 11l0 6"></path><path d="M14 11l0 6"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"></path><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path></svg></button></div></div></div><div class="group relative p-2.5 rounded-lg transition-[background-color,transform] duration-150 ease-out active:scale-[0.99] hover:bg-surface-secondary"><div class="flex items-center gap-2"><p class="text-sm text-foreground/90 flex-1 truncate">Bare</p><div class="flex items-center gap-1.5 shrink-0"></div><div class="flex items-center gap-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] active:duration-[var(--motion-fast,150ms)] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 text-muted-foreground hover:bg-surface-tertiary hover:text-foreground text-xs max-sm:hit-target rounded-full h-6 w-6 p-0"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-edit"><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415"></path><path d="M16 5l3 3"></path></svg></button><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium tracking-normal transition-[transform,background-color,box-shadow,opacity,border-color] duration-200 ease-smooth focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 active:scale-[0.96] active:duration-[var(--motion-fast,150ms)] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 hover:bg-surface-tertiary text-xs max-sm:hit-target rounded-full h-6 w-6 p-0 text-danger hover:text-danger"><svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-trash"><path d="M4 7l16 0"></path><path d="M10 11l0 6"></path><path d="M14 11l0 6"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"></path><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path></svg></button></div></div></div></div></div></div></div></div></div></div>"`;
|
|
@@ -50,109 +50,7 @@ export interface ActivityTasksConfig {
|
|
|
50
50
|
thinkingIcon?: { src: string; alt: string };
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
export interface ActivityTodoItem {
|
|
55
|
-
content: string;
|
|
56
|
-
status: "pending" | "in_progress" | "completed";
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export interface ActivityStepOutput {
|
|
60
|
-
text: string;
|
|
61
|
-
exitCode?: number;
|
|
62
|
-
truncated?: boolean;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface ActivityStepEdit {
|
|
66
|
-
oldText: string;
|
|
67
|
-
newText: string;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** One choice offered by an AskUserQuestion prompt. */
|
|
71
|
-
export interface ActivityQuestionOption {
|
|
72
|
-
label: string;
|
|
73
|
-
description?: string;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** One question of an AskUserQuestion prompt, with the choices shown. */
|
|
77
|
-
export interface ActivityQuestion {
|
|
78
|
-
question: string;
|
|
79
|
-
header?: string;
|
|
80
|
-
multiSelect?: boolean;
|
|
81
|
-
options: ActivityQuestionOption[];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export interface ActivityStep {
|
|
85
|
-
type:
|
|
86
|
-
| "read"
|
|
87
|
-
| "edit"
|
|
88
|
-
| "write"
|
|
89
|
-
| "bash"
|
|
90
|
-
| "search_files"
|
|
91
|
-
| "search_code"
|
|
92
|
-
| "web_fetch"
|
|
93
|
-
| "web_search"
|
|
94
|
-
| "subtask"
|
|
95
|
-
| "notebook"
|
|
96
|
-
| "thinking"
|
|
97
|
-
| "reasoning"
|
|
98
|
-
| "response"
|
|
99
|
-
| "question"
|
|
100
|
-
| "todos"
|
|
101
|
-
| "tool"
|
|
102
|
-
| "notice"
|
|
103
|
-
| "hook"
|
|
104
|
-
| "status"
|
|
105
|
-
/** A queued user message the agent took into this live turn (Steer). */
|
|
106
|
-
| "steer";
|
|
107
|
-
label: string;
|
|
108
|
-
detail?: string;
|
|
109
|
-
/** Full, unshortened path for file-type steps. Powers the chat File Viewer. */
|
|
110
|
-
path?: string;
|
|
111
|
-
/** `pending`: a planned step that has not started (sandbox startup stages). */
|
|
112
|
-
status: "complete" | "active" | "pending";
|
|
113
|
-
/** The tool_use id that produced this step (Claude only). */
|
|
114
|
-
toolUseId?: string;
|
|
115
|
-
/** Parent `Agent` tool_use id — set on steps that ran inside a subagent. */
|
|
116
|
-
parentToolUseId?: string;
|
|
117
|
-
/** Todo checklist snapshot (type "todos" only). */
|
|
118
|
-
todos?: ActivityTodoItem[];
|
|
119
|
-
/** Bash command (fuller than detail, capped). */
|
|
120
|
-
command?: string;
|
|
121
|
-
/** Tool result transcript (tail-capped). */
|
|
122
|
-
output?: ActivityStepOutput;
|
|
123
|
-
/** Edit before/after snippets. */
|
|
124
|
-
edits?: ActivityStepEdit[];
|
|
125
|
-
/** Codex file_change paths. */
|
|
126
|
-
files?: string[];
|
|
127
|
-
/** Write tool content head preview. */
|
|
128
|
-
contentPreview?: string;
|
|
129
|
-
/** True when the tool failed or exited non-zero. */
|
|
130
|
-
isError?: boolean;
|
|
131
|
-
/** Wall time from push → complete (ms). */
|
|
132
|
-
durationMs?: number;
|
|
133
|
-
/** AskUserQuestion prompt (type "question" only): the questions and options shown to the user. */
|
|
134
|
-
questions?: ActivityQuestion[];
|
|
135
|
-
/** AskUserQuestion answers keyed by question text. Absent when the turn ended without a structured answer. */
|
|
136
|
-
answers?: Record<string, string>;
|
|
137
|
-
/**
|
|
138
|
-
* The transcript query stripped this step's expanded-only fields (`output`,
|
|
139
|
-
* `edits`, `contentPreview`) to keep the chat subscription small. The row
|
|
140
|
-
* still opens; the body fills in once the full payload is fetched.
|
|
141
|
-
*/
|
|
142
|
-
hasHiddenDetail?: boolean;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/** True when the step has expandable rich detail to show. */
|
|
146
|
-
export function activityStepHasRichDetail(step: ActivityStep): boolean {
|
|
147
|
-
return Boolean(
|
|
148
|
-
step.command ||
|
|
149
|
-
step.output ||
|
|
150
|
-
(step.edits && step.edits.length > 0) ||
|
|
151
|
-
(step.files && step.files.length > 0) ||
|
|
152
|
-
step.contentPreview ||
|
|
153
|
-
step.hasHiddenDetail,
|
|
154
|
-
);
|
|
155
|
-
}
|
|
53
|
+
export * from "./activity-step-types";
|
|
156
54
|
|
|
157
55
|
/** Glyph for thinking steps: the app's mark from `UiConfig.ActivityTasks.thinkingIcon`, or a brain. */
|
|
158
56
|
export function ActivityThinkingIcon({ className }: { className?: string }) {
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Pure step types for the activity timeline: no React, so `@vvedantb/native-ui`
|
|
2
|
+
// keeps a byte-identical copy (`src/ai/activity-step-types.ts`), with the step
|
|
3
|
+
// labels and grouping that read them.
|
|
4
|
+
|
|
5
|
+
/** One item in a todo checklist step (type "todos"). */
|
|
6
|
+
export interface ActivityTodoItem {
|
|
7
|
+
content: string;
|
|
8
|
+
status: "pending" | "in_progress" | "completed";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ActivityStepOutput {
|
|
12
|
+
text: string;
|
|
13
|
+
exitCode?: number;
|
|
14
|
+
truncated?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ActivityStepEdit {
|
|
18
|
+
oldText: string;
|
|
19
|
+
newText: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** One choice offered by an AskUserQuestion prompt. */
|
|
23
|
+
export interface ActivityQuestionOption {
|
|
24
|
+
label: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** One question of an AskUserQuestion prompt, with the choices shown. */
|
|
29
|
+
export interface ActivityQuestion {
|
|
30
|
+
question: string;
|
|
31
|
+
header?: string;
|
|
32
|
+
multiSelect?: boolean;
|
|
33
|
+
options: ActivityQuestionOption[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ActivityStep {
|
|
37
|
+
type:
|
|
38
|
+
| "read"
|
|
39
|
+
| "edit"
|
|
40
|
+
| "write"
|
|
41
|
+
| "bash"
|
|
42
|
+
| "search_files"
|
|
43
|
+
| "search_code"
|
|
44
|
+
| "web_fetch"
|
|
45
|
+
| "web_search"
|
|
46
|
+
| "subtask"
|
|
47
|
+
| "notebook"
|
|
48
|
+
| "thinking"
|
|
49
|
+
| "reasoning"
|
|
50
|
+
| "response"
|
|
51
|
+
| "question"
|
|
52
|
+
| "todos"
|
|
53
|
+
| "tool"
|
|
54
|
+
| "notice"
|
|
55
|
+
| "hook"
|
|
56
|
+
| "status"
|
|
57
|
+
/** A queued user message the agent took into this live turn (Steer). */
|
|
58
|
+
| "steer";
|
|
59
|
+
label: string;
|
|
60
|
+
detail?: string;
|
|
61
|
+
/** Full, unshortened path for file-type steps. Powers the chat File Viewer. */
|
|
62
|
+
path?: string;
|
|
63
|
+
/** `pending`: a planned step that has not started (sandbox startup stages). */
|
|
64
|
+
status: "complete" | "active" | "pending";
|
|
65
|
+
/** The tool_use id that produced this step (Claude only). */
|
|
66
|
+
toolUseId?: string;
|
|
67
|
+
/** Parent `Agent` tool_use id — set on steps that ran inside a subagent. */
|
|
68
|
+
parentToolUseId?: string;
|
|
69
|
+
/** Todo checklist snapshot (type "todos" only). */
|
|
70
|
+
todos?: ActivityTodoItem[];
|
|
71
|
+
/** Bash command (fuller than detail, capped). */
|
|
72
|
+
command?: string;
|
|
73
|
+
/** Tool result transcript (tail-capped). */
|
|
74
|
+
output?: ActivityStepOutput;
|
|
75
|
+
/** Edit before/after snippets. */
|
|
76
|
+
edits?: ActivityStepEdit[];
|
|
77
|
+
/** Codex file_change paths. */
|
|
78
|
+
files?: string[];
|
|
79
|
+
/** Write tool content head preview. */
|
|
80
|
+
contentPreview?: string;
|
|
81
|
+
/** True when the tool failed or exited non-zero. */
|
|
82
|
+
isError?: boolean;
|
|
83
|
+
/** Wall time from push → complete (ms). */
|
|
84
|
+
durationMs?: number;
|
|
85
|
+
/** AskUserQuestion prompt (type "question" only): the questions and options shown to the user. */
|
|
86
|
+
questions?: ActivityQuestion[];
|
|
87
|
+
/** AskUserQuestion answers keyed by question text. Absent when the turn ended without a structured answer. */
|
|
88
|
+
answers?: Record<string, string>;
|
|
89
|
+
/**
|
|
90
|
+
* The transcript query stripped this step's expanded-only fields (`output`,
|
|
91
|
+
* `edits`, `contentPreview`) to keep the chat subscription small. The row
|
|
92
|
+
* still opens; the body fills in once the full payload is fetched.
|
|
93
|
+
*/
|
|
94
|
+
hasHiddenDetail?: boolean;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** True when the step has expandable rich detail to show. */
|
|
98
|
+
export function activityStepHasRichDetail(step: ActivityStep): boolean {
|
|
99
|
+
return Boolean(
|
|
100
|
+
step.command ||
|
|
101
|
+
step.output ||
|
|
102
|
+
(step.edits && step.edits.length > 0) ||
|
|
103
|
+
(step.files && step.files.length > 0) ||
|
|
104
|
+
step.contentPreview ||
|
|
105
|
+
step.hasHiddenDetail,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
@@ -109,14 +109,21 @@ const MAX_VISIBLE_ROWS = 8;
|
|
|
109
109
|
/** Max nested child rows shown under a subtask before "+N more". */
|
|
110
110
|
const MAX_VISIBLE_CHILDREN = 8;
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
/**
|
|
113
|
+
* Both layouts show mid-turn reply text in the timeline, in the order it was
|
|
114
|
+
* written, so a live turn never stacks its first words below newer steps.
|
|
115
|
+
*/
|
|
116
|
+
const HIDDEN_TYPES = new Set<ActivityStep["type"]>(["thinking"]);
|
|
113
117
|
|
|
114
|
-
/**
|
|
115
|
-
const
|
|
118
|
+
/** A subagent's own text belongs to its child thread view, not under its row. */
|
|
119
|
+
const HIDDEN_CHILD_TYPES = new Set<ActivityStep["type"]>([
|
|
120
|
+
"thinking",
|
|
121
|
+
"response",
|
|
122
|
+
]);
|
|
116
123
|
|
|
117
124
|
/**
|
|
118
|
-
* `folded` (Codex-style): a settled turn collapses behind "Worked for …"
|
|
119
|
-
* long timelines cap behind "Show N more"
|
|
125
|
+
* `folded` (Codex-style): a settled turn collapses behind "Worked for …" and
|
|
126
|
+
* long timelines cap behind "Show N more".
|
|
120
127
|
* `inline` (Claude-style): every step and the text between them stay open.
|
|
121
128
|
*/
|
|
122
129
|
export type ActivityLayout = "folded" | "inline";
|
|
@@ -396,10 +403,8 @@ function ActivityStepRow({
|
|
|
396
403
|
if (step.type === "reasoning") return <ActivityReasoningLine step={step} />;
|
|
397
404
|
|
|
398
405
|
const Icon = iconForStep(step);
|
|
399
|
-
// A subagent's own text (`response` children) belongs to its child thread
|
|
400
|
-
// view, not the parent's timeline.
|
|
401
406
|
const childRows = (children ?? []).filter(
|
|
402
|
-
(child) => !
|
|
407
|
+
(child) => !HIDDEN_CHILD_TYPES.has(child.step.type),
|
|
403
408
|
);
|
|
404
409
|
const openSubagent =
|
|
405
410
|
step.type === "subtask" ? (
|
|
@@ -693,10 +698,9 @@ export const ActivityTasks = memo(
|
|
|
693
698
|
}: ActivityTasksProps) => {
|
|
694
699
|
const merge = useCn();
|
|
695
700
|
const inline = layout === "inline";
|
|
696
|
-
const hiddenTypes = inline ? INLINE_HIDDEN_TYPES : HIDDEN_TYPES;
|
|
697
701
|
const rows = buildActivityRows(steps).filter(
|
|
698
702
|
(row) =>
|
|
699
|
-
!
|
|
703
|
+
!HIDDEN_TYPES.has(row.step.type) &&
|
|
700
704
|
// A subagent's text whose Agent row is missing still belongs to its
|
|
701
705
|
// child thread, never to the parent's inline reply.
|
|
702
706
|
!(row.step.type === "response" && row.step.parentToolUseId),
|
|
@@ -47,8 +47,9 @@ export function AgentTraceLine({
|
|
|
47
47
|
data-status={status}
|
|
48
48
|
className={merge(
|
|
49
49
|
"flex w-fit max-w-full min-w-0 items-center gap-2 text-muted-foreground text-sm transition-colors",
|
|
50
|
-
|
|
51
|
-
"
|
|
50
|
+
// Gated like `hover:` plus a fine pointer, so a tap on a phone does not leave it lit.
|
|
51
|
+
"[@media(hover:hover)_and_(pointer:fine)]:in-[button:hover]:text-foreground",
|
|
52
|
+
"data-[status=error]:text-destructive data-[status=error]:[@media(hover:hover)_and_(pointer:fine)]:in-[button:hover]:text-destructive",
|
|
52
53
|
"data-[status=pending]:opacity-60",
|
|
53
54
|
className,
|
|
54
55
|
)}
|
package/src/client.ts
CHANGED
|
@@ -326,6 +326,9 @@ export type {
|
|
|
326
326
|
SiteFooterProps,
|
|
327
327
|
SiteFooterSocial,
|
|
328
328
|
} from "./marketing/SiteFooter";
|
|
329
|
+
export { ProductHero } from "./marketing/ProductHero";
|
|
330
|
+
export type { ProductHeroAction, ProductHeroProps } from "./marketing/ProductHero";
|
|
331
|
+
export { PROJECT_V_HOME_URL } from "./marketing/projectV";
|
|
329
332
|
export { PricingModal, V_PRO_APP_BENEFITS } from "./marketing/PricingModal";
|
|
330
333
|
export type {
|
|
331
334
|
PricingModalLegacyProps,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useId, type CSSProperties, type ReactNode, type SVGProps } from "react";
|
|
2
2
|
import { cn } from "../utils/cn";
|
|
3
3
|
|
|
4
|
-
/** `"hover"`: animate while an ancestor with the `group` class is hovered. `true`: always. `false`: never. */
|
|
4
|
+
/** `"hover"`: animate while an ancestor with the `group` class is hovered by a mouse (fine pointer). `true`: always. `false`: never. */
|
|
5
5
|
export type IconAnimate = boolean | "hover";
|
|
6
6
|
|
|
7
7
|
export type IconProps = Omit<SVGProps<SVGSVGElement>, "children" | "color" | "height" | "width" | "strokeWidth"> & {
|
package/src/index.ts
CHANGED
|
@@ -326,6 +326,9 @@ export type {
|
|
|
326
326
|
SiteFooterProps,
|
|
327
327
|
SiteFooterSocial,
|
|
328
328
|
} from "./marketing/SiteFooter";
|
|
329
|
+
export { ProductHero } from "./marketing/ProductHero";
|
|
330
|
+
export type { ProductHeroAction, ProductHeroProps } from "./marketing/ProductHero";
|
|
331
|
+
export { PROJECT_V_HOME_URL } from "./marketing/projectV";
|
|
329
332
|
export { PricingModal, V_PRO_APP_BENEFITS } from "./marketing/PricingModal";
|
|
330
333
|
export type {
|
|
331
334
|
PricingModalLegacyProps,
|