Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 commits
Select commit Hold shift + click to select a range
b73ac1d
fix(registry): rewrite workspace imports in served registry content
educlopez Jun 10, 2026
246e0a2
fix(components): add missing "use client" directive to scramble-hover
educlopez Jun 10, 2026
f065d77
feat(registry): installable themes, AI skill, and theme install button
educlopez Jun 10, 2026
0aa10fd
chore(ci): add typecheck pipeline, pin radix-ui, bump shadcn to 4.10
educlopez Jun 10, 2026
2327ec4
fix(docs): pass percentage strings to react-resizable-panels v4
educlopez Jun 10, 2026
74d0ce1
fix(blocks): respect prefers-reduced-motion across all animated blocks
educlopez Jun 10, 2026
a3bf67d
test: add smoke and a11y coverage for all blocks and untested components
educlopez Jun 10, 2026
4e4531e
fix(components): remove forced min-h-screen from number-flow root
educlopez Jun 10, 2026
7a0f2ec
feat(docs): theme studio page with pannable full-registry board
educlopez Jun 10, 2026
119157f
fix(components): disable native image dragging across the library
educlopez Jun 10, 2026
a276f59
fix(docs): stop frame-box decoration and pan capture from eating clicks
educlopez Jun 10, 2026
e8c441a
feat(docs): copy install command button on each studio demo card
educlopez Jun 10, 2026
27a9f3e
fix(docs): define missing destructive and sidebar-accent source tokens
educlopez Jun 10, 2026
c08e88c
style(docs): float the customize drawer and align studio sidebar metrics
educlopez Jun 10, 2026
690258f
style(docs): match dialkit's measured metrics in customize and studio…
educlopez Jun 10, 2026
ae0e307
style(components): match scrubber sizing to the dialkit inspector scale
educlopez Jun 10, 2026
504beca
feat(docs): per-palette presets plus font and accent controls in studio
educlopez Jun 10, 2026
d1430f4
feat(docs): SmoothUI's own preset system with installable custom themes
educlopez Jun 10, 2026
d9707d9
chore(deps): bump shadcn to 4.11.0
educlopez Jun 11, 2026
e6d8e3e
perf(docs): mark the cursor-follow demo image as priority
educlopez Jun 11, 2026
1a4214c
feat(docs): component search and center-board action in the studio
educlopez Jun 11, 2026
0c35db4
docs: themes guide and 3.5.0 changelog entry
educlopez Jun 11, 2026
f53845b
Merge pull request #87 from educlopez/feat/registry-themes-and-fixes
educlopez Jun 12, 2026
f1ce982
fix(theme): rebuild neutral ramp to uniform spacing and WCAG AA contrast
educlopez Jun 12, 2026
c92f0a1
docs(design): add UI Craft brief and token spine
educlopez Jun 12, 2026
1cd0929
feat(theme): add motion tokens and fix prose type-scale hierarchy
educlopez Jun 12, 2026
d696418
feat(landing): redesign Features as an asymmetric bento with a live demo
educlopez Jun 12, 2026
17b3d44
style(landing): sentence-case section headings and CTA
educlopez Jun 12, 2026
dccc103
feat(landing): unify the showcase to the SectionHeader pattern
educlopez Jun 12, 2026
804f352
style(landing): vary vertical rhythm between sections
educlopez Jun 12, 2026
70fb98b
fix(landing): flatten the AI section card and balance its columns
educlopez Jun 12, 2026
380ced0
style(landing): tame the brand accent across illustrations
educlopez Jun 12, 2026
adc3212
feat(landing): loop a component marquee in the Features lead cell
educlopez Jun 12, 2026
122241d
style(landing): tabular-nums on counters and balance testimonials
educlopez Jun 12, 2026
e9943d8
feat(landing): rework testimonials into a gradient-tile bento
educlopez Jun 12, 2026
2754e7f
feat(landing): turn the testimonials bento into an arrow-paged slider
educlopez Jun 12, 2026
e71bdd8
refactor(landing): match testimonials to the ElevenLabs staggered bento
educlopez Jun 12, 2026
b52b767
refactor(landing): static testimonial cards with an ElevenLabs crossfade
educlopez Jun 12, 2026
bac31f2
feat(landing): morph the testimonials like ElevenLabs
educlopez Jun 12, 2026
960ce04
feat(landing): real Twitter avatars and tweet links on testimonials
educlopez Jun 12, 2026
50f30e3
fix(landing): fillers match center height and hug the center
educlopez Jun 12, 2026
949dd6d
feat(landing): blurred landscape photo backgrounds on feature cards
educlopez Jun 12, 2026
ee82908
fix(landing): unique blurred photos and square filler tiles
educlopez Jun 12, 2026
98e59ea
fix(landing): hug the filler squares to the center card
educlopez Jun 12, 2026
e1eaf44
style(landing): center the testimonials header
educlopez Jun 12, 2026
0397a52
feat(landing): back each Why-choose card with a real artifact
educlopez Jun 12, 2026
2155041
feat(landing): rebuild the AI section as a cohesive artifact bento
educlopez Jun 12, 2026
738fc55
feat(landing): saturated blurred photo backgrounds on the feature leads
educlopez Jun 12, 2026
075b90f
chore(landing): grainy saturated landscapes for all card photos
educlopez Jun 12, 2026
109ec51
feat(landing): vibrant landscape photos and a solid chat card
educlopez Jun 12, 2026
6c14605
chore(landing): higher-quality scene photos with subtle grain
educlopez Jun 12, 2026
1c15c4b
chore(landing): use the provided smooth blur photo for the Why-choose…
educlopez Jun 12, 2026
bb5101f
fix(landing): wire provided scene photos and bypass the dev image opt…
educlopez Jun 12, 2026
c507305
feat(landing): two-sided chat in the AI agent illustration
educlopez Jun 12, 2026
d6bd67d
style(landing): push the chat bubbles to opposite sides
educlopez Jun 12, 2026
01275bb
style(landing): let the chat span the card so bubbles hug their sides
educlopez Jun 12, 2026
83b9109
chore(landing): swap the AI lead photo to the blue/violet scene
educlopez Jun 12, 2026
20069df
feat(landing): richer agent panel with a skill-steps card
educlopez Jun 12, 2026
5bbdb34
feat(landing): real-UI window chrome on illustration artifacts
educlopez Jun 12, 2026
410d5d4
feat(landing): real content in the Hero and Pricing block previews
educlopez Jun 12, 2026
e9b7597
feat(landing): real content in Testimonial and FAQ block previews
educlopez Jun 12, 2026
5c169f8
feat(landing): real content in Footer, Logo, Stats and Team previews
educlopez Jun 12, 2026
87bb888
refactor(landing): simplify the pricing block preview
educlopez Jun 12, 2026
a8f1764
fix(landing): stop block previews inheriting centered text
educlopez Jun 12, 2026
0ccce56
feat(docs): use Plus Jakarta Sans for titles
educlopez Jun 13, 2026
6b585f4
refactor(landing): remove eyebrow labels from section headers
educlopez Jun 13, 2026
dbf24f8
feat(docs): switch to notebook layout with full-width grid and docs f…
educlopez Jun 13, 2026
39048bb
feat(docs): migrate icons from lucide-react to nucleo
educlopez Jun 14, 2026
9e37c1f
style(docs): add thin scrollbars and antialiased text rendering
educlopez Jun 14, 2026
15b137f
fix(docs): center blog post layout and fix AnimatedInput hydration mi…
educlopez Jun 14, 2026
8dd3dc2
feat(docs): add changelog popover and theme switch to docs nav
educlopez Jun 14, 2026
e335543
fix(docs): sidebar polish, icon cleanup, and hydration fixes
educlopez Jun 14, 2026
e2b11c0
fix(docs): consistent content width, compact FeatureCard, sidebar top…
educlopez Jun 14, 2026
1cc3efa
style(docs): align heading scale to ElevenLabs typography
educlopez Jun 14, 2026
e32e65f
feat(docs): move changelog + theme actions next to search in nav
educlopez Jun 20, 2026
3caa80c
feat(smooth-button): rework into a decoupled design-system button
educlopez Jun 23, 2026
44d3740
refactor(landing): unify CTAs on the design-system button
educlopez Jun 23, 2026
09a1137
fix(basic-accordion): keep a stable width by not unmounting collapsed…
educlopez Jun 23, 2026
bc75693
fix(docs): prevent site images from being draggable
educlopez Jun 23, 2026
6f45895
feat(landing): new section artwork, optimized to webp
educlopez Jun 24, 2026
189556f
feat(landing): redesign skill section as a meadow hero
educlopez Jun 24, 2026
99a496a
chore(themes): remove the shadcn/create (approx.) preset link
educlopez Jun 24, 2026
f243688
feat(icon): more cartoon mascot reactions
educlopez Jun 24, 2026
0817daa
feat(landing): add "From the blog" section with the latest posts
educlopez Jun 24, 2026
dafd97a
feat(blog): add "AI Design Slop" post (from main)
educlopez Jun 24, 2026
57cffc1
feat(blog): post cover images with on-brand gradient fallback
educlopez Jun 24, 2026
3a5ea65
refactor(landing): order home as blog → testimonials → FAQ
educlopez Jun 24, 2026
4289641
feat(blog): add cover images to posts
educlopez Jun 24, 2026
9408479
feat(blog): add cover images to the remaining tutorial posts
educlopez Jun 24, 2026
3c68593
fix(landing): self-host the Vercel OSS badge
educlopez Jun 24, 2026
3e0c5f8
fix(blog): shorter post hero cover
educlopez Jun 24, 2026
1edd784
fix(blog): center the cover image crop
educlopez Jun 24, 2026
69b293d
feat(landing): optional UI sound effects (site only)
educlopez Jun 24, 2026
a427cfc
feat(docs): subtle sound on live demo interactions
educlopez Jun 24, 2026
27eaab5
fix(docs): throttle UI sound to prevent double-fire
educlopez Jun 24, 2026
5250c5a
refactor(docs): use the shared button click sound for demos
educlopez Jun 24, 2026
aaff262
fix(seo): index blog in sitemap, canonicals, breadcrumbs
educlopez Jun 24, 2026
56783b8
feat(landing): components-first hero with copy-to-install
educlopez Jun 24, 2026
9c01840
feat(seo): index /themes and give docs pages unique descriptions
educlopez Jun 24, 2026
c44edf0
feat(landing): community coverage strip
educlopez Jun 25, 2026
2e44aef
feat(landing): conversion-optimized section order
educlopez Jun 25, 2026
dceb1eb
fix(landing): drop redundant closing CTA and trailing divider
educlopez Jun 25, 2026
7b1add3
feat(components): add PhotoStack draggable photo deck
educlopez Jun 26, 2026
ed8461c
feat(docs): use Figma background images in component demos
educlopez Jun 26, 2026
c7c0c13
fix(docs): align bundle-size badge icon and move it beside last-updated
educlopez Jun 26, 2026
68ce096
feat(landing): bento components showcase with inline install copy
educlopez Jun 26, 2026
a04bcd0
feat(docs): install bundle — pick components, shareable one-command i…
educlopez Jun 27, 2026
62ba6a4
feat(docs): add blocks to install bundle via Installer add button
educlopez Jun 27, 2026
c4deae2
feat(docs): track install bundle events with Vercel Analytics
educlopez Jun 27, 2026
3d28d47
chore: update lockfile for photo-stack package
educlopez Jun 27, 2026
9908c53
feat(components): add 23 text animation components from animate-text …
educlopez Jun 27, 2026
dddaefc
chore: ignore local skill install artifacts
educlopez Jun 27, 2026
245f96d
feat(components): add ShineText literal light-sweep text effect
educlopez Jun 27, 2026
b5fe33e
feat: add shader transition components
educlopez Jun 29, 2026
fe10fbd
fix: polish bundle add controls
educlopez Jun 29, 2026
f7840d9
feat(landing): refresh hero layout and UI Craft install selector
educlopez Jul 4, 2026
27f7cea
feat(components): rename Akella transitions to ShaderReveal and close…
educlopez Jul 6, 2026
ec747f3
fix(docs): a11y and chrome fixes from the design-system audit
educlopez Jul 6, 2026
68838cf
feat(docs): full-width components gallery with bento grid and fit-sca…
educlopez Jul 6, 2026
dc667f6
feat(docs): remove TOC from blocks pages for full-width previews
educlopez Jul 6, 2026
a5b2259
test(smoothui): raise coverage back above the regression gate
educlopez Jul 6, 2026
26aef52
chore(smoothui): raise coverage thresholds to the new baseline
educlopez Jul 6, 2026
3be3171
docs(guides): document shared animation constants (closes #90)
educlopez Jul 9, 2026
ccd2611
test(app-download-stack): type controlled selectedApps as number[]
educlopez Jul 9, 2026
b118b6e
fix(docs): guard blocks preview against examples without default export
educlopez Jul 12, 2026
907bd1c
Merge remote-tracking branch 'origin/main' into feat/ds-tokens
educlopez Jul 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
26 changes: 26 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ node_modules
.yarn/install-state.gz

# testing
/coverage
coverage/

# next.js
.next/
Expand Down Expand Up @@ -51,3 +51,7 @@ AGENT.md

# internal planning docs (never committed)
planning/
.agents/
node-compile-cache/
skills-lock.json
.claude/skills/
63 changes: 63 additions & 0 deletions .ui-craft/brief.md
Original file line number Diff line number Diff line change
@@ -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.
80 changes: 80 additions & 0 deletions .ui-craft/tokens.md
Original file line number Diff line number Diff line change
@@ -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.
8 changes: 4 additions & 4 deletions apps/docs/app/(home)/docs/page.tsx
Original file line number Diff line number Diff line change
@@ -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: {
Expand All @@ -23,19 +23,19 @@ export default function DocsPage() {
{
name: "Documentation",
description: "The guides for SmoothUI.",
icon: <Library className="size-full" />,
icon: <IconBooksFill24 className="size-full" />,
href: "/docs/guides",
},
{
name: "Components",
description: "The library of SmoothUI components.",
icon: <Pencil className="size-full" />,
icon: <IconPencilFill24 className="size-full" />,
href: "/docs/components",
},
{
name: "Blocks",
description: "The library of SmoothUI blocks.",
icon: <Pencil className="size-full" />,
icon: <IconPencilFill24 className="size-full" />,
href: "/docs/blocks",
},
].map((item) => (
Expand Down
16 changes: 11 additions & 5 deletions apps/docs/app/(home)/page.tsx
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -29,22 +31,26 @@ function SectionSkeleton({ minHeight = "400px" }: { minHeight?: string }) {
}

export default function Home() {
const stats = getSmoothuiStats();
return (
<>
<Hero />
<Features />
<SocialProof />
<Suspense fallback={<SectionSkeleton minHeight="600px" />}>
<ComponentsSlideshow />
</Suspense>
<Features />
<BlockCategories />
<AISection />
<SkillsSection />
<FAQ />
<Suspense fallback={<SectionSkeleton minHeight="700px" />}>
<WhatTheySay />
</Suspense>
<Footer componentCount={stats.componentCount} version={stats.version} />
<Coverage />
<FAQ />
<Suspense fallback={<SectionSkeleton minHeight="500px" />}>
<LatestPosts />
</Suspense>
<Footer />
</>
);
}
14 changes: 14 additions & 0 deletions apps/docs/app/(studio)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { FloatNav } from "@docs/components/float-nav";
import Navbar from "@docs/components/landing/navbar/navbar";

// Full-bleed layout for studio-style screens (no max-w container, unlike
// the (home) landing layout): the canvas must reach the viewport edges.
export default function Layout({ children }: LayoutProps<"/">) {
return (
<div className="relative isolate min-h-screen bg-primary transition">
<Navbar className="mx-auto max-w-7xl" />
{children}
<FloatNav />
</div>
);
}
19 changes: 19 additions & 0 deletions apps/docs/app/(studio)/themes/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ThemeStudio } from "@docs/components/themes/theme-studio";
import { createMetadata } from "@docs/lib/metadata";
import type { Metadata } from "next";

export const metadata: Metadata = createMetadata({
title: "Themes — SmoothUI",
description:
"Installable SmoothUI color themes for shadcn projects. Six palettes with light and dark mode, applied with a single CLI command.",
alternates: {
canonical: "/themes",
},
openGraph: {
url: "/themes",
},
});

export default function ThemesPage() {
return <ThemeStudio />;
}
4 changes: 4 additions & 0 deletions apps/docs/app/blocks/preview/[blockId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export default async function BlockPreviewPage({ params }: PageProps) {
(mod) => mod.default
);

if (typeof BlockExample !== "function") {
notFound();
}

return (
<div className="flex min-h-screen w-full flex-col bg-background p-0 text-foreground">
<ColorSync />
Expand Down
45 changes: 44 additions & 1 deletion apps/docs/app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ArticleSchema } from "@docs/components/article-schema";
import { PostCover } from "@docs/components/post-cover";
import { RelatedPosts } from "@docs/components/related-posts";
import { ShareButtons } from "@docs/components/share-buttons";
import { createMetadata } from "@docs/lib/metadata";
Expand Down Expand Up @@ -43,14 +44,52 @@ export default async function BlogPostPage({ params }: PageProps) {
title={post.data.title}
url={post.url}
/>
<main className="container max-w-6xl py-12">
<script
// biome-ignore lint/security/noDangerouslySetInnerHtml: Schema.org JSON-LD
dangerouslySetInnerHTML={{
__html: JSON.stringify({
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: [
{
"@type": "ListItem",
position: 1,
name: "Home",
item: "https://smoothui.dev",
},
{
"@type": "ListItem",
position: 2,
name: "Blog",
item: "https://smoothui.dev/blog",
},
{
"@type": "ListItem",
position: 3,
name: post.data.title,
item: `https://smoothui.dev${post.url}`,
},
],
}),
}}
type="application/ld+json"
/>
<main className="mx-auto w-full max-w-6xl px-6 py-12">
<Link
className="mb-8 inline-flex items-center gap-2 text-foreground/60 text-sm hover:text-foreground"
href="/blog"
>
← Back to Blog
</Link>

<PostCover
alt={post.data.title}
className="mb-8 aspect-[4/1] rounded-2xl border border-border"
image={post.data.image as string | undefined}
seed={post.url}
sizes="(max-width: 1024px) 100vw, 1152px"
/>

<article>
<header className="mb-8 border-b pb-8">
<h1 className="mb-4 font-bold text-4xl">{post.data.title}</h1>
Expand All @@ -63,7 +102,11 @@ export default async function BlogPostPage({ params }: PageProps) {
<img
alt={post.data.author as string}
className="size-8 rounded-full object-cover"
draggable={false}
height={32}
loading="lazy"
src="https://ik.imagekit.io/16u211libb/avatar-educalvolpz.jpeg?updatedAt=1765524159631&tr=w-64,h-64,q-85,f-auto"
width={32}
/>
<span className="font-medium text-foreground">
{post.data.author as string}
Expand Down
Loading
Loading