Files
manavarya09__design-extract/website/app/x/[hash]/page.js
T
Manav Arya Singh cd58dcaece feat(v12): chat REPL + permalinks + gallery + spec + distribution prep
The "best in the game" release: takes designlang from one-shot extractor
to iterative + shareable + standardized + distributed.

ITERATIVE — designlang chat
- src/chat.js: REPL over a live extraction. Heuristic-only router
  parses natural-ish English ("make it brutalist", "primary #ff4800",
  "sharpen radii", "dark mode") into structured operations on the
  design object. Re-derives DTCG / Tailwind / CSS vars / DESIGN.md
  on `save`. Loads from URL or existing *-design-tokens.json.
- bin: new `chat <target>` subcommand. ~360 lines, zero new deps.

SHAREABLE — permalinks
- website/lib/cache.js: getCachedByHash + listRecent helpers over
  the existing Blob cache (24h TTL), no new infra.
- website/lib/build-files.js: shared file-builder used by both
  /api/extract (streaming) and /x/[hash] (permalink page).
- website/app/x/[hash]/page.js + PermalinkViewer.js: every cached
  extraction is now a stable URL. Stat strip + Copy permalink CTA +
  the same 12-tab ResultViewer.
- /api/extract emits a `permalink` event up front; HeroExtractor
  rewrites the URL bar via history.replaceState so refresh-and-share
  works mid-stream.
- website/app/gallery/page.js: public directory of recent extractions,
  palette-strip cards, relative timestamps, intent + material + library
  signals. ISR-cached every 10 min.

STANDARDIZED — DESIGN.md spec
- website/app/spec/page.js: formal spec doc. Eight canonical sections,
  YAML front-matter schema, reference implementation pointer, CC BY 4.0
  license, credit to design-extractor.com for pioneering the format.
- website/public/badge.svg: embeddable Verified badge (paper + ink + accent).
- Sitemap + robots updated with /spec, /gallery.

DISTRIBUTED — submission playbook
- marketplace/SUBMISSION-PLAYBOOK.md: ordered list of 6 marketplaces
  with click-time estimates and review-queue waits.
- marketplace/{figma,cursor,vscode,claude-code-skill,raycast,chrome}-listing.md:
  pre-written listing copy, manifests, screenshot briefs, tweet drafts
  for each. Click "submit" tomorrow morning; nothing left to write.

Home nav: Gallery + Spec links added; v11 → v12 label.
Tests: 317/317 pass.
2026-04-26 21:55:00 +04:00

46 lines
1.8 KiB
JavaScript

import { notFound } from 'next/navigation';
import { getCachedByHash } from '../../../lib/cache';
import { buildFiles, buildSummary } from '../../../lib/build-files';
import PermalinkViewer from './PermalinkViewer';
export const dynamic = 'force-dynamic';
export const runtime = 'nodejs';
export async function generateMetadata({ params }) {
const { hash } = await params;
const cached = await getCachedByHash(hash);
if (!cached) {
return {
title: 'Extraction not found — designlang',
description: 'This designlang permalink has expired or never existed. Run a fresh extraction at designlang.app.',
};
}
const { design } = cached;
const url = design.meta?.url || '';
const title = design.meta?.title || url;
const palette = (design.colors?.all || []).slice(0, 5).map((c) => c.hex).join(' · ');
return {
title: `${title} — design system extracted by designlang`,
description: `${url} · ${design.colors?.all?.length ?? 0} colors · ${design.typography?.families?.[0]?.name || 'system'} · ${design.materialLanguage?.label || 'flat'} material · palette ${palette}.`,
alternates: { canonical: `https://designlang.app/x/${hash}` },
openGraph: {
title: `${title} — designlang`,
description: `Design system extracted from ${url}.`,
url: `https://designlang.app/x/${hash}`,
},
};
}
export default async function PermalinkPage({ params }) {
const { hash } = await params;
const cached = await getCachedByHash(hash);
if (!cached) notFound();
const { design } = cached;
const url = design.meta?.url || '';
const { files } = buildFiles(design, url);
const summary = buildSummary(design);
return <PermalinkViewer hash={hash} url={url} title={design.meta?.title || url} summary={summary} files={files} />;
}