Initial public push: docs cosmos v4 + AI module + framework groundwork
This is the snapshot the production landing site (nibiru-framework.com) is deployed from. Brings together the recent splash + docs migration to the v4 "Cosmos" design system, the new in-framework AI module, and the framework groundwork that backs the framework-reference extraction. What lands: - docs/: Astro + Starlight site with the v4 dark cosmic palette, GalaxyHero canvas constellation, Mission Control chat (wired to /api/oracle → api.neuronetz.ai via providers.mjs Ollama), 5-panel MMVC stage (Model · AI · Module · Controller · View), translated EN/DE/JA/ES/FR content, PWA + sitemap + llms.txt + Umami analytics. - docs/design-system/: canonical mockup bundle (source/index-v2.html for splash, source/docs-system.html + preview/ for docs, SPEC.md, tokens). - docs/scripts/extraction/framework-reference-v2.md: deep framework reference (~1.6k lines, file:line citations, every public factory and idiom — basis for the LoRA training corpus. - application/module/ai/: AI module with chat / embed / RAG / agent plugins, plus pdoQuery / httpGet / fileRead tools and Modelfile + smoke-test in training/. - application/module/users/: user / ACL / form-factory traits used as the reference plugin pattern for the framework docs. - application/settings/config/database/: schema + seed migrations including the AI module tables (200–203). - Form factory + autogenerator changes the framework-reference-v2 covers. Production secrets stay out: docs/.env, settings.production.ini and ai.production.ini are all gitignored (.example files are in tree). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
523
docs/design-system/source/docs-system.html
Normal file
523
docs/design-system/source/docs-system.html
Normal file
@@ -0,0 +1,523 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Nibiru — Docs Design System</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter+Tight:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="docs-system/tokens.css" />
|
||||
<link rel="stylesheet" href="docs-system/components.css" />
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
background: #050208;
|
||||
font-family: "Inter Tight", system-ui, sans-serif;
|
||||
color: #f4eedb;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Lotus logo as data URI (so the bundler can inline it & it works with file://) -->
|
||||
<img id="lotus-asset" src="docs-system/assets/lotus.png" style="display:none" alt=""/>
|
||||
<script>
|
||||
// Convert the loaded image to a data URL once, expose globally for components.
|
||||
(function () {
|
||||
const img = document.getElementById('lotus-asset');
|
||||
function publish() {
|
||||
try {
|
||||
const c = document.createElement('canvas');
|
||||
c.width = img.naturalWidth || 861;
|
||||
c.height = img.naturalHeight || 569;
|
||||
c.getContext('2d').drawImage(img, 0, 0);
|
||||
window.NIBIRU_LOTUS = c.toDataURL('image/png');
|
||||
} catch (e) {
|
||||
window.NIBIRU_LOTUS = img.src;
|
||||
}
|
||||
}
|
||||
if (img.complete && img.naturalWidth) publish();
|
||||
else img.addEventListener('load', publish, { once: true });
|
||||
})();
|
||||
</script>
|
||||
|
||||
<template id="__bundler_thumbnail" data-bg-color="#0b0410">
|
||||
<svg viewBox="0 0 1200 800" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<radialGradient id="bg" cx="50%" cy="50%" r="60%">
|
||||
<stop offset="0%" stop-color="#1a0824"/>
|
||||
<stop offset="100%" stop-color="#05020a"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="petalP" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#d8a8ff"/>
|
||||
<stop offset="100%" stop-color="#8a78c4"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="petalB" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#bfd4ee"/>
|
||||
<stop offset="100%" stop-color="#7ea0cc"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="1200" height="800" fill="url(#bg)"/>
|
||||
<g transform="translate(600 420)" opacity="0.95">
|
||||
<ellipse cx="0" cy="-80" rx="38" ry="140" fill="url(#petalP)"/>
|
||||
<ellipse cx="-130" cy="-30" rx="38" ry="140" fill="url(#petalP)" transform="rotate(-30 -130 -30)"/>
|
||||
<ellipse cx="130" cy="-30" rx="38" ry="140" fill="url(#petalB)" transform="rotate(30 130 -30)"/>
|
||||
<ellipse cx="-230" cy="40" rx="34" ry="120" fill="url(#petalP)" transform="rotate(-55 -230 40)"/>
|
||||
<ellipse cx="230" cy="40" rx="34" ry="120" fill="url(#petalB)" transform="rotate(55 230 40)"/>
|
||||
</g>
|
||||
<text x="600" y="640" text-anchor="middle" font-family="system-ui, sans-serif" font-size="64" font-weight="300" fill="#d8a8ff" letter-spacing="2">Nibiru</text>
|
||||
<text x="600" y="700" text-anchor="middle" font-family="system-ui, sans-serif" font-size="22" fill="#8ea8d4" letter-spacing="3">Docs Design System</text>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<div id="root"></div>
|
||||
|
||||
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
||||
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
||||
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
||||
|
||||
<script type="text/babel" src="design-canvas.jsx"></script>
|
||||
<script type="text/babel" src="docs-system/components/navigation.jsx"></script>
|
||||
<script type="text/babel" src="docs-system/components/typography-and-code.jsx"></script>
|
||||
<script type="text/babel" src="docs-system/components/extras.jsx"></script>
|
||||
|
||||
<script type="text/babel" data-presets="react">
|
||||
(() => {
|
||||
const { DesignCanvas, DCSection, DCArtboard } = window;
|
||||
|
||||
// ============================================================
|
||||
// Frame wrapper — gives each artboard the docs-frame baseline
|
||||
// ============================================================
|
||||
function Frame({ theme = "dark", padded = true, children, style }) {
|
||||
return (
|
||||
<div
|
||||
className={"docs-frame " + (theme === "light" ? "theme-light" : "")}
|
||||
style={{ width: "100%", height: "100%", ...style }}
|
||||
>
|
||||
<div style={{ background: "var(--space)", minHeight: "100%", height: "100%", padding: padded ? 32 : 0 }} className="cosmic-bg">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// FULL PAGE PREVIEW (the marquee artboard)
|
||||
// ============================================================
|
||||
function FullPagePreview({ theme = "dark" }) {
|
||||
const tocItems = [
|
||||
{ id: "overview", level: 1, label: "Overview" },
|
||||
{ id: "box", level: 1, label: "What's in the box" },
|
||||
{ id: "mmvc", level: 1, label: "What MMVC actually means" },
|
||||
{ id: "lifecycle", level: 1, label: "The request lifecycle" },
|
||||
{ id: "for-whom", level: 1, label: "Who Nibiru is for" },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className={"docs-frame " + (theme === "light" ? "theme-light" : "")} style={{ height: "100%" }}>
|
||||
<div className="docs-page-preview-shell cosmic-bg">
|
||||
<TopNav theme={theme} />
|
||||
<div className="docs-page-preview-body">
|
||||
<Sidebar />
|
||||
<div className="docs-page-preview-content">
|
||||
<PageHeader
|
||||
crumbs={["Get Started", "What is Nibiru?"]}
|
||||
title="What is Nibiru?"
|
||||
summary="A modular MVC PHP framework — MMVC — built for rapid prototyping without giving up the discipline of a real framework."
|
||||
lastUpdated="2 days ago"
|
||||
/>
|
||||
<Prose>
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>
|
||||
<strong>Nibiru</strong> is a modular <em>MMVC</em> framework — Model, <strong>Module</strong>, View, Controller — small enough to fit in your head, powerful enough to back production apps.
|
||||
</p>
|
||||
<p>
|
||||
The name is a wink at Babylonian astronomy: <strong>Nibiru</strong> was the celestial crossing-point associated with Marduk. The framework runs on the same idea — a single point through which your modules, controllers, views and data cross paths.
|
||||
</p>
|
||||
|
||||
<h2 id="box">What's in the box</h2>
|
||||
<DocTable
|
||||
headers={["Layer", "Description"]}
|
||||
rows={[
|
||||
["Routing & dispatch", <>URL-pattern + SEO-URL parsing, soft 404, automatic action lookup.</>],
|
||||
["MVC + a second M", <>Controllers, Views (Smarty), Models, plus first-class <strong>Modules</strong> with traits, plugins, interfaces, settings and an observer pattern.</>],
|
||||
["Multi-database", <>Native MySQL, PDO, PostgreSQL via libpq (<code>psql</code> / <code>postgresql</code>) and ODBC, all behind a unified <code>Db</code> adapter.</>],
|
||||
["Forms", <>28+ field types built fluently with <code>Form::addInputType…()</code> and a layout helper for divs.</>],
|
||||
]}
|
||||
/>
|
||||
|
||||
<Callout kind="tip" title="Quick win">
|
||||
Run <code>nibiru new myapp</code> to scaffold a working project in under 30 seconds.
|
||||
</Callout>
|
||||
|
||||
<h2 id="mmvc">What MMVC actually means</h2>
|
||||
<p>
|
||||
The extra <strong>M</strong> stands for <em>Module</em> — a self-contained unit that can declare its own routes, controllers, models, views, and settings. Modules slot into the framework's registry and are wired together at boot.
|
||||
</p>
|
||||
</Prose>
|
||||
<Pagination prev={null} next="Why Nibiru, not Laravel" />
|
||||
</div>
|
||||
<RightTOC items={tocItems} activeId="box" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// CANVAS
|
||||
// ============================================================
|
||||
function App() {
|
||||
return (
|
||||
<DesignCanvas title="Nibiru — Docs Design System" defaultZoom={0.65}>
|
||||
|
||||
{/* ============ SECTION: FULL PAGE ============ */}
|
||||
<DCSection id="full" title="Full page · the system in context">
|
||||
<DCArtboard id="full-dark" label="Dark — primary" width={1440} height={840}>
|
||||
<FullPagePreview theme="dark" />
|
||||
</DCArtboard>
|
||||
<DCArtboard id="full-light" label="Light — daylight reading" width={1440} height={840}>
|
||||
<FullPagePreview theme="light" />
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: TOP NAV ============ */}
|
||||
<DCSection id="nav" title="Top navigation">
|
||||
<DCArtboard id="nav-dark" label="Top nav — dark" width={1280} height={120}>
|
||||
<Frame padded={false}><TopNav theme="dark" /></Frame>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="nav-light" label="Top nav — light" width={1280} height={120}>
|
||||
<Frame theme="light" padded={false}><TopNav theme="light" /></Frame>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: SIDEBAR ============ */}
|
||||
<DCSection id="sidebar" title="Sidebar nav · sectioned with collapsibles">
|
||||
<DCArtboard id="sb-dark" label="Sidebar — dark" width={320} height={760}>
|
||||
<Frame padded={false}><Sidebar /></Frame>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="sb-light" label="Sidebar — light" width={320} height={760}>
|
||||
<Frame theme="light" padded={false}><Sidebar /></Frame>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="toc" label="On-this-page TOC" width={280} height={520}>
|
||||
<Frame padded={false}>
|
||||
<RightTOC
|
||||
activeId="lifecycle"
|
||||
items={[
|
||||
{ id: "overview", level: 1, label: "Overview" },
|
||||
{ id: "box", level: 1, label: "What's in the box" },
|
||||
{ id: "mmvc", level: 1, label: "What MMVC means" },
|
||||
{ id: "module", level: 2, label: "The Module layer" },
|
||||
{ id: "lifecycle", level: 1, label: "Request lifecycle" },
|
||||
{ id: "edge", level: 2, label: "Edge cases" },
|
||||
{ id: "for-whom", level: 1, label: "Who it's for" },
|
||||
]}
|
||||
/>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: PAGE HEADER & TYPOGRAPHY ============ */}
|
||||
<DCSection id="prose" title="Page header & body typography">
|
||||
<DCArtboard id="header" label="Page header" width={780} height={280}>
|
||||
<Frame>
|
||||
<PageHeader
|
||||
crumbs={["The Framework", "Architecture (MMVC)"]}
|
||||
title="Architecture (MMVC)"
|
||||
summary="How Model, Module, View, and Controller cross paths through a single dispatcher."
|
||||
lastUpdated="2 days ago"
|
||||
/>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="prose-dark" label="Prose — dark" width={780} height={620}>
|
||||
<Frame>
|
||||
<Prose>
|
||||
<h2>Headings, body, and rhythm</h2>
|
||||
<p>
|
||||
Body text uses <strong>Inter Tight</strong> at 16px with a 1.7 line height — the right balance between density and readability for technical content. Inline accents like <em>emphasized terms</em> use the magenta accent color, and <code>inline code</code> sits in a tinted token.
|
||||
</p>
|
||||
<h3>Lists carry their own rhythm</h3>
|
||||
<ul>
|
||||
<li>List markers pick up the magenta accent.</li>
|
||||
<li>Spacing between items is tight — 6px — so dense reference content stays scannable.</li>
|
||||
<li>Sub-bullets nest cleanly without losing the magenta thread.</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
"MMVC is the discipline of MVC plus the modularity of plugins — without the indirection of either."
|
||||
</blockquote>
|
||||
<p>
|
||||
Block quotes get a magenta left rail with a subtle gradient pulling the eye toward the quote.
|
||||
</p>
|
||||
</Prose>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="prose-light" label="Prose — light" width={780} height={620}>
|
||||
<Frame theme="light">
|
||||
<Prose>
|
||||
<h2>Headings, body, and rhythm</h2>
|
||||
<p>
|
||||
On the <strong>light theme</strong>, accent colors shift to higher-contrast equivalents — purple replaces magenta, teal replaces cyan — keeping <em>emphasized terms</em> and <code>inline code</code> legible against the parchment background.
|
||||
</p>
|
||||
<h3>Code samples stay dark</h3>
|
||||
<p>
|
||||
Code blocks remain on the cosmic plum background even in light mode. The contrast against parchment grounds the page and signals "this is a runnable artifact."
|
||||
</p>
|
||||
</Prose>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: CODE BLOCKS ============ */}
|
||||
<DCSection id="code" title="Code blocks · Mission-Control aesthetic">
|
||||
<DCArtboard id="code-php" label="PHP" width={760} height={440}>
|
||||
<Frame>
|
||||
<CodeBlock filename="app/Controllers/BookingController.php" lang="php">
|
||||
{phpSample}
|
||||
</CodeBlock>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="code-sql" label="SQL" width={760} height={300}>
|
||||
<Frame>
|
||||
<CodeBlock filename="queries/recent-bookings.sql" lang="sql">
|
||||
{sqlSample}
|
||||
</CodeBlock>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="code-yaml" label="YAML config" width={760} height={300}>
|
||||
<Frame>
|
||||
<CodeBlock filename="config/app.yaml" lang="yaml">
|
||||
{yamlSample}
|
||||
</CodeBlock>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="code-tabs" label="Tabbed code (PHP / SQL / YAML)" width={760} height={460}>
|
||||
<Frame>
|
||||
<Tabs tabs={[
|
||||
{ label: "PHP", content: <CodeBlock filename="BookingController.php" lang="php">{phpSample}</CodeBlock> },
|
||||
{ label: "SQL", content: <CodeBlock filename="queries.sql" lang="sql">{sqlSample}</CodeBlock> },
|
||||
{ label: "YAML", content: <CodeBlock filename="config/app.yaml" lang="yaml">{yamlSample}</CodeBlock> },
|
||||
]}/>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: CALLOUTS ============ */}
|
||||
<DCSection id="callouts" title="Callouts · cosmic-coded by severity">
|
||||
<DCArtboard id="callout-stack" label="All four kinds" width={780} height={460}>
|
||||
<Frame>
|
||||
<Callout kind="note" title="Note">
|
||||
The dispatcher resolves the controller and action automatically — you rarely need to wire routes by hand.
|
||||
</Callout>
|
||||
<Callout kind="tip" title="Tip">
|
||||
Use <code>nibiru make:module Blog</code> to scaffold a complete module — routes, controller, model, and views.
|
||||
</Callout>
|
||||
<Callout kind="warning" title="Backwards-compat break">
|
||||
In <code>2.0</code>, <code>Form::addInput()</code> is deprecated. Use <code>Form::addInputType()</code> instead.
|
||||
</Callout>
|
||||
<Callout kind="danger" title="Don't do this in production">
|
||||
Never run <code>nibiru migrate --fresh</code> against a production database — it drops every table.
|
||||
</Callout>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: TABLES ============ */}
|
||||
<DCSection id="tables" title="Reference tables">
|
||||
<DCArtboard id="table-dark" label="Reference table — dark" width={780} height={440}>
|
||||
<Frame>
|
||||
<DocTable
|
||||
headers={["Field type", "Renders", "Validation", "Example"]}
|
||||
rows={[
|
||||
["text", "Single-line input", "string", <code>$form->addInputType('text', 'name')</code>],
|
||||
["email", "Email input + envelope icon", "RFC 5322", <code>$form->addInputType('email', 'address')</code>],
|
||||
["password", "Masked input + reveal toggle", "min length", <code>$form->addInputType('password', 'pw')</code>],
|
||||
["select", "Native dropdown", "value-in-set", <code>$form->addInputType('select', 'role')</code>],
|
||||
["file", "Drag-drop uploader", "mime + size", <code>$form->addInputType('file', 'avatar')</code>],
|
||||
["date", "Native date picker", "ISO-8601", <code>$form->addInputType('date', 'dob')</code>],
|
||||
]}
|
||||
/>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: API REFERENCE ============ */}
|
||||
<DCSection id="api" title="API reference blocks">
|
||||
<DCArtboard id="api-block" label="Method signature + params + returns" width={780} height={620}>
|
||||
<Frame>
|
||||
<ApiBlock
|
||||
signature={{
|
||||
name: "Form::addInputType",
|
||||
args: [
|
||||
{ name: "type", type: "string" },
|
||||
{ name: "name", type: "string" },
|
||||
{ name: "options", type: "array" },
|
||||
],
|
||||
returns: "Form",
|
||||
}}
|
||||
params={[
|
||||
{ name: "type", type: "string", required: true, desc: "The input type — one of 28 supported types (text, email, select, file, date, etc.)." },
|
||||
{ name: "name", type: "string", required: true, desc: "Field name. Becomes the form key and the HTML name attribute." },
|
||||
{ name: "options", type: "array", default: "[]", desc: "Field-specific options: validation rules, placeholder, default value, attributes." },
|
||||
]}
|
||||
returns={{ type: "Form", desc: "The form instance, for fluent chaining." }}
|
||||
/>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: CARDS ============ */}
|
||||
<DCSection id="cards" title="Feature card grid">
|
||||
<DCArtboard id="cards-grid" label="Get-started card grid" width={780} height={320}>
|
||||
<Frame>
|
||||
<CardGrid cards={[
|
||||
{
|
||||
title: "Quick Start",
|
||||
desc: "Scaffold, run, and ship your first Nibiru app in 60 seconds.",
|
||||
glow: "linear-gradient(135deg, #b86bff, #ff7ab8)",
|
||||
icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>,
|
||||
},
|
||||
{
|
||||
title: "Modules",
|
||||
desc: "The fourth letter in MMVC — first-class plugins with their own scope.",
|
||||
glow: "linear-gradient(135deg, #6ad9ff, #b86bff)",
|
||||
icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>,
|
||||
},
|
||||
{
|
||||
title: "Routing",
|
||||
desc: "URL-pattern + SEO-URL parsing with automatic action lookup.",
|
||||
glow: "linear-gradient(135deg, #ffb574, #ff7ab8)",
|
||||
icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2"><circle cx="6" cy="19" r="3"/><circle cx="18" cy="5" r="3"/><path d="M6 16V8a4 4 0 0 1 4-4h4M18 8v8a4 4 0 0 1-4 4h-4"/></svg>,
|
||||
},
|
||||
{
|
||||
title: "Database",
|
||||
desc: "MySQL, PostgreSQL, ODBC — one unified Db adapter.",
|
||||
glow: "linear-gradient(135deg, #6ee7b0, #6ad9ff)",
|
||||
icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14a9 3 0 0 0 18 0V5M3 12a9 3 0 0 0 18 0"/></svg>,
|
||||
},
|
||||
]}/>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: SEARCH MODAL ============ */}
|
||||
<DCSection id="search" title="Search modal · ⌘K">
|
||||
<DCArtboard id="search-dark" label="Search modal — dark" width={680} height={580}>
|
||||
<div style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center", background: "rgba(11,4,16,0.85)", padding: 32 }} className="docs-frame cosmic-bg">
|
||||
<SearchModal />
|
||||
</div>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="search-light" label="Search modal — light" width={680} height={580}>
|
||||
<div className="docs-frame theme-light" style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center", background: "rgba(250,246,236,0.7)", padding: 32 }}>
|
||||
<SearchModal />
|
||||
</div>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: PAGINATION + FAB + 404 ============ */}
|
||||
<DCSection id="utility" title="Pagination, floating help, empty states">
|
||||
<DCArtboard id="pagination" label="Page navigation footer" width={780} height={160}>
|
||||
<Frame>
|
||||
<Pagination prev="Quick Start" next="Project Structure" />
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="fab" label="Floating help button" width={300} height={240}>
|
||||
<Frame>
|
||||
<div style={{ position: "absolute", bottom: 32, right: 32 }}>
|
||||
<FAB />
|
||||
</div>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="404" label="404 / off-orbit" width={680} height={620}>
|
||||
<Frame>
|
||||
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||||
<NotFound />
|
||||
</div>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: MOBILE ============ */}
|
||||
<DCSection id="mobile" title="Mobile drawer">
|
||||
<DCArtboard id="drawer-dark" label="Mobile drawer — dark" width={360} height={680}>
|
||||
<div className="docs-frame" style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center", padding: 16, background: "var(--space)" }}>
|
||||
<MobileDrawer />
|
||||
</div>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="drawer-light" label="Mobile drawer — light" width={360} height={680}>
|
||||
<div className="docs-frame theme-light" style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center", padding: 16, background: "var(--space)" }}>
|
||||
<MobileDrawer />
|
||||
</div>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
{/* ============ SECTION: COLOR / TYPE TOKENS ============ */}
|
||||
<DCSection id="tokens" title="Tokens · color & type">
|
||||
<DCArtboard id="palette" label="Cosmic palette" width={920} height={360}>
|
||||
<Frame>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: 12 }}>
|
||||
{[
|
||||
["space", "#0b0410", "Deepest void"],
|
||||
["space-2", "#120822", "Panel surface"],
|
||||
["space-3", "#1a0c2e", "Raised surface"],
|
||||
["plum", "#2a1545", "Nebula plum"],
|
||||
["star", "#f4eedb", "Primary text"],
|
||||
["muted", "#8b85a3", "Tertiary text"],
|
||||
["nebula-mag", "#b86bff", "Accent · links"],
|
||||
["nebula-cyan", "#6ad9ff", "Accent · note"],
|
||||
["nebula-amber","#ffb574", "Accent · warn"],
|
||||
["nebula-rose", "#ff7ab8", "Accent · danger"],
|
||||
["nebula-green","#6ee7b0", "Accent · tip"],
|
||||
["nebula-mag-2","#d8a8ff", "Accent · hover"],
|
||||
].map(([name, hex, desc]) => (
|
||||
<div key={name} style={{ borderRadius: 12, border: "1px solid var(--line)", overflow: "hidden", background: "var(--space-2)" }}>
|
||||
<div style={{ height: 80, background: hex, position: "relative", boxShadow: "inset 0 0 0 1px rgba(255,255,255,0.04)" }}/>
|
||||
<div style={{ padding: "10px 12px" }}>
|
||||
<div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--star)", letterSpacing: "0.04em" }}>--{name}</div>
|
||||
<div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--muted)", marginTop: 2 }}>{hex}</div>
|
||||
<div style={{ fontSize: 11, color: "var(--star-soft)", marginTop: 4 }}>{desc}</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
<DCArtboard id="type" label="Type scale" width={780} height={520}>
|
||||
<Frame>
|
||||
<div className="docs-frame">
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
|
||||
{[
|
||||
["48 · page hero", 48, 600, "Architecture (MMVC)"],
|
||||
["36 · page title", 36, 600, "What is Nibiru?"],
|
||||
["28 · h2", 28, 600, "What's in the box"],
|
||||
["22 · h3", 22, 600, "The Module layer"],
|
||||
["18 · summary", 18, 400, "A modular MVC PHP framework — MMVC."],
|
||||
["16 · body", 16, 400, "Body text uses Inter Tight at 16px with 1.7 leading."],
|
||||
["13 · ui", 13, 500, "Sidebar items, buttons, breadcrumbs"],
|
||||
["11 · mono / kbd", 11, 500, "GET STARTED · ⌘K · ROUTING & DISPATCH"],
|
||||
].map(([label, size, weight, sample]) => (
|
||||
<div key={label} style={{ display: "grid", gridTemplateColumns: "180px 1fr", alignItems: "baseline", gap: 24 }}>
|
||||
<div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--muted)", letterSpacing: "0.06em", textTransform: "uppercase" }}>{label}</div>
|
||||
<div style={{
|
||||
fontFamily: typeof label === "string" && label.includes("mono") ? "var(--font-mono)" : "var(--font-sans)",
|
||||
fontSize: size, fontWeight: weight, color: "var(--star)",
|
||||
letterSpacing: size >= 28 ? "-0.02em" : "0",
|
||||
lineHeight: 1.15,
|
||||
}}>{sample}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Frame>
|
||||
</DCArtboard>
|
||||
</DCSection>
|
||||
|
||||
</DesignCanvas>
|
||||
);
|
||||
}
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user