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
3 changes: 3 additions & 0 deletions .agents/skills/constructive-blocks/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ to endpoints, sessions, adapters, or tenant data.
| Secure document rooms shared inside and outside an organization (roles, folder shares, agreements, Q&A, insights) | `data-rooms` |
| Global commands and workflows | `command-palette` |
| Metadata-driven data grid | `sheets` |
| List, detail, and form screens for an app's own tables (relations, many-to-many, delete) | `resource-kit` |
| Sign-in, sign-up, check-email, verify-email, and password reset screens | `auth-pages` |
| An app's home screen with counts and recent records | `dashboard-tiles` |
| PostgreSQL schema workspace | `schema-builder` |
| Reporting hierarchy | `org-chart` |
| Object storage workspace | `storage-browser` or a focused storage leaf |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ live `shadcn@latest search` and `view`.
| Secure document rooms | `data-rooms` | Installed source owns the rooms, documents, people, Q&A, insights, settings, and access-map views, the access explanations and previews, optimistic local updates, and scripted assistant answers; the host supplies workspace data and owns storage, delivery, authorization, the activity log, and assistant runs. |
| Searchable application commands | `command-palette` | The npm package owns the headless engine; installed source owns the dialog and task presentation; the host owns routing and actions. |
| Arbitrary application-table CRUD | `sheets` | Installed source owns the grid; the data runtime interprets current `_meta`; the host owns endpoint and session discovery. |
| Generated app screens for known tables | `resource-kit` | Installed source owns the list, detail, form, relation picker, and delete views, query caching, and invalidation after writes; the host supplies resource definitions, each table's source (list, get, create, update, remove, link), and the router. |
| Public account screens | `auth-pages` | Installed source owns the panels' validation, pending, and result states; the host owns routing, sessions, tokens, and every auth call. |
| App home screen | `dashboard-tiles` | Installed source owns the tiles and their layout and reads counts and recent rows through `resource-kit` sources; the host chooses what to show. |
| Database schema editing | `schema-builder` | Installed source owns the workspace; a host adapter performs control-plane operations and confirmation workflows. |
| Reporting relationships | `org-chart` | The controlled block owns hierarchy presentation; the host loads and persists reporting lines. |
| Object storage management | `storage-browser` or a storage leaf | Blocks are controlled and transport-neutral; the host filters, authorizes, fetches, uploads, and mutates objects. |
Expand Down Expand Up @@ -73,6 +76,7 @@ and dependency closure. The public documentation provides richer examples:
- Storage: `https://constructive-io.github.io/blocks/blocks/storage/` (Storage Browser at `/blocks/storage/browser/`, the feature pack at `/blocks/features/storage/`)
- Agents Builder: `https://constructive-io.github.io/blocks/blocks/agents-builder/`
- Data Rooms: `https://constructive-io.github.io/blocks/blocks/data-rooms/`
- Resource Kit, Auth Pages, Dashboard Tiles: `https://constructive-io.github.io/blocks/blocks/resource-kit/`, `/blocks/auth-pages/`, `/blocks/dashboard-tiles/`
- Billing: `https://constructive-io.github.io/blocks/blocks/billing/` (Billing Account at `/blocks/billing/account/`, Billing Console at `/blocks/billing/console/`)
- Feature packs: `https://constructive-io.github.io/blocks/blocks/features/`
- Console Kit: `https://constructive-io.github.io/blocks/blocks/console-kit/`
Expand Down
23 changes: 23 additions & 0 deletions apps/blocks/src/app/blocks/auth-pages/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Metadata } from 'next';

import { ApplicationBlockDocsPage } from '@/components/application-block-showcase/application-block-docs-page';
import { getApplicationBlock } from '@/lib/application-blocks';
import { OG_IMAGE, withBase } from '@/lib/site';

const block = getApplicationBlock('auth-pages')!;

export default function AuthPagesPage() {
return <ApplicationBlockDocsPage block={block} />;
}

