mirror of
https://github.com/Manavarya09/design-extract.git
synced 2026-09-19 02:41:14 +08:00
cd58dcaece
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.
46 lines
1.8 KiB
JavaScript
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} />;
|
|
}
|