create-ailk 0.1.1 → 0.2.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/component-catalog.md +175 -14
- package/dist/cli.js +0 -0
- package/package.json +14 -15
- package/templates/apps/api/CLAUDE.md +4 -1
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +10 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +11 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +127 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/me-route-precedence.test.ts +221 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +468 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +707 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +11 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +467 -0
- package/templates/apps/api/src/routes/project-listings/index.ts +15 -0
- package/templates/apps/api/src/routes/project-listings/me.ts +76 -0
- package/templates/apps/api/src/routes/project-listings/start.ts +8 -0
- package/templates/apps/api/src/server.ts +14 -0
- package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +65 -0
- package/templates/apps/api/src/services/__tests__/consent.test.ts +282 -0
- package/templates/apps/api/src/services/__tests__/listing-promotion.test.ts +684 -0
- package/templates/apps/api/src/services/consent.ts +236 -0
- package/templates/apps/api/src/services/flow-engine.ts +18 -0
- package/templates/apps/api/src/services/listing-promotion.ts +342 -0
- package/templates/apps/api/src/services/project-listing-decision.ts +21 -1
- package/templates/apps/api/src/services/project-listings.ts +373 -25
- package/templates/apps/web/app/[locale]/layout.tsx +13 -1
- package/templates/apps/web/jest.config.cjs +6 -0
- package/templates/apps/web/lib/__tests__/site-theme.test.ts +112 -0
- package/templates/apps/web/lib/site-brand.tsx +4 -1
- package/templates/apps/web/lib/site-theme.ts +74 -0
- package/templates/apps/web/package.json +1 -0
- package/templates/content/_site.mdx +12 -0
- package/templates/database/CHANGELOG.md +61 -0
- package/templates/database/inbox/schema.prisma +98 -0
- package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +32 -0
- package/templates/database/migrations/20260911180000_consent_grants/migration.sql +71 -0
- package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +30 -0
- package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +49 -0
- package/templates/database/package.json +1 -1
- package/templates/database/scripts/db-generate-locked.sh +0 -0
- package/templates/package.json +1 -1
package/component-catalog.md
CHANGED
|
@@ -2,22 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- GENERATED FILE — do not hand-edit. Regenerate with `pnpm --filter create-ailk run build-catalog`. -->
|
|
4
4
|
|
|
5
|
-
The
|
|
5
|
+
The component inventory of `@working-theory/ui` and the shells of `@working-theory/templates` — the library an AI Launch Kit site is built from. It exists because a name search fails: a site rebuilt five components AILK already had, because it searched for the names IT would have used and AILK uses different ones — `ContactOverlay`→`FormLightbox`, `SearchOverlay`→`SpotlightPanel`/`NavSearchTrigger`, `SiteRail`→`SidebarNav`, `FunnelNav`→`Nav`, `NumberedWorkList`→`Steps`/`StairSteps`.
|
|
6
6
|
|
|
7
|
-
**What this file does NOT cover.**
|
|
7
|
+
**What this file does NOT cover.** All six component tiers are indexed — Sections, Blocks, Chrome, Primitives, Panels and Shells — so a component absent from these tables is genuinely absent from the library. Outside the file: the **design tokens** (tier 0 — colors, spacing, typography, radius and the rest are values in `@working-theory/theme`, not components; `packages/ui/src/tokens/` holds their Storybook stories and the small display components those stories use); the **page compositions** in `packages/ui/src/pages/` and `packages/templates/src/pages/`, which assemble whole pages from the tiers below; and every non-component module (hooks, `utils/`, `.ts` helpers).
|
|
8
|
+
|
|
9
|
+
**Two things a listing does not promise.** First, the tables index every component file in the six tiers, **including the paid module slices** — the `Booker` family is here, and a build with the scheduling module switched off will not contain it. Listed is not the same as present in your tree; check the modules your site was scaffolded with. Second, this file carries no **props or data shapes**: it says what a component is FOR, never what it accepts. For a section's accepted `data` fields, read its Zod schema, or the `component-catalog.json` manifest the AILK source repo generates alongside this file.
|
|
8
10
|
|
|
9
11
|
**Before you build a component, search this file for what it DOES.**
|
|
10
12
|
|
|
11
13
|
1. Read **Find by capability** below — it maps the words people actually type to the names AILK uses.
|
|
12
14
|
2. If nothing matches, grep the per-tier tables for a verb or noun from your requirement (`grep -i backdrop`, `grep -i "multi-step"`), not for your working name for the component.
|
|
13
|
-
3. Check the
|
|
15
|
+
3. Check the Primitives, Panels and Shells tables too — a low-level control, a collapsible layout container, or a route-level frame lives there, not under Sections or Blocks.
|
|
14
16
|
4. Only then build. If you do build, you are declaring the capability is genuinely absent.
|
|
15
17
|
|
|
16
|
-
Inventory: **
|
|
18
|
+
Inventory: **286 component files** across 6 tiers — 59 sections, 115 blocks, 18 chrome, 79 primitives, 7 panels, 8 shells. 283 distinct names: `SchedulerEmbed`, `Separator`, `Tabs` exist in more than one tier as genuinely different components, listed once per tier with its own source path.
|
|
19
|
+
|
|
20
|
+
Description coverage: **282/286** components carry a capability description derived from source — 41 from the section registry's hand-authored when-to-use text, 204 from the component's own doc-comment header, 37 from its tier barrel's roster line. **4** have none; they are listed under [Undescribed components](#undescribed-components) rather than given a sentence invented from their name.
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
Of those, **252** are *strong* — a capability sentence you could match a requirement against — and **30** are *weak*: either one short clause, or a long one that spends itself on wiring (client boundaries, class names, which primitives it composes) instead of on what the thing is for. Weak rows are marked `(weak)` and listed in full under [Weak descriptions](#weak-descriptions). Coverage is 99%, but **findable-without-luck coverage is 88%**.
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
Per tier, strong out of total: **Sections** 58/59 · **Blocks** 110/115 · **Chrome** 11/18 · **Primitives** 64/79 (4 undescribed) · **Panels** 6/7 · **Shells** 3/8. A tier low on this line is a tier where a capability search is most likely to come up empty on something that exists.
|
|
21
25
|
|
|
22
26
|
That grade is **mechanical**. It counts what it can measure — how much a description adds beyond the component's own name, how much of it is spent on wiring, whether the extraction came out damaged — and it cannot tell a fluent paragraph about the wrong subject from a useful one. A person reading these tables will find more rows unusable than the weak count admits. Treat it as a floor on the problem, not a measurement of it, and read the source before concluding a capability is absent.
|
|
23
27
|
|
|
@@ -34,7 +38,7 @@ The left column is search vocabulary — how a person phrases the need. It is ha
|
|
|
34
38
|
| site rail · vertical nav column · left rail · app sidebar · icon rail · dashboard sidebar | `SidebarNav` (chrome) · `SidebarNavRailItems` (chrome) · `DocsSidebar` (chrome) · `SidePanel` (chrome) | Pick by context: SidebarNav is the DASHBOARD rail (it hardcodes a teams section and a user footer, and is the `sidebar` prop of DashboardShell) — fighting it into a marketing site is the wrong call; DocsSidebar is the DOCS rail (takes a page tree); SidebarNavRailItems is SidebarNav's collapsed icon-rail row. SidePanel is the RIGHT edge, not a left rail. |
|
|
35
39
|
| funnel nav · minimal chrome with one CTA · stripped-down header · landing-page nav · one-action header · sticky CTA | `Nav` (chrome) · `SectionNav` (chrome) · `FloatingCta` (chrome) | There is no separate funnel-nav component, and there does not need to be: this is a CONFIGURATION of Nav — pass it one action and no link list. SectionNav is the in-page section jump nav; FloatingCta is the persistent floating single-action affordance. |
|
|
36
40
|
| numbered work list · ordered steps · process list · how it works · 1-2-3 steps · staircase | `Steps` (blocks) · `StepFlow` (sections) · `StairSteps` (sections) · `FlowStepper` (sections) | For a numbered LIST you want Steps (presentational block) or StairSteps (staggered staircase section). StepFlow and FlowStepper are listed because the phrase collides, but they are the interactive multi-step FORM and its progress indicator — not a work list. |
|
|
37
|
-
| accordion · collapsible · expand/collapse · show more · disclosure | `FaqItem` (blocks) · `FAQ` (sections) · `Objection` (sections) |
|
|
41
|
+
| accordion · collapsible · expand/collapse · show more · disclosure | `Accordion` (primitives) · `Collapsible` (primitives) · `FaqItem` (blocks) · `FAQ` (sections) · `Objection` (sections) | `Accordion` is the standalone primitive (Radix, multi-panel) and `Collapsible` is the single show/hide — reach for those for generic disclosure. FaqItem and the FAQ/Objection sections carry their own expand/collapse and are the right choice for question-and-answer CONTENT, because they also feed the page's JSON-LD. |
|
|
38
42
|
| banner · announcement bar · cookie consent · notification strip | `Banner` (chrome) · `AlertSection` (sections) | Banner is chrome (announcement + consent, with dismiss/consent islands); AlertSection is the in-page dismissible strip. |
|
|
39
43
|
| logo wall · client logos · trusted by · partner marks | `LogoCloud` (sections) · `Awards` (sections) | |
|
|
40
44
|
| pricing table · plan comparison · feature matrix · tier cards | `Pricing` (sections) · `PricingTierCard` (blocks) · `ComparisonMatrix` (blocks) · `ComparisonTable` (sections) · `BillingToggle` (blocks) | |
|
|
@@ -44,12 +48,12 @@ The left column is search vocabulary — how a person phrases the need. It is ha
|
|
|
44
48
|
| email capture · newsletter signup · subscribe box | `Newsletter` (sections) · `NewsletterFormInline` (blocks) · `NewsletterDetail` (blocks) | |
|
|
45
49
|
| video player · embedded video · video modal | `VideoSection` (sections) · `VideoEmbed` (blocks) · `VideoLightbox` (blocks) | |
|
|
46
50
|
| image slider · gallery · carousel · lightbox for images | `Carousel` (sections) · `Gallery` (sections) · `MediaBand` (sections) | |
|
|
47
|
-
| locale switcher · language picker · region selector · view toggle | `LocaleSwitcher` (blocks) · `MarkdownViewToggle` (blocks) | Dark-mode switching is `ThemeToggle`, a PRIMITIVE —
|
|
51
|
+
| locale switcher · language picker · region selector · view toggle | `LocaleSwitcher` (blocks) · `MarkdownViewToggle` (blocks) | Dark-mode switching is `ThemeToggle`, a PRIMITIVE — see the Primitives table below. Import it from `@working-theory/ui/primitives`. |
|
|
48
52
|
| table of contents · on-page nav · jump links · sticky outline | `SectionNav` (chrome) · `DocsTocButton` (blocks) · `DocumentChassis` (sections) | |
|
|
49
53
|
|
|
50
54
|
---
|
|
51
55
|
|
|
52
|
-
## Sections (
|
|
56
|
+
## Sections (59)
|
|
53
57
|
|
|
54
58
|
Page-level content bands. Most are MDX-driven (authored by `type` in page frontmatter and dispatched by `SectionRenderer`); a few are composed directly in a route.
|
|
55
59
|
|
|
@@ -76,6 +80,9 @@ Import: `import { X } from "@working-theory/ui/sections";` (or from the `@workin
|
|
|
76
80
|
| `DecisionSplit` | An honest either-option decision block — use on /vs pages before any comparison. | MDX `type: decision-split` |
|
|
77
81
|
| `Definition` | A single-term definition callout — use for one prominent 'What is X?' answer-first block. | MDX `type: definition` |
|
|
78
82
|
| `DocumentChassis` | A long-read document page (privacy policy, terms, DPA, working agreement) — chrome-free header + optional stat strip + a sticky numbered section nav beside continuous prose; one document per page/route. The authored `sections` list drives both the nav and the body. | MDX `type: document-chassis` |
|
|
83
|
+
| `DocumentViewer` | A paginated document embedded in a page (a report, a client deliverable) — use for a 10-50 page PDF at a closed 16:9 (deck) or letter (portrait) geometry, rendered by a dynamically-imported PDF.js so it never enters the main bundle. `src` accepts a public path or the authenticated `/v1/deliverables/:grantId` route. Not for long-read prose — that is `document-chassis`. | MDX `type: document-viewer` |
|
|
84
|
+
| `DocumentViewerCanvas` | The PDF.js renderer for DocumentViewer. This file is reached ONLY via the dynamic import in DocumentViewerClient.tsx — that is deliberate: the static `import "pdfjs-dist"` below is what lands in this file's own route-split chunk instead of the main bundle (a static import of the renderer is a spec violation, not a style preference). | internal — compose from `packages/ui/src/sections/DocumentViewerCanvas.tsx` |
|
|
85
|
+
| `DocumentViewerClient` | The interactive shell for DocumentViewer. Split out of DocumentViewer.tsx (which stays RSC) for the same reason AlertSection composes AlertSectionDismissIsland: interactivity is contained to one client island. *(weak)* | internal — compose from `packages/ui/src/sections/DocumentViewerClient.tsx` |
|
|
79
86
|
| `FAQ` | Question-and-answer pairs — use to pre-empt buyer objections that are naturally phrased as questions. | MDX `type: faq` · `import { FAQ } from "@working-theory/ui/sections"` |
|
|
80
87
|
| `Feature` | A multi-item benefit/feature highlight grid — use to walk through several product capabilities. | MDX `type: feature` |
|
|
81
88
|
| `FlowStepper` | Rendering a served flow config as a real multi-step form. | `import { FlowStepper } from "@working-theory/ui/sections"` |
|
|
@@ -102,21 +109,21 @@ Import: `import { X } from "@working-theory/ui/sections";` (or from the `@workin
|
|
|
102
109
|
| `SchedulerEmbed` | A declarative third-party booking iframe (e.g. Google Calendar Appointment Schedules) — use for a booking/scheduling moment; sets the provider's cookies on load, so a site classifying it as non-essential may wrap it in a consent gate. | MDX `type: scheduler-embed` · `import { SchedulerEmbed } from "@working-theory/ui/sections"` · `packages/ui/src/sections/SchedulerEmbed.tsx` |
|
|
103
110
|
| `SectionEmpty` | The shared empty-state body every section's `*Empty` variant delegates to. | `import { SectionEmpty } from "@working-theory/ui/sections"` |
|
|
104
111
|
| `SectionRenderer` | Typed dispatch table. Maps a section's `type` discriminant to its React component. | `import { SectionRenderer } from "@working-theory/ui/sections"` |
|
|
105
|
-
| `Separator` | An inter-section spacer — use to add rhythm or a visible rule between two sections that need more separation than default spacing gives. | MDX `type: separator` · `import { Separator } from "@working-theory/ui/sections"` |
|
|
112
|
+
| `Separator` | An inter-section spacer — use to add rhythm or a visible rule between two sections that need more separation than default spacing gives. | MDX `type: separator` · `import { Separator } from "@working-theory/ui/sections"` · `packages/ui/src/sections/Separator.tsx` |
|
|
106
113
|
| `SocialProof` | Tweet/post-shaped social proof items — use for lightweight, screenshot-style endorsements. | MDX `type: social-proof` · `import { SocialProof } from "@working-theory/ui/sections"` |
|
|
107
114
|
| `SplitContentMedia` | Lays out a SectionHeader (text, one side) beside a media slot (the other side) — the HubSpot/wealthsmyth split content+media pattern. | `import { SplitContentMedia } from "@working-theory/ui/sections"` |
|
|
108
115
|
| `SpotlightPanel` | A full-width dimmed/blurred backdrop (abstract pattern or product image) behind a centered elevated card carrying a headline, support text, and a form/flow embed — use for a demo or signup moment that needs focus without leaving the page flow (apollo.io /demo pattern). | MDX `type: spotlight-panel` · `import { SpotlightPanel } from "@working-theory/ui/sections"` |
|
|
109
116
|
| `StairSteps` | A 2-5 step staircase — use for process/journey narratives where direction carries meaning (an ascending 'up-right' staircase for a build-up story, a descending 'down-right' one for the conversionfactory.co 'from idea to impact' pattern). | MDX `type: stair-steps` · `import { StairSteps } from "@working-theory/ui/sections"` |
|
|
110
117
|
| `Stats` | A number-led credibility row — use to show scale or outcome metrics. An optional leadQuote can front the row with an analyst quote (staggered variant mirrors apollo.io's mixed-size evidence band). | MDX `type: stats` |
|
|
111
118
|
| `StepFlow` | A data-driven multi-step lead-capture form (one small field group per step, progress affordance, per-step advance) — use for a longer qualifying gate where a single-step ContactForm would feel too long; fires onStepComplete after each step so an abandoned flow still captures a partial lead. | MDX `type: step-flow` · `import { StepFlow } from "@working-theory/ui/sections"` |
|
|
112
|
-
| `Tabs` | Tabbed content panels — use to let a reader choose between parallel content without scrolling. | MDX `type: tabs` · `import { Tabs } from "@working-theory/ui/sections"` |
|
|
119
|
+
| `Tabs` | Tabbed content panels — use to let a reader choose between parallel content without scrolling. | MDX `type: tabs` · `import { Tabs } from "@working-theory/ui/sections"` · `packages/ui/src/sections/Tabs.tsx` |
|
|
113
120
|
| `Team` | A team member grid — use on About pages to introduce the people behind the product. | MDX `type: team` · `import { Team } from "@working-theory/ui/sections"` |
|
|
114
121
|
| `Testimonials` | Direct customer quotes — use for first-person social proof with attribution. | MDX `type: testimonials` |
|
|
115
122
|
| `VideoSection` | The standard large-centered-video section (acquisition.com/workshop pattern) — optional headline/intro above a bounded-width centered video, optional caption/CTA below; renders a labeled placeholder until a real source is supplied. | MDX `type: video-section` · `import { VideoSection } from "@working-theory/ui/sections"` |
|
|
116
123
|
|
|
117
124
|
---
|
|
118
125
|
|
|
119
|
-
## Blocks (
|
|
126
|
+
## Blocks (115)
|
|
120
127
|
|
|
121
128
|
Intermediate composition tiles — the pieces sections are built from. Compose primitives and panels; never import a section.
|
|
122
129
|
|
|
@@ -150,6 +157,8 @@ Import: `import { X } from "@working-theory/ui/blocks";` (or from the `@working-
|
|
|
150
157
|
| `CodeBlock` | Read-only code display with syntax highlighting. Modeled on the Claude docs code-block pattern. | `import { CodeBlock } from "@working-theory/ui/blocks"` |
|
|
151
158
|
| `ComparisonMatrix` | Full feature × tier comparison matrix for the Pricing 'with-comparison-table' variant. Renders N collapsible ComparisonGroups, each containing M feature rows with per-tier values. | `import { ComparisonMatrix } from "@working-theory/ui/blocks"` |
|
|
152
159
|
| `Composer` | The chat input, per the ploy.ai capture contract. | `import { Composer } from "@working-theory/ui/blocks"` |
|
|
160
|
+
| `ConsentGroup` | The composite control for the `consent` field kind: one real checkbox per consent purpose, each with its statement and inline policy links, inside one fieldset. | `import { ConsentGroup } from "@working-theory/ui/blocks"` |
|
|
161
|
+
| `ConsentStatement` | The sentence a person agrees to, with its policy links inline. | `import { ConsentStatement } from "@working-theory/ui/blocks"` |
|
|
153
162
|
| `ContactChannelItem` | Renders one support channel entry: colored icon square + headline + description paragraph + CTA link (with trailing arrow icon). | `import { ContactChannelItem } from "@working-theory/ui/blocks"` |
|
|
154
163
|
| `ContactFormFields` | Renders the form field grid (Input / Textarea / Select primitives) + submit Button + optional consent text footer. | `import { ContactFormFields } from "@working-theory/ui/blocks"` |
|
|
155
164
|
| `ContactInfoAside` | For ContactForm 'split-with-pattern' variant. Renders address / phone / email contact info rows. Each row: sr-only <dt> label + visible <dd> with Icon + Text. Phone and email render as tel:/mailto: links (click-to-call / click-to-email). | `import { ContactInfoAside } from "@working-theory/ui/blocks"` |
|
|
@@ -269,12 +278,140 @@ Import: `import { X } from "@working-theory/ui/chrome";` (or from the `@working-
|
|
|
269
278
|
|
|
270
279
|
---
|
|
271
280
|
|
|
281
|
+
## Primitives (79)
|
|
282
|
+
|
|
283
|
+
The base control and text vocabulary — Button, Heading, Text, Link, Icon, Input, Dialog, Command, Tooltip, ThemeToggle and the rest. This is the only tier allowed to render raw HTML elements; every tier above it composes these instead. Search here before building any low-level control.
|
|
284
|
+
|
|
285
|
+
Import: `import { X } from "@working-theory/ui/primitives";` (or from the `@working-theory/ui` root barrel). Components marked *internal* are not re-exported — they are implementation details of a sibling in the same tier.
|
|
286
|
+
|
|
287
|
+
| Component | What it does | How to use it |
|
|
288
|
+
| --- | --- | --- |
|
|
289
|
+
| `Accordion` | Collapsible panel set built on @radix-ui/react-accordion. | `import { Accordion } from "@working-theory/ui/primitives"` |
|
|
290
|
+
| `Alert` | Contextual status message for user feedback. Supports four semantic variants (default, error, warning, success, info) that map to AILK Brand 1.3 status tokens. | `import { Alert } from "@working-theory/ui/primitives"` |
|
|
291
|
+
| `AlertBanner` | Full-width status or promotional banner strip. Renders a horizontally-centered, full-width bar for site-level notices: informational, success, warning, error, and promotional messages. | `import { AlertBanner } from "@working-theory/ui/primitives"` |
|
|
292
|
+
| `AlertDialog` | Confirmation overlay composed from @radix-ui/react-alert-dialog. Unlike Dialog, AlertDialog traps focus and requires the user to explicitly confirm or cancel before dismissing — appropriate for destructive actions. | `import { AlertDialog } from "@working-theory/ui/primitives"` |
|
|
293
|
+
| `AlertDot` | Colored status dot with optional notification count. Use on integration cards, avatars, or any icon needing inline status indication. Pass `count` to render a capped badge (e.g. "99+") instead of a plain dot. Announces status to assistive technology via role="status" and a caller-supplied aria-label (required by accessibility contract). | `import { AlertDot } from "@working-theory/ui/primitives"` |
|
|
294
|
+
| `AspectRatio` | Constrains content to a given width/height ratio. Thin re-export of @radix-ui/react-aspect-ratio. RSC-safe: no hooks or browser APIs — default server component. *(weak)* | `import { AspectRatio } from "@working-theory/ui/primitives"` |
|
|
295
|
+
| `Avatar` | Circular or square user/company avatar with image, initials, or icon fallback. | `import { Avatar } from "@working-theory/ui/primitives"` |
|
|
296
|
+
| `Badge` | Inline label chip with semantic status variants and size scale. | `import { Badge } from "@working-theory/ui/primitives"` |
|
|
297
|
+
| `Breadcrumb` | Navigation primitive that renders an ordered wayfinding trail with accessible current-page marking and logical-direction separators. | `import { Breadcrumb } from "@working-theory/ui/primitives"` |
|
|
298
|
+
| `Button` | `<button>` (or any element via `asChild`) with cva variant + size styling via @working-theory/theme tokens. | `import { Button } from "@working-theory/ui/primitives"` |
|
|
299
|
+
| `Calendar` | Date picker built on react-day-picker with AILK semantic tokens. | `import { Calendar } from "@working-theory/ui/primitives"` |
|
|
300
|
+
| `Checkbox` | Accessible checkbox control backed by @radix-ui/react-checkbox. Renders a 16×16 checkbox with a Check icon when checked. Supports disabled state, custom className, and all Radix Checkbox.Root props. | `import { Checkbox } from "@working-theory/ui/primitives"` |
|
|
301
|
+
| `ChipInput` | Row of dismissible chips with an optional add button. | `import { ChipInput } from "@working-theory/ui/primitives"` |
|
|
302
|
+
| `CitationMarker` | Inline citation/source marker for agent-generated content. Renders a compact numbered or labeled source reference inline with text. Used alongside AI-generated content to surface provenance for individual claims. | `import { CitationMarker } from "@working-theory/ui/primitives"` |
|
|
303
|
+
| `Code` | Code inline primitive — renders a semantic <code> for code/variable spans inside prose. Inline sibling of Text. | `import { Code } from "@working-theory/ui/primitives"` |
|
|
304
|
+
| `Collapsible` | Thin re-export of the Radix Collapsible root and content parts, plus the styled CollapsibleTrigger button. | `import { Collapsible } from "@working-theory/ui/primitives"` |
|
|
305
|
+
| `Command` | Keyboard-navigable command palette / search input. Thin wrapper over the `cmdk` library (Command component) with AILK semantic token styling. Provides the full sub-component set: Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut. | `import { Command } from "@working-theory/ui/primitives"` |
|
|
306
|
+
| `ConfidenceIndicator` | Accessible confidence-level badge for AI-generated claims. Bound to the `@working-theory/validation` confidence shape: confidence_level = "low" \| "medium" \| "high" This matches the `overallConfidence` enum in market-landscape-summary and canonical-messaging-summary schemas, and the free-text `confidence_level` on HypothesisClaim. | `import { ConfidenceIndicator } from "@working-theory/ui/primitives"` |
|
|
307
|
+
| `Container` | _no description in source — read `packages/ui/src/primitives/Container.tsx`_ | `import { Container } from "@working-theory/ui/primitives"` |
|
|
308
|
+
| `ContextMenu` | Right-click / long-press contextual action menu. Thin wrapper over @radix-ui/react-context-menu with AILK semantic token styling. Provides the full Radix sub-component set: Root, Trigger, Portal, Content, Group, Label, Item, CheckboxItem, RadioGroup, RadioItem, ItemIndicator, Separator, Sub, SubTrigger, SubContent, Shortcut. | `import { ContextMenu } from "@working-theory/ui/primitives"` |
|
|
309
|
+
| `CopyButton` | CopyButton Primitive. *(weak)* | `import { CopyButton } from "@working-theory/ui/primitives"` |
|
|
310
|
+
| `Delta` | Sign-driven semantic indicator for numeric change. *(weak)* | `import { Delta } from "@working-theory/ui/primitives"` |
|
|
311
|
+
| `Dialog` | Modal overlay composed from @radix-ui/react-dialog. *(weak)* | `import { Dialog } from "@working-theory/ui/primitives"` |
|
|
312
|
+
| `DropdownMenu` | Contextual action menu anchored to a trigger. Thin wrapper over @radix-ui/react-dropdown-menu with AILK semantic token styling. Provides the full Radix sub-component set: Root, Trigger, Portal, Content, Group, Label, Item, CheckboxItem, RadioGroup, RadioItem, ItemIndicator, Separator, Sub, SubTrigger, SubContent, Shortcut. | `import { DropdownMenu } from "@working-theory/ui/primitives"` |
|
|
313
|
+
| `EmptyState` | Purposeful empty / zero-item state indicator. Distinct from loading (`Skeleton`, `SectionSkeleton`) and error (`SectionErrorBoundary`) states. Use `EmptyState` when content is absent by design (no items yet, no search results, no activity), not when content is loading or a render error occurred. | `import { EmptyState } from "@working-theory/ui/primitives"` |
|
|
314
|
+
| `Field` | Composes Label + a control slot + helper/error text. | `import { Field } from "@working-theory/ui/primitives"` |
|
|
315
|
+
| `Form` | `preventDefault` + native Validity State + ARIA wiring. | `import { Form } from "@working-theory/ui/primitives"` |
|
|
316
|
+
| `GradientText` | Mechanism (pure CSS, no client JS): the `.gt-text` utility in `@working-theory/theme`'s tokens.css sets `background-image: var(gradient-brand)` plus `background-clip: text` + transparent fill, so the gradient shows through the glyphs. That is the SAME technique `ShimmerText` uses via `.st-text`, minus the sweep: no `background-size` stretch, no `@keyframes`, no animate companion class. | `import { GradientText } from "@working-theory/ui/primitives"` |
|
|
317
|
+
| `Heading` | _no description in source — read `packages/ui/src/primitives/Heading.tsx`_ | `import { Heading } from "@working-theory/ui/primitives"` |
|
|
318
|
+
| `HoverCard` | Floating card revealed on hover, built on @radix-ui/react-hover-card. Exports Root, Trigger, and Content. The trigger is typically an anchor or interactive element; the content floats alongside it on pointer hover/focus. | `import { HoverCard } from "@working-theory/ui/primitives"` |
|
|
319
|
+
| `Icon` | Single rendering path for Lucide UI icons and brand/channel logos (Simple Icons raw paths). | `import { Icon } from "@working-theory/ui/primitives"` |
|
|
320
|
+
| `Image` | Wraps `next/image` and closes foot-guns at the type level. | `import { Image } from "@working-theory/ui/primitives"` |
|
|
321
|
+
| `InlineMessage` | Quiet helper/error/warning text for forms. | `import { InlineMessage } from "@working-theory/ui/primitives"` |
|
|
322
|
+
| `Input` | Single-line text input with variant styling. Supports default, warning, and error validation states, three size variants, and optional leading/trailing icon slots. | `import { Input } from "@working-theory/ui/primitives"` |
|
|
323
|
+
| `Label` | Form field label with peer-disabled state styling. Wraps @radix-ui/react-label for correct association with form controls via `htmlFor`. Automatically dims and shows a not-allowed cursor when the associated control carries the `disabled` attribute (peer-disabled). | `import { Label } from "@working-theory/ui/primitives"` |
|
|
324
|
+
| `Link` | _no description in source — read `packages/ui/src/primitives/Link.tsx`_ | `import { Link } from "@working-theory/ui/primitives"` |
|
|
325
|
+
| `LoaderRing` | Compact loading-animation indicator. Renders the three loading animations (spinner, dots, check-transition) and, for terminal status, composes the shared StatusBadge primitive (success/error/warning). Sizes track the AILK icon-size token scale; all colors are AILK Brand 1.3 semantic tokens. | `import { LoaderRing } from "@working-theory/ui/primitives"` |
|
|
326
|
+
| `Menubar` | Horizontal application menu bar with keyboard navigation. | `import { Menubar } from "@working-theory/ui/primitives"` |
|
|
327
|
+
| `MenuItem` | Interactive menu item for dropdowns, context menus, etc. Full-width, left-aligned button with support for left/right icons, secondary text, selection state, and destructive variant. | `import { MenuItem } from "@working-theory/ui/primitives"` |
|
|
328
|
+
| `MoneyAmount` | Locale-aware currency display. *(weak)* | `import { MoneyAmount } from "@working-theory/ui/primitives"` |
|
|
329
|
+
| `NavigationMenu` | Accessible site navigation with flyout content. Thin wrapper over @radix-ui/react-navigation-menu with AILK semantic token styling. Provides the full Radix sub-component set: Root, List, Item, Trigger, Content, Link, Viewport, Indicator. | `import { NavigationMenu } from "@working-theory/ui/primitives"` |
|
|
330
|
+
| `Pagination` | • Link mode (default, RSC-safe) — prev/next render as `<a>` links built from `baseUrl` (`?page=N`); the inactive boundary control is a disabled `<span>`. This is the original behaviour and is unchanged. | `import { Pagination } from "@working-theory/ui/primitives"` |
|
|
331
|
+
| `PanelEdgeHandle` | Presentational primitive (Primitives tier, Tier 1). A full-height vertical edge handle with a ≥44px touch target (min-w-11). Used by tier-2 panels as the interactive edge handle — FixedPanel (collapse/expand) and ResizablePanel (drag-resize). | `import { PanelEdgeHandle } from "@working-theory/ui/primitives"` |
|
|
332
|
+
| `Popover` | Floating content panel anchored to a trigger. Thin wrapper over @radix-ui/react-popover with AILK semantic token styling. Provides: Popover (root), PopoverTrigger, PopoverAnchor, PopoverContent, PopoverClose — the full Radix sub-component set. | `import { Popover } from "@working-theory/ui/primitives"` |
|
|
333
|
+
| `Progress` | Wraps @radix-ui/react-progress with AILK token-driven styling. Supports three size variants (sm, md, lg) and two track colors (default, secondary). The indicator fill switches to the success emphasis token when `isComplete` is true. | `import { Progress } from "@working-theory/ui/primitives"` |
|
|
334
|
+
| `ProgressRing` | Circular SVG progress indicator. Renders a ring (stroke arc) or pie (filled wedge) progress meter, plus success/error/warning filled-ring status states that mirror LoaderRing's status variants for consistent visual language. | `import { ProgressRing } from "@working-theory/ui/primitives"` |
|
|
335
|
+
| `ProvenanceBadge` | Agent/human/system authorship chip with optional audit id. | `import { ProvenanceBadge } from "@working-theory/ui/primitives"` |
|
|
336
|
+
| `RadioGroup` | Accessible radio button group backed by @radix-ui/react-radio-group. Exports RadioGroup (Root) and RadioGroupItem. The Root renders as a grid with gap-2 by default; items are 16×16 px filled circles. | `import { RadioGroup } from "@working-theory/ui/primitives"` |
|
|
337
|
+
| `Rating` | Renders star icons for a 0–5 numeric rating, with full and half-star support and an accessible aria-label. | `import { Rating } from "@working-theory/ui/primitives"` |
|
|
338
|
+
| `ScrollArea` | Custom-styled scroll container built on @radix-ui/react-scroll-area. Exposes ScrollArea (Root + Viewport + Corner composite) and ScrollBar as separately composable sub-components. | `import { ScrollArea } from "@working-theory/ui/primitives"` |
|
|
339
|
+
| `SearchInputTrigger` | It is NOT search-or hero-specific: every visual axis (height, width, corner radius, background, border, placeholder, shortcut hint) is a token-driven prop so the same control can be restyled per placement. It does not own a real <input>; clicking it (or pressing the hinted shortcut) fires `onClick`, which the caller wires to open a Command palette. | `import { SearchInputTrigger } from "@working-theory/ui/primitives"` |
|
|
340
|
+
| `SectionErrorBoundary` | Wraps any section in a render-error containment layer. When a child throws during render, the boundary catches the error, logs it, and renders `<SectionSkeleton>` as the fallback. | `import { SectionErrorBoundary } from "@working-theory/ui/primitives"` |
|
|
341
|
+
| `SectionSkeleton` | Minimal animated placeholder block. Used as the default fallback by SectionErrorBoundary and as a loading skeleton in suspense-enabled section consumers. Renders a single animated rectangle respecting an optional aspect-ratio and className. | `import { SectionSkeleton } from "@working-theory/ui/primitives"` |
|
|
342
|
+
| `SegmentedControl` | A compact single-select pill group with radiogroup semantics. | `import { SegmentedControl } from "@working-theory/ui/primitives"` |
|
|
343
|
+
| `SegmentedProgress` | Discrete N-segment progress indicator. Renders `max` equal-width rounded bars in a row; the first `value` segments render filled (brand fill token), the remainder render as unfilled track segments. Distinct from the continuous `Progress` primitive (a single sliding-fill track) — use SegmentedProgress for step/checklist-style progress such as an onboarding checklist or a multi-step wizard. | `import { SegmentedProgress } from "@working-theory/ui/primitives"` |
|
|
344
|
+
| `Select` | Accessible dropdown select backed by @radix-ui/react-select. Exports the full Radix sub-component set: Select (Root), SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator. | `import { Select } from "@working-theory/ui/primitives"` |
|
|
345
|
+
| `Separator` | Thin divider line between content regions. | `import { Separator } from "@working-theory/ui/primitives"` · `packages/ui/src/primitives/Separator.tsx` |
|
|
346
|
+
| `Sheet` | Slide-out panel anchored to any viewport edge. | `import { Sheet } from "@working-theory/ui/primitives"` |
|
|
347
|
+
| `ShimmerText` | Mechanism (pure CSS, no client JS). All configurable values flow as CSS custom properties via the style prop so they are tunable at call-site without arbitrary Tailwind values. | `import { ShimmerText } from "@working-theory/ui/primitives"` |
|
|
348
|
+
| `ShortcutTrigger` | Button-family primitive: a compact icon trigger with an optional keyboard-shortcut hint (e.g. ⌘K). | `import { ShortcutTrigger } from "@working-theory/ui/primitives"` |
|
|
349
|
+
| `Skeleton` | Animated placeholder shown while content is loading. | `import { Skeleton } from "@working-theory/ui/primitives"` |
|
|
350
|
+
| `Slider` | Range input built on @radix-ui/react-slider. Exposes the full Radix sub-component set (Root, Track, Range, Thumb) for composition, and provides a pre-composed <Slider> default. | `import { Slider } from "@working-theory/ui/primitives"` |
|
|
351
|
+
| `SplitButton` | A main action button paired with a dropdown trigger. *(weak)* | `import { SplitButton } from "@working-theory/ui/primitives"` |
|
|
352
|
+
| `StatusBadge` | Colored circle + glyph status indicator. *(weak)* | `import { StatusBadge } from "@working-theory/ui/primitives"` |
|
|
353
|
+
| `Surface` | Establishes a color-token context for its subtree. The `emphasis` variant marks the wrapper with `data-surface="emphasis"`, which remaps the theme-flipping semantic color tokens to their dark-palette values within the subtree (see the [data-surface="emphasis"] rule in @working-theory/theme/tokens.css). | `import { Surface } from "@working-theory/ui/primitives"` |
|
|
354
|
+
| `Switch` | A toggleable on/off control built on @radix-ui/react-switch. | `import { Switch } from "@working-theory/ui/primitives"` |
|
|
355
|
+
| `Table` | Semantic HTML table with token-driven styling. Exposes Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, and TableCaption as composable sub-components. | `import { Table } from "@working-theory/ui/primitives"` |
|
|
356
|
+
| `Tabs` | Radix-backed tablist/tab/tabpanel with optional per-tab count badges and an optional "More ▾" overflow menu. | `import { Tabs } from "@working-theory/ui/primitives"` · `packages/ui/src/primitives/Tabs.tsx` |
|
|
357
|
+
| `Text` | _no description in source — read `packages/ui/src/primitives/Text.tsx`_ | `import { Text } from "@working-theory/ui/primitives"` |
|
|
358
|
+
| `Textarea` | Multi-line text input with variant styling. Supports default, warning, and error validation states and three size variants. Compose with <Label> and <Form> for accessible form fields. | `import { Textarea } from "@working-theory/ui/primitives"` |
|
|
359
|
+
| `ThemeToggle` | Stateful 3-state theme owner. *(weak)* | `import { ThemeToggle } from "@working-theory/ui/primitives"` |
|
|
360
|
+
| `ThemeToggleView` | 3-state icon segmented control. A presentational, controlled component. It renders what `value` says and calls `onChange` when the user picks a different mode. All theme persistence (cookies, DOM attribute writes) is the responsibility of the stateful owner {@link ThemeToggle}. | internal — compose from `packages/ui/src/primitives/ThemeToggleView.tsx` |
|
|
361
|
+
| `TimePicker` | Time-of-day selector with 12h/24h formats. A dropdown of time slots (48 per day at the default 30-minute step), NOT an analog clock face. Composes the Select primitive — the generated slots render as Select options, inheriting Select's combobox/listbox a11y, keyboard, type-ahead, and styling (incl. the corner-radius fix). | `import { TimePicker } from "@working-theory/ui/primitives"` |
|
|
362
|
+
| `Toast` | Radix-backed transient notification system. *(weak)* | `import { Toast } from "@working-theory/ui/primitives"` |
|
|
363
|
+
| `Toaster` | Renders the toast viewport and maps queued toasts from `useToast` into individual `<Toast>` instances. | `import { Toaster } from "@working-theory/ui/primitives"` |
|
|
364
|
+
| `Toggle` | Toggle Primitive. *(weak)* | `import { Toggle } from "@working-theory/ui/primitives"` |
|
|
365
|
+
| `Tooltip` | Radix-backed floating label anchored to a trigger element. | `import { Tooltip } from "@working-theory/ui/primitives"` |
|
|
366
|
+
| `VisuallyHidden` | Renders its children so they are present in the DOM and the accessibility tree but visually hidden. Standardizes the ad-hoc `sr-only` className pattern previously hand-rolled across primitives (Dialog/Sheet/Toast close labels) and section headers. *(weak)* | `import { VisuallyHidden } from "@working-theory/ui/primitives"` |
|
|
367
|
+
| `WorkingIndicator` | Renders the authentic Claude Code "working" indicator: a glyph that blooms frame-by-frame from a middle dot through increasingly complex Unicode star shapes to a full-star, then resets. Beside it sits a steady-colored label ("Thinking…" by default). | `import { WorkingIndicator } from "@working-theory/ui/primitives"` |
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## Panels (7)
|
|
372
|
+
|
|
373
|
+
Reusable layout containers that own their own interaction state (collapse, rail, drag-to-resize, off-canvas drawer below `lg`). Not page shells — composable containers that sit between primitives and blocks.
|
|
374
|
+
|
|
375
|
+
Import: `import { X } from "@working-theory/ui/panels";` (or from the `@working-theory/ui` root barrel). Components marked *internal* are not re-exported — they are implementation details of a sibling in the same tier.
|
|
376
|
+
|
|
377
|
+
| Component | What it does | How to use it |
|
|
378
|
+
| --- | --- | --- |
|
|
379
|
+
| `CardGrid` | The shared owner of how card-grid cells are arranged and separated — columns, gap, and the inter-cell SEPARATION treatment. Seven sections (BentoGrid, Items, Pricing, SocialProof, Stats, Testimonials, Team) currently hand-roll `grid gap-grid grid-cols-*`; this panel is the foundation they compose instead, the direct analogue of how `SectionFrame` collapsed 23× frame duplication. | `import { CardGrid } from "@working-theory/ui/panels"` |
|
|
380
|
+
| `FixedPanel` | Collapsible layout-container primitive (Tier 2 — Panels). A three-state panel: expanded ↔ rail ↔ hidden. Controlled only — callers manage state via `state` + `onStateChange`. | `import { FixedPanel } from "@working-theory/ui/panels"` |
|
|
381
|
+
| `FlowFrame` | The // frame: a full-viewport ground on the site `bg` token, two 50/50 regions (a persistent side panel + an active region) that stack below `md:` (side panel first, in DOM and visual order), and a bottom bar pinned to the VISIBLE viewport (`position: fixed`, safe-area aware) carrying a single continuous accent progress line, `leading` / `label` (center) / `trailing` slots, and a prop-controlled "Powered by Working Theory" line. *(weak)* | `import { FlowFrame } from "@working-theory/ui/panels"` |
|
|
382
|
+
| `InvoiceDetail` | A single invoice's detail view, for the invoice surface (U4). Capability-bearing: binds a schema.org `Invoice` resource-payload fragment (imported from `@working-theory/schema`) — so a co-located `.text.ts` + `.text.test.ts` renderer is required and gated by `scripts/check-ax-parity.sh`. | `import { InvoiceDetail } from "@working-theory/ui/panels"` |
|
|
383
|
+
| `ResizablePanel` | Drag-resizable layout-container primitive (Panels tier, Tier 2). Provides a resizable side panel container for layout composition. The panel width is controlled by the parent via `width` + `onWidthChange`/`onWidthChangeEnd`. The panel itself manages the drag interaction; the parent persists the committed width (e.g. via localStorage or server state). | `import { ResizablePanel } from "@working-theory/ui/panels"` |
|
|
384
|
+
| `SectionFrame` | The shared frame the section tier composes instead of hand-rolling the `SectionErrorBoundary` + `<section className="py-section bg-bg">` + `Container` plumbing (23× duplicated at time). | `import { SectionFrame } from "@working-theory/ui/panels"` |
|
|
385
|
+
| `StickyColumn` | Makes one column of a two-column layout stick (`lg:sticky` with a top offset) while the sibling column scrolls — the HubSpot "left header sticks, right content scrolls" pattern. `lg`-only: below `lg` it is NOT sticky (normal flow, stacks). Consumed by SplitContentMedia; reusable by any two-column layout. | `import { StickyColumn } from "@working-theory/ui/panels"` |
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Shells (8)
|
|
390
|
+
|
|
391
|
+
Route-level slot-frames — the outermost layout a page is placed into. They supply geometry and slots (nav / sidebar / main / footer), not content: you inject the real Nav, Footer and sidebar. A different package from every tier above: `@working-theory/templates`.
|
|
392
|
+
|
|
393
|
+
Import: `import { X } from "@working-theory/templates/shells";` (or from the `@working-theory/templates` root barrel). Components marked *internal* are not re-exported — they are implementation details of a sibling in the same tier.
|
|
394
|
+
|
|
395
|
+
| Component | What it does | How to use it |
|
|
396
|
+
| --- | --- | --- |
|
|
397
|
+
| `AdminShell` | @deprecated; use PortalShell with your own navItems. Internal admin dashboard layout shell. Thin composition of AppShell + SidebarNav. Converged from the hand-rolled layout in the prior MVP to match the AppShell pattern established by WorkspaceShell. | `import { AdminShell } from "@working-theory/templates/shells"` |
|
|
398
|
+
| `AppShell` | Shared authed-app base frame. Layout ownership: AppShell is the SINGLE owner of the authed sidebar frame layout. The `sidebar` prop is CONTENT (e.g. a <SidebarNav>), never a layout component. Do NOT pass SidebarShell or FixedPanel as the sidebar — that nests two incompatible layout systems (a fixed-width shell vs a variable-width panel). | `import { AppShell } from "@working-theory/templates/shells"` |
|
|
399
|
+
| `ArtifactEditorShell` | Chat + artifact-canvas split-view slot-frame. Recomposes the ploy.ai Ploy Editor capture: a chat-driven artifact editor whose split view is LEFT = chat pane (conversation + composer) and RIGHT = artifact canvas (toolbar + preview/code), behind a drag-resizable divider. A blank session is chat-only, full width, until an artifact exists — then the canvas panel slides in. | `import { ArtifactEditorShell } from "@working-theory/templates/shells"` |
|
|
400
|
+
| `BlogShell` | Blog reading **slot-frame** (DOCS-UI-8). Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* and *where content goes*, owning **geometry only**. Chrome (Nav/Footer) and content (the post meta rail + the reconciled BlogPost body) **fill** the slots — nothing is baked in. Peer to MarketingShell / DocsShell; see. *(weak)* | `import { BlogShell } from "@working-theory/templates/shells"` |
|
|
401
|
+
| `DocsShell` | Documentation reading **slot-frame** (DOCS-UI-4). Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* and *where content goes*, owning **geometry only**. Chrome (DocsSidebar) and content (DocsArticleHeader + MDXContent + ArticlePager + DocsFeedback) **fill** the slots — nothing is baked in. Peer to MarketingShell; see. *(weak)* | `import { DocsShell } from "@working-theory/templates/shells"` |
|
|
402
|
+
| `MarketingShell` | Public-facing marketing site **slot-frame**. Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* (top + bottom) and *where sections go* (the body), owning **geometry only**. Chrome (Nav/Footer) and sections **fill** the slots — nothing is baked into the component. See (first instance). *(weak)* | `import { MarketingShell } from "@working-theory/templates/shells"` |
|
|
403
|
+
| `PortalShell` | Customer-facing portal (sidebar + branded top chrome + main);. Thin composition of AppShell + SidebarNav. Converged from the hand-rolled layout in the prior MVP to match the AppShell pattern established by WorkspaceShell. *(weak)* | `import { PortalShell } from "@working-theory/templates/shells"` |
|
|
404
|
+
| `WorkspaceShell` | Application sidebar shell (thin AppShell composition);. Props are intentionally identical to the old DashboardShellProps — no additions beyond what AppShell provides — so any fork using DashboardShell can swap the import without changes. *(weak)* | `import { WorkspaceShell } from "@working-theory/templates/shells"` |
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
272
408
|
## Weak descriptions
|
|
273
409
|
|
|
274
|
-
These
|
|
410
|
+
These 30 components have a description that is accurate but does not do the job well: too short to match against, or long but spent on implementation. A capability search reaches them only if the searcher's word happens to be in it, so they are the most likely place for this catalog to repeat the failure it was built to fix. Read the source before concluding the capability is absent — and if you own one of these components, its header is the fix.
|
|
275
411
|
|
|
276
412
|
| Component | Tier | What the source gives us |
|
|
277
413
|
| --- | --- | --- |
|
|
414
|
+
| `DocumentViewerClient` | sections | The interactive shell for DocumentViewer. Split out of DocumentViewer.tsx (which stays RSC) for the same reason AlertSection composes AlertSectionDismissIsland: interactivity is contained to one client island. |
|
|
278
415
|
| `AgentContextCard` | blocks | Capability-bearing block that renders agent provenance. RSC note: no hooks or browser APIs — server-renderable by default. |
|
|
279
416
|
| `PageHeader` | blocks | RSC. Page-level header composing the Breadcrumb primitive for the left-side wayfinding trail, a generic right-side `actions` slot, and an optional `switcher` slot for header-owned segment switching. Fills AppShell's `header` slot (DashboardShell and similar). No accent bar. No tab API. No named action props — the caller assembles whatever button/menu nodes it needs and passes them as `actions`. |
|
|
280
417
|
| `PricingTierCardSeatControl` | blocks | Seat-count range picker for the Team tier card. Renders a Select primitive that lets the user choose an "Up to N seats" option from a caller-supplied list of numbers. The parent PricingTierCard stays a pure RSC; only this tiny island is hydrated. Pattern mirrors PageHeaderSwitcher.tsx: small "use client" island imported by an otherwise-server-rendered parent, keeping the client bundle minimal. |
|
|
@@ -287,9 +424,33 @@ These 12 components have a description that is accurate but does not do the job
|
|
|
287
424
|
| `NavMobileMenu` | chrome | Client subcomponent for mobile hamburger state. Isolates "use client" to this narrow component so Nav (Server Component) stays clean. Renders a hamburger button + collapsible link list. Closes the menu automatically when the pathname changes (route navigation). |
|
|
288
425
|
| `SidebarNav` | chrome | Application sidebar rail (nav + teams + user) for dashboard shells. Server Component (RSC). Renders the vertical sidebar rail for application-shell layouts. Used as the `sidebar` prop of DashboardShell. Wrap in a FixedPanel (panels tier) to get the expanded ↔ rail ↔ hidden state machinery. Independently reusable in future shells (settings, analytics, etc.). |
|
|
289
426
|
| `SidebarNavRailItems` | chrome | Client boundary for the collapsed rail tooltip affordance. Isolated "use client" boundary so SidebarNav itself stays a Server Component. Renders icon-only nav links with Tooltip labels when the rail is collapsed. |
|
|
427
|
+
| `AspectRatio` | primitives | Constrains content to a given width/height ratio. Thin re-export of @radix-ui/react-aspect-ratio. RSC-safe: no hooks or browser APIs — default server component. |
|
|
428
|
+
| `CopyButton` | primitives | CopyButton Primitive. |
|
|
429
|
+
| `Delta` | primitives | Sign-driven semantic indicator for numeric change. |
|
|
430
|
+
| `Dialog` | primitives | Modal overlay composed from @radix-ui/react-dialog. |
|
|
431
|
+
| `MoneyAmount` | primitives | Locale-aware currency display. |
|
|
432
|
+
| `SplitButton` | primitives | A main action button paired with a dropdown trigger. |
|
|
433
|
+
| `StatusBadge` | primitives | Colored circle + glyph status indicator. |
|
|
434
|
+
| `ThemeToggle` | primitives | Stateful 3-state theme owner. |
|
|
435
|
+
| `Toast` | primitives | Radix-backed transient notification system. |
|
|
436
|
+
| `Toggle` | primitives | Toggle Primitive. |
|
|
437
|
+
| `VisuallyHidden` | primitives | Renders its children so they are present in the DOM and the accessibility tree but visually hidden. Standardizes the ad-hoc `sr-only` className pattern previously hand-rolled across primitives (Dialog/Sheet/Toast close labels) and section headers. |
|
|
438
|
+
| `FlowFrame` | panels | The // frame: a full-viewport ground on the site `bg` token, two 50/50 regions (a persistent side panel + an active region) that stack below `md:` (side panel first, in DOM and visual order), and a bottom bar pinned to the VISIBLE viewport (`position: fixed`, safe-area aware) carrying a single continuous accent progress line, `leading` / `label` (center) / `trailing` slots, and a prop-controlled "Powered by Working Theory" line. |
|
|
439
|
+
| `BlogShell` | shells | Blog reading **slot-frame** (DOCS-UI-8). Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* and *where content goes*, owning **geometry only**. Chrome (Nav/Footer) and content (the post meta rail + the reconciled BlogPost body) **fill** the slots — nothing is baked in. Peer to MarketingShell / DocsShell; see. |
|
|
440
|
+
| `DocsShell` | shells | Documentation reading **slot-frame** (DOCS-UI-4). Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* and *where content goes*, owning **geometry only**. Chrome (DocsSidebar) and content (DocsArticleHeader + MDXContent + ArticlePager + DocsFeedback) **fill** the slots — nothing is baked in. Peer to MarketingShell; see. |
|
|
441
|
+
| `MarketingShell` | shells | Public-facing marketing site **slot-frame**. Server Component (RSC default). A shell is a slot-defining frame: it carves out *where chrome goes* (top + bottom) and *where sections go* (the body), owning **geometry only**. Chrome (Nav/Footer) and sections **fill** the slots — nothing is baked into the component. See (first instance). |
|
|
442
|
+
| `PortalShell` | shells | Customer-facing portal (sidebar + branded top chrome + main);. Thin composition of AppShell + SidebarNav. Converged from the hand-rolled layout in the prior MVP to match the AppShell pattern established by WorkspaceShell. |
|
|
443
|
+
| `WorkspaceShell` | shells | Application sidebar shell (thin AppShell composition);. Props are intentionally identical to the old DashboardShellProps — no additions beyond what AppShell provides — so any fork using DashboardShell can swap the import without changes. |
|
|
290
444
|
|
|
291
445
|
---
|
|
292
446
|
|
|
293
447
|
## Undescribed components
|
|
294
448
|
|
|
295
|
-
|
|
449
|
+
These 4 components carry no capability description recoverable from source: no section-registry entry, no substantive doc-comment header, no tier-barrel roster line. They are this catalog's blind spots — a capability search will not find them, so read the source before concluding AILK lacks something.
|
|
450
|
+
|
|
451
|
+
| Component | Tier | Source |
|
|
452
|
+
| --- | --- | --- |
|
|
453
|
+
| `Container` | primitives | `packages/ui/src/primitives/Container.tsx` |
|
|
454
|
+
| `Heading` | primitives | `packages/ui/src/primitives/Heading.tsx` |
|
|
455
|
+
| `Link` | primitives | `packages/ui/src/primitives/Link.tsx` |
|
|
456
|
+
| `Text` | primitives | `packages/ui/src/primitives/Text.tsx` |
|
package/dist/cli.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-ailk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Scaffolder for AI Launch Kit — `pnpm create ailk@latest <dir>` produces a starter repo consuming @working-theory/* from npm (per ADR 0007).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -30,18 +30,6 @@
|
|
|
30
30
|
"bugs": {
|
|
31
31
|
"url": "https://github.com/working-theory-labs/ai-launch-kit/issues"
|
|
32
32
|
},
|
|
33
|
-
"scripts": {
|
|
34
|
-
"lint": "tsx ../../scripts/lint-package.ts",
|
|
35
|
-
"build": "tsc -b",
|
|
36
|
-
"type-check": "tsc --noEmit",
|
|
37
|
-
"test": "tsc -b && node scripts/build-templates.mjs && jest",
|
|
38
|
-
"test:watch": "jest --watch",
|
|
39
|
-
"test:coverage": "jest --coverage",
|
|
40
|
-
"build-templates": "node scripts/build-templates.mjs",
|
|
41
|
-
"build-catalog": "node scripts/build-component-catalog.mjs",
|
|
42
|
-
"check-catalog": "node scripts/build-component-catalog.mjs --check",
|
|
43
|
-
"prepublishOnly": "node scripts/build-templates.mjs && node scripts/build-component-catalog.mjs && tsc -b"
|
|
44
|
-
},
|
|
45
33
|
"engines": {
|
|
46
34
|
"node": ">=20.0.0"
|
|
47
35
|
},
|
|
@@ -51,5 +39,16 @@
|
|
|
51
39
|
"create-ailk",
|
|
52
40
|
"ai-launch-kit"
|
|
53
41
|
],
|
|
54
|
-
"license": "Apache-2.0"
|
|
55
|
-
|
|
42
|
+
"license": "Apache-2.0",
|
|
43
|
+
"scripts": {
|
|
44
|
+
"lint": "tsx ../../scripts/lint-package.ts",
|
|
45
|
+
"build": "tsc -b",
|
|
46
|
+
"type-check": "tsc --noEmit",
|
|
47
|
+
"test": "tsc -b && node scripts/build-templates.mjs && jest",
|
|
48
|
+
"test:watch": "jest --watch",
|
|
49
|
+
"test:coverage": "jest --coverage",
|
|
50
|
+
"build-templates": "node scripts/build-templates.mjs",
|
|
51
|
+
"build-catalog": "node scripts/build-component-catalog.mjs",
|
|
52
|
+
"check-catalog": "node scripts/build-component-catalog.mjs --check"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -30,6 +30,7 @@ Routes are versioned under `/v1/*`:
|
|
|
30
30
|
- `/v1/waitlist-experiments` (GET), `/v1/waitlist-experiments/:experimentId` (GET), `/v1/waitlist-experiments/:experimentId/signups` (GET), `/v1/waitlist-experiments/:experimentId/signups/:leadId` (GET) — the operator-dashboard read API for Parallel Waitlist Validation (#4665 D7, B0): tenant-scoped list + rollup, per-waitlist comparison, paginated signups, and a signup drill-down over A1's `WaitlistExperiment` / `WaitlistScore` / `Lead` rows (`src/services/waitlist-dashboard.ts`, #4671). Role floor `owner|admin` (signup PII); the platform-operator scope (`isSentinel(organizationId) && role === "owner"`, ALSO requiring `AILK_OPERATOR_EMAIL` to be set — fail-closed, PR #4687) sees every site, an ordinary owner/admin sees only its own `siteId`. No MCP twin — identity-bound tenant routes (#3591 exception, same shape as `/v1/billing/*`).
|
|
31
31
|
- `/v1/waitlist-signups/me` (GET, `?experimentKey=<slug>`) — the respondent read (#4731): a signed-in, **email-verified** user's OWN newest signup for one experiment (`experimentKey`, `waitlistKey`, `completedAt`, `tier`, `score`, `aeoScore`, `answers.q3` — seven fields, nothing more; `src/services/waitlist-signups.ts` is the only read path). Registered in `authScope` only (auth, no tenant guard — a respondent has no workspace). Identity is `request.userId`; the email is the `User`'s, never a parameter; `emailVerified !== true` → 403 `email_unverified` before any `Lead` read; no match → 404 `signup_not_found`; every read scoped to `currentSiteId()`. No MCP twin — identity-bound (#3591 exception).
|
|
32
32
|
- `/v1/flow-checkouts/me` (GET) — the respondent purchases read (#4984, FEAT-022 M2): a signed-in, **email-verified** user's OWN `FlowCheckout` rows, newest first, `[]` when none (`id`, `flowSlug`, `experimentKey`, `offerKey`, `status`, `amountMinor`, `currency`, `period`, `completedAt`, `createdAt` — ten fields, nothing more; `src/services/flow-checkouts.ts` is the only read path). Registered in `authScope` only, beside `/v1/waitlist-signups/me`. Identity is `request.userId`; rows are joined through the promotion link (`Lead.promotedUserId = userId`, `src/services/lead-promotion.ts`) — never by an email, and no query parameter is read; `emailVerified !== true` → 403 `email_unverified` before any `Lead` read; every read scoped to `currentSiteId()`. No MCP twin — identity-bound (#3591 exception).
|
|
33
|
+
- `/v1/project-listings/me` (GET) — the FOUNDER'S OWN listings read (#5295): a signed-in user's own `ProjectListing` rows, newest first, `[]` when none. Registered in `authScope` only, beside `/v1/flow-checkouts/me` — a founder is not a workspace member, so the tenant guard's default-deny would answer 403 for their own submission. Identity is `request.userId`; rows are joined through the owner link (`ProjectListing.ownerUserId = userId`, stamped by `src/services/listing-promotion.ts`) — **never** by `founderEmail`, at any stage, and no query parameter is read. `founderEmail` is an unverified string typed into an anonymous form, so a read-time email match would hand one of two people sharing an address the other's submission. The row shape is `projectListingDraftSchema` (the founder-facing shape the anonymous draft read already uses — no `siteId`, `leadId`, `decidedBy`, `issueUrl`, or `experimentKey`). The route is ADDITIVE: `PROJECT_LISTING_ROLES` stays `owner|admin` and the tenant-scoped list/get/patch routes are unchanged. No MCP twin — identity-bound (#3591 exception).
|
|
33
34
|
|
|
34
35
|
The workspace site-config routes are **identity-bound tenant routes** (guarded by the tenant preHandler; the write scope is the caller's active workspace, never a body-supplied id). Like the sibling `/v1/workspaces/*` routes they have **no anonymous MCP twin** — the OSS MCP surface is identity-blind (`apps/mcp/CLAUDE.md`), so the "1:1 MCP tool" rule above does not apply to them; the tenant-scoped authed MCP surface is tracked in #3591. The `/v1/billing/*` and `/v1/waitlist-experiments/*` routes are the same shape — identity-bound tenant routes, admin/settings-facing rather than agent-facing, no MCP twin.
|
|
35
36
|
|
|
@@ -118,7 +119,9 @@ sweep's own DB constraint (never a caller-side lock).
|
|
|
118
119
|
- Don't read MDX directly — use `@working-theory/content-adapters`.
|
|
119
120
|
- Don't put session state in `apps/api`. It's stateless.
|
|
120
121
|
|
|
121
|
-
Last updated: 2026-09-
|
|
122
|
+
Last updated: 2026-09-12 — doc-sync: added `GET /v1/project-listings/me` (#5295), the auth-scoped founder read joined on the owner link, to Endpoint conventions — verified against `apps/api/src/routes/project-listings/me.ts` and `apps/api/src/server.ts`.
|
|
123
|
+
|
|
124
|
+
Prior: 2026-09-07 — doc-sync: added `listing-csv:sweep` (#5001), the weekly founder-CSV sweep, to `## Scheduled sweeps (external cron)` — verified against `apps/api/src/bin/listing-csv-sweep.ts` and `apps/api/package.json`.
|
|
122
125
|
|
|
123
126
|
Prior: 2026-09-04 — doc-sync: added the `## Scheduled sweeps (external cron)` section documenting `abandon:sweep` and `followup:sweep` (#4732 AC-6) — verified against `apps/api/package.json` and `apps/api/src/bin/`.
|
|
124
127
|
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
* inbox model flowCheckout (create / update / updateMany / findUnique /
|
|
22
22
|
* findMany) — the recommender buyer record written by the
|
|
23
23
|
* recommender-capture service (#4837) and stamped by the webhook (#4838)
|
|
24
|
+
* inbox model consentGrant (its `createMany` append-only writer + `findMany`
|
|
25
|
+
* reader) — used by the #5275 consent service + project-listings draft tests
|
|
24
26
|
* inbox model waitlistFollowUpSend (its `create` stamp writer + `findMany`
|
|
25
27
|
* idempotency reader) + callback.findMany (booked-call suppression) +
|
|
26
28
|
* waitlistScore.findMany (tier lookup) — used by the #4732
|
|
@@ -241,6 +243,14 @@ export const prisma = {
|
|
|
241
243
|
findFirst: jest.fn(),
|
|
242
244
|
create: jest.fn(),
|
|
243
245
|
},
|
|
246
|
+
// ── Inbox namespace (ConsentGrant — #5275) ───────────────────────────────
|
|
247
|
+
// `createMany` — the ONLY write path into consent_grants (recordConsent /
|
|
248
|
+
// recordLegacyConsent); append-only, never update/upsert. `findMany` — the
|
|
249
|
+
// "what did this subject agree to" read.
|
|
250
|
+
consentGrant: {
|
|
251
|
+
createMany: jest.fn(),
|
|
252
|
+
findMany: jest.fn(),
|
|
253
|
+
},
|
|
244
254
|
// ── Content namespace (UsageEvent, UsagePeriod — FEAT-047 P1.S1/#3709) ──
|
|
245
255
|
usageEvent: {
|
|
246
256
|
create: jest.fn(),
|
package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts
CHANGED
|
@@ -190,6 +190,17 @@ function installStore(): void {
|
|
|
190
190
|
},
|
|
191
191
|
);
|
|
192
192
|
|
|
193
|
+
// #5275 — the grant write `start` makes after the row. Append-only; it only
|
|
194
|
+
// needs to resolve here (drafts.test.ts asserts on what it is called with).
|
|
195
|
+
(prisma.consentGrant.createMany as jest.Mock).mockImplementation(
|
|
196
|
+
({ data }: { data: Row[] }) => Promise.resolve({ count: data.length }),
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
// #5275 — `start` writes the row and its grant in one interactive
|
|
200
|
+
// transaction; the mock hands the same store-backed client through.
|
|
201
|
+
(prisma.$transaction as jest.Mock).mockImplementation(
|
|
202
|
+
async (fn: (tx: typeof prisma) => Promise<unknown>) => fn(prisma),
|
|
203
|
+
);
|
|
193
204
|
(prisma.projectListing.create as jest.Mock).mockImplementation(({ data }: { data: Row }) => {
|
|
194
205
|
const now = new Date();
|
|
195
206
|
const row: Row = {
|