export const metadata: Metadata = {
title: block.title,
description: block.description,
alternates: { canonical: withBase('/blocks/auth-pages') },
openGraph: {
title: block.title,
description: block.description,
url: withBase('/blocks/auth-pages'),
images: [OG_IMAGE],
},
};
18 changes: 18 additions & 0 deletions apps/blocks/src/app/blocks/auth-pages/preview/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Metadata } from 'next';

import { ApplicationBlockShowcaseCanvas } from '@/components/application-block-showcase/application-block-showcase-canvas';
import { withBase } from '@/lib/site';

export default function AuthPagesPreviewPage() {
return (
<>
<h1 className="sr-only">Auth Pages live preview</h1>
<ApplicationBlockShowcaseCanvas name="auth-pages" />
</>
);
}

export const metadata: Metadata = {
alternates: { canonical: withBase('/blocks/auth-pages') },
robots: { follow: false, index: false },
};
23 changes: 23 additions & 0 deletions apps/blocks/src/app/blocks/dashboard-tiles/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Metadata } from 'next';

import { ApplicationBlockDocsPage } from '@/components/application-block-showcase/application-block-docs-page';
import { getApplicationBlock } from '@/lib/application-blocks';
import { OG_IMAGE, withBase } from '@/lib/site';

const block = getApplicationBlock('dashboard-tiles')!;

export default function DashboardTilesPage() {
return <ApplicationBlockDocsPage block={block} />;
}

export const metadata: Metadata = {
title: block.title,
description: block.description,
alternates: { canonical: withBase('/blocks/dashboard-tiles') },
openGraph: {
title: block.title,
description: block.description,
url: withBase('/blocks/dashboard-tiles'),
images: [OG_IMAGE],
},
};
18 changes: 18 additions & 0 deletions apps/blocks/src/app/blocks/dashboard-tiles/preview/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Metadata } from 'next';

import { ApplicationBlockShowcaseCanvas } from '@/components/application-block-showcase/application-block-showcase-canvas';
import { withBase } from '@/lib/site';

export default function DashboardTilesPreviewPage() {
return (
<>
<h1 className="sr-only">Dashboard Tiles live preview</h1>
<ApplicationBlockShowcaseCanvas name="dashboard-tiles" />
</>
);
}

export const metadata: Metadata = {
alternates: { canonical: withBase('/blocks/dashboard-tiles') },
robots: { follow: false, index: false },
};
23 changes: 23 additions & 0 deletions apps/blocks/src/app/blocks/resource-kit/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Metadata } from 'next';

import { ApplicationBlockDocsPage } from '@/components/application-block-showcase/application-block-docs-page';
import { getApplicationBlock } from '@/lib/application-blocks';
import { OG_IMAGE, withBase } from '@/lib/site';

const block = getApplicationBlock('resource-kit')!;

export default function ResourceKitPage() {
return <ApplicationBlockDocsPage block={block} />;
}

export const metadata: Metadata = {
title: block.title,
description: block.description,
alternates: { canonical: withBase('/blocks/resource-kit') },
openGraph: {
title: block.title,
description: block.description,
url: withBase('/blocks/resource-kit'),
images: [OG_IMAGE],
},
};
18 changes: 18 additions & 0 deletions apps/blocks/src/app/blocks/resource-kit/preview/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Metadata } from 'next';

import { ApplicationBlockShowcaseCanvas } from '@/components/application-block-showcase/application-block-showcase-canvas';
import { withBase } from '@/lib/site';

export default function ResourceKitPreviewPage() {
return (
<>
<h1 className="sr-only">Resource Kit live preview</h1>
<ApplicationBlockShowcaseCanvas name="resource-kit" />
</>
);
}

export const metadata: Metadata = {
alternates: { canonical: withBase('/blocks/resource-kit') },
robots: { follow: false, index: false },
};
3 changes: 3 additions & 0 deletions apps/blocks/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
@source '../../../../packages/ui/src/components/billing-kit';
@source '../../../../packages/ui/src/components/billing-account';
@source '../../../../packages/ui/src/components/billing-console';
@source '../../../../packages/ui/src/components/resource-kit';
@source '../../../../packages/ui/src/components/auth-pages';
@source '../../../../packages/ui/src/components/dashboard-tiles';

