Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/blocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Run `pnpm gen` after changing any authored input. Never edit the generated files
| `check:selections` | Reject empty mutation selections in `src/blocks` |
| `lint:types` | `tsc --noEmit` |
| `test` | `vitest run` |
| `test:visual` | Compare the static Pages site with the Playwright screenshot baselines |
| `test:visual` | Compare the static Pages site with platform-specific Playwright screenshot baselines |
| `build:pages` | `BLOCKS_PAGES=1 next build` — static export for GitHub Pages |

## Layout
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
2 changes: 1 addition & 1 deletion apps/blocks/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
testDir: './e2e',
snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}',
snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{platform}/{arg}{ext}',
fullyParallel: true,
forbidOnly: Boolean(process.env.CI),
retries: process.env.CI ? 2 : 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ export default function DesignAndMotionPage() {
/* "Bigger thing moves, slower spring" — three tiers, nothing in between. */
--dur-fast: 120ms; /* hover, focus, taps */
--dur: 160ms; /* dropdowns, tabs, accordion */
--dur-slow: 240ms; /* dialogs, drawers, stepped flows */`}
--dur-slow: 200ms; /* dialogs, drawers, stepped flows */`}
/>
</div>
<Prose>
<p className="mt-5">
<p className="text-pretty mt-5">
Calm isn’t the absence of design — it’s the discipline of it. The same restraint shapes the blocks you
install: they inherit these tokens, so a surface dropped into your app reads the way the rest of it does.
Retune those tokens for your brand and every block follows — that recipe is{' '}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default function RuntimeContractPage() {
/>
</div>
<Prose>
<p className="mt-5">
<p className="text-pretty mt-5">
This page is about <em>why</em> the contract is shaped this way, not how to install it — the{' '}
<DocLink href="/blocks/getting-started">getting-started</DocLink> tutorial covers the actual setup,
including the environment variables and the auth pieces a block can’t ship for you.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const data = await signIn.mutateAsync({ input: { email, password } });
/>
</div>
<Prose>
<p className="mt-5">
<p className="text-pretty mt-5">
The result is a leaf that already does the full job. The{' '}
<DocLink href="/blocks/auth/sign-in-card">sign-in card</DocLink> validates input, maps the server’s error
codes to copy you can override, branches on unverified and MFA-required states, and renders the loading and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export default function GettingStartedPage() {
namespaces, step-up, passkeys — see{' '}
<DocLink href="/blocks/concepts/runtime-contract">the runtime contract</DocLink>.
</p>
<p className="text-caption text-muted-foreground">
<p className="text-pretty text-caption text-muted-foreground">
You can skip this explicit install — the runtime ships automatically with your first block in the next step.
</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default function AdapterGuidePage() {
}
}`}
/>
<p className="mt-3 text-caption text-muted-foreground">
<p className="text-pretty mt-3 text-caption text-muted-foreground">
Full host checklist: <DocLink href="/blocks/getting-started">Getting started</DocLink>.
</p>
</DocSection>
Expand Down
4 changes: 2 additions & 2 deletions apps/blocks/src/app/blocks/(guides)/guides/auth/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default function AuthGuidePage() {
intro="Add the sign-in card, and make sure BlocksRuntime is mounted so the block can reach your endpoint. Here we only wire the host seams on top of it."
>
<InstallField url="@constructive/auth-sign-in-card" />
<p className="mt-3 text-caption text-muted-foreground">
<p className="text-pretty mt-3 text-caption text-muted-foreground">
Runtime not mounted yet? See <DocLink href="/blocks/guides/adapter">Wire a GraphQL adapter</DocLink>. Full
prop reference: <DocLink href="/blocks/auth/sign-in-card">sign-in-card</DocLink>.
</p>
Expand Down Expand Up @@ -77,7 +77,7 @@ export default function SignInPage() {
);
}`}
/>
<p className="mt-3 text-caption text-muted-foreground">
<p className="text-pretty mt-3 text-caption text-muted-foreground">
<InlineCode>saveSession</InlineCode> is your own token store — the same one{' '}
<InlineCode>BlocksRuntime</InlineCode>’s <InlineCode>getToken</InlineCode> reads, so every later block request
is authenticated.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export default function SignInPage() {
);
}`}
/>
<p className="mt-3 text-caption text-muted-foreground">
<p className="text-pretty mt-3 text-caption text-muted-foreground">
Need a related capability — social sign-in, password reset? Each is its own flow with its own backend; browse
the others in the sidebar.
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default function SingleComponentGuidePage() {
}
}`}
/>
<p className="mt-3 text-caption text-muted-foreground">
<p className="text-pretty mt-3 text-caption text-muted-foreground">
Already done the host setup? Then this is already in place — see{' '}
<DocLink href="/blocks/getting-started">Getting started</DocLink>.
</p>
Expand All @@ -76,7 +76,7 @@ export default function Page() {
return <Button>Create database</Button>;
}`}
/>
<p className="mt-3 text-caption text-muted-foreground">
<p className="text-pretty mt-3 text-caption text-muted-foreground">
Blocks keep importing the package form (<InlineCode>@constructive-io/ui/button</InlineCode>); the two ways to
consume coexist.
</p>
Expand Down
6 changes: 3 additions & 3 deletions apps/blocks/src/app/blocks/(guides)/guides/theming/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default function ThemingGuidePage() {
/* dark-mode overrides */
}`}
/>
<p className="mt-3 text-caption text-muted-foreground">
<p className="text-pretty mt-3 text-caption text-muted-foreground">
New to the host setup? Start with <DocLink href="/blocks/getting-started">Getting started</DocLink>.
</p>
</DocSection>
Expand All @@ -79,7 +79,7 @@ export default function ThemingGuidePage() {
--ring: oklch(0.70 0.18 17);
}`}
/>
<p className="mt-3 text-caption text-muted-foreground">
<p className="text-pretty mt-3 text-caption text-muted-foreground">
Constructive’s own accent is <InlineCode>oklch(0.688 0.175 245.6)</InlineCode> — swap in yours.
</p>
</DocSection>
Expand All @@ -101,7 +101,7 @@ export default function ThemingGuidePage() {
--accent: oklch(0.27 0.01 264);
}`}
/>
<p className="mt-3 text-caption text-muted-foreground">
<p className="text-pretty mt-3 text-caption text-muted-foreground">
These are the standard shadcn token names; the same set exists under <InlineCode>:root</InlineCode> for light
mode.
</p>
Expand Down
10 changes: 5 additions & 5 deletions apps/blocks/src/app/blocks/(guides)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function IntroductionPage() {
<DocPage title={TITLE} description={DESCRIPTION} prev={prev} next={next}>
<section className="flex flex-col gap-6">
<div className="flex flex-col gap-2">
<h3 className="text-[16px] leading-none font-semibold text-foreground">Copy-in, data path wired</h3>
<h3 className="text-balance text-[16px] leading-none font-semibold text-foreground">Copy-in, data path wired</h3>
<p className={proseCls}>
Constructive Blocks are copy-in React components with their data path already wired. Every data block calls a
generated React-Query hook from your application’s <InlineCode>@/generated/&lt;namespace&gt;</InlineCode> SDK
Expand All @@ -43,7 +43,7 @@ export default function IntroductionPage() {
</div>

<div className="flex flex-col gap-2">
<h3 className="text-[16px] leading-none font-semibold text-foreground">One runtime, one wiring point</h3>
<h3 className="text-balance text-[16px] leading-none font-semibold text-foreground">One runtime, one wiring point</h3>
<p className={proseCls}>
One small runtime — <InlineCode>BlocksRuntime</InlineCode> — is the single wiring point: it configures each
namespace’s SDK and shares one <InlineCode>QueryClient</InlineCode>, so blocks never mount providers or read
Expand All @@ -52,7 +52,7 @@ export default function IntroductionPage() {
</div>

<div className="flex flex-col gap-2">
<h3 className="text-[16px] leading-none font-semibold text-foreground">Built on the UI foundation</h3>
<h3 className="text-balance text-[16px] leading-none font-semibold text-foreground">Built on the UI foundation</h3>
<p className={proseCls}>
Every block is built from the same <DocLink href="/blocks/ui/button">UI foundation</DocLink>,{' '}
<InlineCode>@constructive-io/ui</InlineCode>, which ships in this registry too — use it as a package or copy
Expand All @@ -61,7 +61,7 @@ export default function IntroductionPage() {
</div>

<div className="flex flex-col gap-2">
<h3 className="text-[16px] leading-none font-semibold text-foreground">Honest about what’s live</h3>
<h3 className="text-balance text-[16px] leading-none font-semibold text-foreground">Honest about what’s live</h3>
<p className={proseCls}>
Each block states its backend availability, from <em className="text-foreground not-italic">Ready</em> to{' '}
<em className="text-foreground not-italic">Planned</em>, so you always know what is live.
Expand All @@ -87,7 +87,7 @@ export default function IntroductionPage() {
<InstallField url="@constructive/auth-sign-in-card" align="left" className="w-fit" />
</div>
</div>
<p className="text-caption text-muted-foreground">
<p className="text-caption text-pretty text-muted-foreground">
Its whole graph — the runtime, the UI foundation, shared utilities — resolves automatically. Want the
reasoning first? Read <DocLink href="/blocks/concepts/why-blocks">Why blocks</DocLink>. Building a whole
capability? Start from a <DocLink href="/blocks/flows/authentication/email-password">flow</DocLink> — the
Expand Down
2 changes: 1 addition & 1 deletion apps/blocks/src/app/blocks/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export default async function Page({ params }: PageProps) {
))}

{page.builtWith?.length ? (
<p className="text-[13px] text-muted-foreground">
<p className="text-pretty text-[13px] text-muted-foreground">
<span className="text-foreground/70">Built with</span> {page.builtWith.join(', ')}.
</p>
) : null}
Expand Down
2 changes: 1 addition & 1 deletion apps/blocks/src/app/blocks/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ import type { ReactNode } from 'react';
* hamburger; the shell owns the skip-link and `#main` target.
*/
export default function BlocksLayout({ children }: { children: ReactNode }) {
return <div className="mx-auto mt-12 w-full max-w-[760px] px-6 py-20 sm:py-28 xl:mt-0">{children}</div>;
return <div className="mx-auto w-full max-w-[760px] px-6 py-20 sm:py-28">{children}</div>;
}
8 changes: 4 additions & 4 deletions apps/blocks/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1); /* drawers / sheets */
--dur-fast: 80ms; /* hover, color, weight, focus */
--dur: 160ms; /* indicators, small travel */
--dur-slow: 240ms; /* panels, dialogs */
--dur-slow: 200ms; /* panels, dialogs */

/* ── Surfaces (8-level ladder) — LIGHT (DESIGN.md §1.1) ──
Canvas #FAFAFA; the ladder compresses to flat white; shadow does the work.
Expand Down Expand Up @@ -435,7 +435,7 @@ html {
snapping via `display`, these classes fade them: `display` is animated with
`allow-discrete` so the element stays visible across the none↔shown flip,
while opacity tweens. Durations mirror the `spring.slow` motion token —
appear in 0.24s, disappear in 0.16s. The `@starting-style` gives the appear
appear in 0.2s, disappear in 0.16s. The `@starting-style` gives the appear
transition a starting opacity — required for an element to animate out of
`display:none`. Because the panel's space is already reserved at that width,
the appear is a pure opacity fade with no layout shift. Browsers without
Expand All @@ -460,8 +460,8 @@ html {
.xl-fade-block {
opacity: 1;
transition:
opacity 0.24s ease-out,
display 0.24s allow-discrete;
opacity 0.2s ease-out,
display 0.2s allow-discrete;
}
@starting-style {
.xl-fade-flex,
Expand Down
2 changes: 1 addition & 1 deletion apps/blocks/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
className={`${geistSans.variable} ${geistMono.variable}`}
suppressHydrationWarning
>
<body className="min-h-screen bg-background font-sans text-foreground antialiased">
<body className="min-h-dvh bg-background font-sans text-foreground antialiased">
{/* Theme + package-manager context, then the global 3-column shell that
every route (including the landing) renders inside. */}
<Providers>
Expand Down
2 changes: 1 addition & 1 deletion apps/blocks/src/app/not-found.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function NotFound() {
</SiteButton>
</div>

<p className="font-mono text-[12px] text-muted-foreground">
<p className="text-pretty font-mono text-[12px] text-muted-foreground">
HTTP 404 <span aria-hidden>·</span> Not Found
</p>
</div>
Expand Down
10 changes: 5 additions & 5 deletions apps/blocks/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ import { publishedBlockCount, uiCount } from '@/lib/blocks';
// SSR and hydration passes. The skeleton holds the section's size meanwhile.
const GridMotionWall = dynamic(() => import('@/components/landing/grid-motion').then((m) => m.GridMotionWall), {
ssr: false,
loading: () => <div aria-hidden className="h-full w-full motion-safe:animate-pulse" />,
loading: () => <div aria-hidden className="h-full w-full bg-surface-2" />,
});

export default function HomePage() {
return (
<div>
{/* Intro block. `mt-12 xl:mt-0` clears the floating mobile hamburger. */}
<div className="mx-auto mt-12 w-full max-w-[680px] px-6 pb-10 pt-20 sm:pt-28 xl:mt-0">
{/* Intro block. The shell's mobile header owns its top inset. */}
<div className="mx-auto w-full max-w-[680px] px-6 pb-10 pt-20 sm:pt-28">
<div className="flex items-start justify-between gap-4">
<div className="flex flex-col gap-2">
<h1 className="text-h1 text-balance text-foreground max-sm:text-[1.375rem]">Constructive Blocks</h1>
<p className="text-[14px] text-muted-foreground">
<p className="text-pretty text-[14px] text-muted-foreground">
Full-stack auth, org and admin blocks for the Constructive platform — install with shadcn.
</p>
<div className="mt-2 flex items-center gap-2">
Expand Down Expand Up @@ -68,7 +68,7 @@ export default function HomePage() {

{/* Quiet footer — one line. */}
<footer className="mx-auto w-full max-w-[1200px] px-6 pb-10 pt-6">
<p className="text-[12px] tabular-nums text-muted-foreground">
<p className="text-pretty text-[12px] tabular-nums text-muted-foreground">
v0.1.0 <span aria-hidden>·</span> {publishedBlockCount} blocks <span aria-hidden>·</span> {uiCount} ui
components <span aria-hidden>·</span>{' '}
<a
Expand Down
2 changes: 1 addition & 1 deletion apps/blocks/src/blocks-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"registry": "registry.json",
"uiRegistry": "packages/ui/registry.json",
"schemaRegistry": "packages/schema-builder/registry.json",
"hash": "2a07a1c2fdaf156b25aa9ee33ce079c6a946681941f72bd74c4db2447885786a"
"hash": "5bd94ad37b68b1a7fd779a3185ad8d68acd4b60fe98cd46129e1520d1284c9fe"
},
"counts": {
"total": 76,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ export function AccountApiKeysList({
</Button>
</div>
{isMaxReached && (
<p className="text-muted-foreground text-xs mt-1" role="note">
<p className="text-pretty text-muted-foreground text-xs mt-1" role="note">
{merged.maxKeysReached}
</p>
)}
Expand All @@ -256,7 +256,7 @@ export function AccountApiKeysList({
<AuthErrorAlert error={error} />

{keys.length === 0 ? (
<p className="text-muted-foreground text-sm">{merged.noKeysDescription}</p>
<p className="text-pretty text-muted-foreground text-sm">{merged.noKeysDescription}</p>
) : (
<ul role="list" className="space-y-0 list-none">
{keys.map((key, idx) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ export function AccountConnectedAccounts({
)}

{isEmpty ? (
<p className="px-6 pb-4 text-sm text-muted-foreground" data-testid="no-providers-message">
<p className="text-pretty px-6 pb-4 text-sm text-muted-foreground" data-testid="no-providers-message">
{merged.noProvidersMessage}
</p>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ export function AccountDangerCard({

{emailSent ? (
<div role="status" className="rounded-md bg-muted px-4 py-3 text-sm">
<p className="font-medium">{merged.emailSentTitle}</p>
<p className="text-muted-foreground mt-1">{merged.emailSentDescription}</p>
<p className="text-pretty font-medium">{merged.emailSentTitle}</p>
<p className="text-pretty text-muted-foreground mt-1">{merged.emailSentDescription}</p>
</div>
) : (
<Button
Expand All @@ -195,7 +195,7 @@ export function AccountDangerCard({
<DialogDescription>{merged.confirmDialogDescription}</DialogDescription>
</DialogHeader>

<p className="text-sm text-muted-foreground">{merged.confirmDialogBody}</p>
<p className="text-pretty text-sm text-muted-foreground">{merged.confirmDialogBody}</p>

<DialogFooter className="flex-col gap-2 sm:flex-row">
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -928,7 +928,7 @@ export function AccountPhonesList({
{addStep === 2 && (
<div className="px-6 pb-2 space-y-4">
{pendingPhone && (
<p className="text-sm text-muted-foreground">
<p className="text-pretty text-sm text-muted-foreground">
{merged.phoneAddedMessage}
</p>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ export function AccountProfileCard({
</div>

<div className="flex flex-col gap-1.5">
<p className="text-muted-foreground text-xs">{merged.profilePictureHint}</p>
<p className="text-pretty text-muted-foreground text-xs">{merged.profilePictureHint}</p>
<div className="flex gap-2">
<Button
type="button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ export function AccountSessionsList({
<AuthErrorAlert error={error} />

{sessions.length === 0 ? (
<p className="text-muted-foreground text-sm">{merged.noSessionsDescription}</p>
<p className="text-pretty text-muted-foreground text-sm">{merged.noSessionsDescription}</p>
) : (
<ul role="list" className="space-y-0 list-none">
{sessions.map((session, idx) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ export default function AccountSettingsPage({
{merged.skipToContentLabel}
</a>

<h1 className="mb-6 text-2xl font-semibold tracking-tight">{merged.pageTitle}</h1>
<h1 className="mb-6 text-balance text-2xl font-semibold tracking-tight">{merged.pageTitle}</h1>

{currentUserLoading ? (
<div
Expand Down
Loading
Loading