diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c1a16c8b..6961c0eb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -62,6 +62,28 @@ jobs: - name: Lint run: pnpm check + typecheck: + name: Typecheck + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Typecheck + run: pnpm typecheck + test: name: Test runs-on: ubuntu-latest @@ -84,6 +106,10 @@ jobs: - name: Test run: pnpm test + - name: Verify registry output (no workspace import leaks) + working-directory: apps/docs + run: npx tsx scripts/verify-registry.mts + build: name: Build runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 09cec6be..fccf8ca2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ node_modules .yarn/install-state.gz # testing -/coverage +coverage/ # next.js .next/ @@ -51,3 +51,7 @@ AGENT.md # internal planning docs (never committed) planning/ +.agents/ +node-compile-cache/ +skills-lock.json +.claude/skills/ diff --git a/.ui-craft/brief.md b/.ui-craft/brief.md new file mode 100644 index 00000000..58bc8717 --- /dev/null +++ b/.ui-craft/brief.md @@ -0,0 +1,63 @@ +# SmoothUI — Design Brief + +Surface: the SmoothUI public site (landing + docs + Theme Studio at smoothui.dev). +Scoped to the marketing/docs surface, not the installed components themselves. +Created 2026-06-12. Append-mostly — date every change, never delete principles. + +## 1. Product purpose + +The place where React developers and AI agents discover, preview live, and +install animated shadcn-compatible components in one command. + +## 2. Primary user + +A React developer already using shadcn/ui, evaluating components on a desktop, +who wants to preview the motion, then `npx shadcn add` and ship in minutes — and +the AI coding agents that install on their behalf. Both are first-class. + +## 3. Principles (conflict-resolution order — higher wins) + +1. **Show the component, not the chrome.** The live demos are the product; site + UI retreats so the preview is the loudest thing on screen. Decoration loses to + the demo every time. +2. **Installable beats impressive.** The install command is never more than one + click from the preview. Optimize for "copy and ship", not for browsing. +3. **Machine-readable is a first-class surface.** Anything a human can find + (component, props, install), an agent can fetch as structured data. No + human-only affordance for core discovery. +4. **Motion proves the point, never decorates.** Animation demonstrates a + component's behavior; site chrome animates only to communicate state or space, + and always honors `prefers-reduced-motion`. +5. **One signature, applied everywhere.** The dotted-frame motif and the brand + pink are the identity; consistency across landing, docs and studio beats + per-page novelty. + +> Override example: if the dotted-frame motif (P5) competes with a component +> preview for attention (P1), P1 wins — the frame retreats. + +## 4. Success metric + +A developer lands on a component page and has the install command copied (or the +code panel open) within ~15 seconds — and an agent can resolve the same +component's install JSON in a single request. + +## 5. Out of scope + +- Does not persist user state server-side — Theme Studio presets are URL-encoded, not accounts. +- Does not re-explain shadcn basics — links out rather than duplicating shadcn's docs. +- Does not gate core component discovery behind JS-only interactions. +- Does not blur the free/Pro line — Pro content lives on pro.smoothui.dev. +- Does not become a generic theming playground — the studio themes SmoothUI's own surface. + +## Visual direction (durable decisions, 2026-06-12) + +- **Style: Soft Modern, refined.** Evolve the current look — rounded cards, soft + layered shadows (ambient + direct, no heavy glow), generous whitespace, neutrals + with a subtle tint. Polish and consistency over reinvention. +- **Accent: brand pink, kept.** `oklch(0.72 0.2 352.53)`. Budget it to 3–5 + placements per above-the-fold viewport; lower chroma on secondary uses. +- **Signature: the dotted frame** (`.frame-box`) is the recurring motif. +- **Type: Poppins display / Inter body** — keep, but unify into a shared type + scale consumed by landing AND docs prose (today they diverge). +- **Audience: humans + machines equally** — keep the AI-native surface + (llms.txt, skill, structured endpoints) first-class alongside the visual design. diff --git a/.ui-craft/tokens.md b/.ui-craft/tokens.md new file mode 100644 index 00000000..7ab75f55 --- /dev/null +++ b/.ui-craft/tokens.md @@ -0,0 +1,80 @@ +# SmoothUI — Token Spine + +Audit + decisions for the design-token spine. Anchored to `brief.md`. +Created 2026-06-12. The project already has a Tailwind v4 `@theme inline` system +in `apps/docs/app/smoothui.css` + `global.css` — this **extends**, never replaces. + +## Layer status (audit) + +| Category | State | Source | +|---|---|---| +| Neutral ramp | ✅ rebuilt, perceptually uniform, WCAG AA (f1ce982) | `smoothui.css` `--color-smooth-*` | +| Accent (brand) | ✅ pink `oklch(0.72 0.2 352.53)` + secondary/light/lighter | `smoothui.css` `--color-brand*` | +| Semantic color | ✅ shadcn-style (background/foreground/muted/border/input/sidebar/chart) | `smoothui.css` `@theme inline` | +| Spacing | ✅ Tailwind v4 defaults — **no gap**, issue is uniform *usage* (py-24 everywhere) | Tailwind | +| Radius | ⚠️ `--radius` + sm/md/lg/xl exist, but applied uniformly (`rounded-xl` everywhere) | `smoothui.css` lines 48-51 | +| Type scale | ❌ no shared semantic roles; landing (Poppins) / docs prose / studio (13px) diverge; `prose h2` cliffs to 18px | ad-hoc | +| Shadows | ✅ `--shadow-custom`, `--shadow-custom-brand` (layered) | `global.css` | +| Motion | ❌ no duration/easing tokens; components hardcode (0.2-0.3s, cubic-beziers) | ad-hoc | +| Z-index | ⚠️ ad-hoc; not tokenized | — | + +## Decisions + +### Type scale (the unification core) + +One scale, consumed by landing AND docs prose AND studio. Poppins = display, +Inter = body/UI, mono for code/values. Roles (apply consistently, stop ad-hoc sizes): + +| Role | Size | Weight | Tracking | Use | +|---|---|---|---|---| +| display-xl | 60px (text-6xl) | 600 | -0.02em | hero headline | +| display-lg | 48px (text-5xl) | 600 | -0.02em | section headlines | +| heading | 30px (text-3xl) | 600 | -0.01em | page / prose h1 | +| subheading | 24px (text-2xl) | 600 | -0.01em | **prose h2 (fixes 18px cliff)** | +| title | 19px (text-lg/xl) | 600 | normal | prose h3, card titles | +| body | 16px (text-base) | 400 | normal | prose p, descriptions | +| label | 13px | 500 | normal | UI labels, studio inspector | +| eyebrow | 12-13px | 600 | 0.05em, uppercase | category labels (the ONE allowed uppercase) | + +Prose heading scale in `global.css` is corrected to follow this (h2 → subheading, +not text-lg). + +### Radius — vary by element (kill uniform `rounded-xl`) + +| Token | px | Element | +|---|---|---| +| `--radius-sm` (calc -4) | ~6px | inputs, badges, segmented controls | +| `--radius-md` (calc -2) | ~8px | buttons, small panels, studio rows | +| `--radius-lg` (`--radius` 10px) | 10px | cards | +| `--radius-xl` (calc +4) | ~14px | modals, large panels, hero frame | +| `--radius-full` | pill | tags, avatars, the float nav | + +Base `--radius` stays `0.625rem` (10px). Soft Modern = lean toward the larger end +for cards (`rounded-2xl`/14px) where it reads friendly, per brief visual direction. + +### Motion tokens (new category) + +Match the existing `.cursor/rules/animations.mdc` convention — don't invent new curves. + +```css +--duration-fast: 0.15s; /* color/opacity, hover */ +--duration-normal: 0.25s; /* standard UI: dropdowns, toggles */ +--duration-slow: 0.4s; /* modals, drawers, page-level */ +--ease-out: cubic-bezier(0.23, 1, 0.32, 1); /* entering */ +--ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); /* moving */ +``` + +Exit ≈ 75% of enter. Always honor `prefers-reduced-motion`. Spring bounce ≤ 0.1 for UI. + +### Accent budget (brief P-color) + +Brand pink: max 3-5 placements per above-the-fold viewport. Secondary uses drop +chroma (`--color-brand-light/lighter`). Today the pink appears in logo + sidebar +active + TOC active + eyebrows + CTA simultaneously — trim per viewport. + +## Scope boundary + +This spine doc + the additive **motion tokens** + the **prose type-scale fix** are +the token-phase deliverables. Applying the full type/radius scale across every +landing section and component is the **visual redesign phase** (next), done with +the browser in the loop. diff --git a/apps/docs/app/(home)/docs/page.tsx b/apps/docs/app/(home)/docs/page.tsx index 0ba34bb6..f69b9894 100644 --- a/apps/docs/app/(home)/docs/page.tsx +++ b/apps/docs/app/(home)/docs/page.tsx @@ -1,7 +1,7 @@ import { cn } from "@repo/shadcn-ui/lib/utils"; -import { Library, Pencil } from "lucide-react"; import type { Metadata } from "next"; import Link, { type LinkProps } from "next/link"; +import { IconBooksFill24, IconPencilFill24 } from "nucleo-core-fill-24"; export const metadata: Metadata = { alternates: { @@ -23,19 +23,19 @@ export default function DocsPage() { { name: "Documentation", description: "The guides for SmoothUI.", - icon: , + icon: , href: "/docs/guides", }, { name: "Components", description: "The library of SmoothUI components.", - icon: , + icon: , href: "/docs/components", }, { name: "Blocks", description: "The library of SmoothUI blocks.", - icon: , + icon: , href: "/docs/blocks", }, ].map((item) => ( diff --git a/apps/docs/app/(home)/page.tsx b/apps/docs/app/(home)/page.tsx index 3ede73e0..3d0a74aa 100644 --- a/apps/docs/app/(home)/page.tsx +++ b/apps/docs/app/(home)/page.tsx @@ -1,13 +1,15 @@ import { AISection } from "@docs/components/landing/ai-section"; import { BlockCategories } from "@docs/components/landing/block-categories"; import { ComponentsSlideshow } from "@docs/components/landing/components-slideshow"; +import { Coverage } from "@docs/components/landing/coverage"; import { FAQ } from "@docs/components/landing/faqs"; import { Features } from "@docs/components/landing/features"; import Footer from "@docs/components/landing/footer"; import { Hero } from "@docs/components/landing/hero"; +import { LatestPosts } from "@docs/components/landing/latest-posts"; import { SkillsSection } from "@docs/components/landing/skills-section"; +import { SocialProof } from "@docs/components/landing/social-proof"; import { WhatTheySay } from "@docs/components/landing/what-they-say"; -import { getSmoothuiStats } from "@docs/lib/smoothui-stats"; import type { Metadata } from "next"; import { Suspense } from "react"; @@ -29,22 +31,26 @@ function SectionSkeleton({ minHeight = "400px" }: { minHeight?: string }) { } export default function Home() { - const stats = getSmoothuiStats(); return ( <> - + }> + - }> -