html {
scroll-padding-top: 4.5rem;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'use client';

import { LayoutDashboard } from 'lucide-react';
import { type ReactNode, useState } from 'react';

import {
CRM_DEMO_ICONS,
CRM_DEMO_NOW,
createCrmDemo,
MemoryRoute,
ResourceKitProvider,
ResourceNav,
useMemoryRouter,
} from '@/components/ui/resource-kit';
import { NavIcon, NavRow, NavSection, SidebarFrame, WorkspaceShell } from '@/components/ui/workspace-kit';

/**
* The CRM demo inside the workspace shell, routed by component state the way
* a host routes it by URL: `/` for home, `/<resource>` for a list, and
* `/<resource>/<id>` for a record.
*/
export function AppKitPreviewShell({ initialPath, home }: { initialPath: string; home?: ReactNode }) {
const { path, setPath, router } = useMemoryRouter(initialPath);
const [resources] = useState(() => createCrmDemo({ latency: 200 }));

return (
<div className="flex h-dvh min-h-[640px] w-full flex-col" data-slot="application-block-showcase-canvas">
<ResourceKitProvider router={router} resources={resources} icons={CRM_DEMO_ICONS} now={CRM_DEMO_NOW}>
<WorkspaceShell
className="min-h-0 flex-1"
sidebar={({ mode, collapsed, onCollapsedChange, onNavigate }) => {
const rail = mode === 'rail' && collapsed;
return (
<SidebarFrame
label="Acme CRM"
menu={<span className="min-w-0 flex-1 truncate px-1.5 text-sm font-medium">{rail ? 'A' : 'Acme CRM'}</span>}
collapsed={collapsed}
onCollapsedChange={onCollapsedChange}
drawer={mode === 'drawer'}
onClose={onNavigate}
>
<nav aria-label="Acme CRM" className="flex w-full flex-col gap-3">
{home ? (
<NavSection collapsed={rail}>
<NavRow
label="Overview"
collapsed={rail}
active={path === '/'}
leading={<NavIcon icon={LayoutDashboard} active={path === '/'} />}
onClick={() => {
setPath('/');
onNavigate();
}}
/>
</NavSection>
) : null}
<ResourceNav collapsed={rail} activeHref={path} onNavigate={onNavigate} title={home ? 'Records' : undefined} />
</nav>
</SidebarFrame>
);
}}
>
<MemoryRoute path={path} home={home} />
</WorkspaceShell>
</ResourceKitProvider>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ const OrgChartPreview = dynamic(() =>
const StorageBrowserPreview = dynamic(() =>
import('./storage-browser-preview').then((module) => module.StorageBrowserPreview),
);
const ResourceKitPreview = dynamic(() =>
import('./resource-kit-preview').then((module) => module.ResourceKitPreview),
);
const AuthPagesPreview = dynamic(() =>
import('./auth-pages-preview').then((module) => module.AuthPagesPreview),
);
const DashboardTilesPreview = dynamic(() =>
import('./dashboard-tiles-preview').then((module) => module.DashboardTilesPreview),
);

export function ApplicationBlockShowcaseCanvas({
name,
Expand All @@ -33,6 +42,9 @@ export function ApplicationBlockShowcaseCanvas({
if (name === 'data-rooms') return <DataRoomsPreview />;
if (name === 'billing-account') return <BillingAccountPreview />;
if (name === 'billing-console') return <BillingConsolePreview />;
if (name === 'resource-kit') return <ResourceKitPreview />;
if (name === 'auth-pages') return <AuthPagesPreview />;
if (name === 'dashboard-tiles') return <DashboardTilesPreview />;
return name === 'org-chart' ? (
<OrgChartPreview />
) : (
Expand Down
Loading
Loading