Files
pi-skill/skills/assets/template-full.html
2026-05-25 16:41:08 +07:00

404 lines
21 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>[PROJECT NAME] Architecture</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* ── Tokens ─────────────────────────────────────────────────── */
:root {
--color-paper: #f5f4ed;
--color-paper-2: #efeee5;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-soft: #65655c;
--color-rule: rgba(11,13,11,0.12);
--color-rule-solid: rgba(135,139,134,0.25);
--color-accent: #f7591f;
--color-accent-tint: rgba(247,89,31,0.08);
--color-link: #1a70c7;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', 'Times New Roman', serif;
--font-mono: 'Geist Mono', ui-monospace, Menlo, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
min-height: 100vh;
padding: 3rem 2rem;
color: var(--color-ink);
}
.container { max-width: 1200px; margin: 0 auto; }
/* ── Header ─────────────────────────────────────────────────── */
.header { margin-bottom: 2.5rem; }
.header-eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.75rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.1;
color: var(--color-ink);
margin-bottom: 0.5rem;
}
.subtitle {
font-family: var(--font-sans);
font-size: 1rem;
line-height: 1.55;
color: var(--color-muted);
max-width: 52ch;
}
/* ── Diagram container ────────────────────────────────────────── */
.diagram-container {
background: var(--color-paper-2);
border-radius: 8px;
border: 1px solid var(--color-rule);
padding: 1.5rem;
overflow-x: auto;
}
svg { width: 100%; min-width: 900px; display: block; }
/* ── Info cards ───────────────────────────────────────────────── */
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
margin-top: 1.5rem;
}
.card {
background: #ffffff;
border-radius: 6px;
border: 1px solid var(--color-rule);
padding: 1.25rem;
}
.card-header {
display: flex;
align-items: center;
gap: 0.6rem;
margin-bottom: 0.875rem;
padding-bottom: 0.875rem;
border-bottom: 1px solid rgba(11,13,11,0.08);
}
.card-dot {
width: 7px; height: 7px;
border-radius: 50%;
flex-shrink: 0;
}
.card-dot.ink { background: var(--color-ink); }
.card-dot.muted { background: var(--color-muted); }
.card-dot.coral { background: var(--color-accent); }
.card-dot.link { background: var(--color-link); }
.card-dot.soft { background: var(--color-soft); }
.card h3 {
font-family: var(--font-sans);
font-size: 0.875rem;
font-weight: 600;
color: var(--color-ink);
letter-spacing: -0.005em;
}
.card ul {
list-style: none;
color: var(--color-muted);
font-size: 0.8125rem;
line-height: 1.55;
}
.card li {
margin-bottom: 0.3rem;
padding-left: 0.875rem;
position: relative;
}
.card li::before {
content: '—';
position: absolute;
left: 0;
color: rgba(11,13,11,0.25);
font-size: 0.75rem;
}
/* ── Footer ─────────────────────────────────────────────────── */
.footer {
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid rgba(11,13,11,0.10);
font-family: var(--font-mono);
font-size: 0.72rem;
letter-spacing: 0.06em;
color: var(--color-soft);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem;
}
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<div class="header">
<p class="header-eyebrow">Architecture · [Date]</p>
<h1>[Project Name]</h1>
<p class="subtitle">[One-sentence description of what this diagram shows.]</p>
</div>
<!-- Main Diagram -->
<div class="diagram-container">
<svg viewBox="0 0 1000 700" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- Dot grid background (matches site .hero-terminal pattern) -->
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<!-- Arrow: muted (default — generic / internal connections) -->
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#52534e"/>
</marker>
<!-- Arrow: coral (accent — primary / highlighted flows) -->
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#f7591f"/>
</marker>
<!-- Arrow: link-blue (#1a70c7 — HTTP/API / external calls) -->
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#1a70c7"/>
</marker>
</defs>
<!-- Background: paper + dot grid -->
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.6"/>
<!-- =================================================================
DRAW ARROWS FIRST — they paint behind boxes (SVG document order).
================================================================= -->
<!-- HTTP/API arrow (link-blue) with label -->
<line x1="130" y1="305" x2="195" y2="305" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<text x="162" y="297" fill="#1a70c7" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.06em">HTTPS</text>
<!-- Generic internal arrow -->
<line x1="310" y1="305" x2="356" y2="305" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Vertical arrow -->
<line x1="253" y1="332" x2="253" y2="376" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Auth / security flow (dashed coral) -->
<path d="M 80 140 L 80 200 Q 80 218 98 218 L 200 218 Q 218 218 218 236 L 218 276"
fill="none" stroke="#f7591f" stroke-width="1.2" stroke-dasharray="5,4"
marker-end="url(#arrow-accent)"/>
<text x="148" y="212" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.06em">JWT</text>
<!-- Primary data flow (coral) -->
<line x1="620" y1="305" x2="696" y2="305" stroke="#f7591f" stroke-width="1.2" marker-end="url(#arrow-accent)"/>
<text x="655" y="297" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.06em">TLS</text>
<!-- =================================================================
COMPONENT BOXES
Pattern: opaque paper rect first (masks arrows), then styled rect.
Mono type labels use Geist Mono — mono is dominant in tool/data.
================================================================= -->
<!-- ── External / User ──────────────────────────────────────── -->
<rect x="30" y="278" width="100" height="54" rx="6" fill="#f5f4ed"/>
<rect x="30" y="278" width="100" height="54" rx="6" fill="rgba(82,83,78,0.10)" stroke="#65655c" stroke-width="1"/>
<!-- Rectangular type tag (not rounded — brand rule) -->
<rect x="38" y="284" width="26" height="12" rx="2" fill="transparent" stroke="rgba(101,101,92,0.4)" stroke-width="0.8"/>
<text x="51" y="293" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXT</text>
<!-- Main label -->
<text x="80" y="308" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Users</text>
<text x="80" y="323" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Browser / Mobile</text>
<!-- ── Security / Auth ──────────────────────────────────────── -->
<rect x="30" y="78" width="100" height="56" rx="6" fill="#f5f4ed"/>
<rect x="30" y="78" width="100" height="56" rx="6" fill="rgba(247,89,31,0.06)" stroke="rgba(247,89,31,0.50)" stroke-width="1"/>
<rect x="38" y="84" width="28" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.40)" stroke-width="0.8"/>
<text x="52" y="93" fill="rgba(247,89,31,0.8)" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.06em">AUTH</text>
<text x="80" y="110" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Auth Provider</text>
<text x="80" y="125" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">OAuth 2.0</text>
<!-- ── Region boundary (dashed) ─────────────────────────────── -->
<rect x="158" y="38" width="822" height="624" rx="8" fill="transparent" stroke="rgba(11,13,11,0.18)" stroke-width="1" stroke-dasharray="6,4"/>
<text x="170" y="55" fill="#52534e" font-size="8" font-weight="500" font-family="'Geist Mono', monospace" letter-spacing="0.12em">AWS REGION · US-WEST-2</text>
<!-- ── Cloud / CDN (with faded watermark numeral — slide card pattern) -->
<rect x="198" y="278" width="112" height="54" rx="6" fill="#f5f4ed"/>
<rect x="198" y="278" width="112" height="54" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<!-- Faded mono watermark numeral (background) -->
<text x="294" y="323" fill="rgba(11,13,11,0.06)" font-size="40" font-weight="600" font-family="'Geist Mono', monospace" text-anchor="end">01</text>
<rect x="206" y="284" width="24" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="218" y="293" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CDN</text>
<text x="254" y="308" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">CloudFront</text>
<text x="254" y="323" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">AWS CDN</text>
<!-- ── Cloud / Storage ───────────────────────────────────────── -->
<rect x="198" y="378" width="112" height="102" rx="6" fill="#f5f4ed"/>
<rect x="198" y="378" width="112" height="102" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="294" y="468" fill="rgba(11,13,11,0.06)" font-size="40" font-weight="600" font-family="'Geist Mono', monospace" text-anchor="end">02</text>
<rect x="206" y="384" width="22" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="217" y="393" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">S3</text>
<text x="254" y="408" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">S3 Buckets</text>
<text x="254" y="426" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">bucket-assets</text>
<text x="254" y="440" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">bucket-uploads</text>
<text x="254" y="466" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">OAI PROTECTED</text>
<!-- ── Security group boundary ───────────────────────────────── -->
<rect x="348" y="264" width="120" height="80" rx="6" fill="transparent" stroke="rgba(247,89,31,0.45)" stroke-width="1" stroke-dasharray="4,4"/>
<text x="356" y="278" fill="rgba(247,89,31,0.7)" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.08em">SG · :443</text>
<!-- ── Load Balancer (inside security group) ──────────────────── -->
<rect x="358" y="282" width="100" height="54" rx="6" fill="#f5f4ed"/>
<rect x="358" y="282" width="100" height="54" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<rect x="366" y="288" width="22" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="377" y="297" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.06em">LB</text>
<text x="408" y="311" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Load Balancer</text>
<text x="408" y="326" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">HTTPS :443</text>
<!-- ── Backend / API ─────────────────────────────────────────── -->
<rect x="508" y="278" width="112" height="54" rx="6" fill="#f5f4ed"/>
<rect x="508" y="278" width="112" height="54" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="516" y="284" width="26" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="529" y="293" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">API</text>
<text x="564" y="308" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">API Server</text>
<text x="564" y="323" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">FastAPI :8000</text>
<!-- ── Database ───────────────────────────────────────────────── -->
<rect x="698" y="278" width="120" height="54" rx="6" fill="#f5f4ed"/>
<rect x="698" y="278" width="120" height="54" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="1"/>
<rect x="706" y="284" width="22" height="12" rx="2" fill="transparent" stroke="rgba(82,83,78,0.50)" stroke-width="0.8"/>
<text x="717" y="293" fill="#52534e" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">DB</text>
<text x="758" y="308" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Database</text>
<text x="758" y="323" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">PostgreSQL</text>
<!-- ── Frontend / UI ─────────────────────────────────────────── -->
<rect x="198" y="518" width="200" height="112" rx="6" fill="#f5f4ed"/>
<rect x="198" y="518" width="200" height="112" rx="6" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<rect x="206" y="524" width="22" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.50)" stroke-width="0.8"/>
<text x="217" y="533" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">UI</text>
<text x="298" y="550" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Web App</text>
<text x="298" y="567" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">React + TypeScript</text>
<text x="298" y="581" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Astro SSG</text>
<!-- Link-blue URL label -->
<text x="298" y="614" fill="#1a70c7" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.04em">app.example.com</text>
<!-- =================================================================
LEGEND — OUTSIDE all boundary boxes.
Region boundary ends at y=662 → legend starts at y=682.
================================================================= -->
<text x="510" y="544" fill="#0b0d0b" font-size="9" font-weight="500" font-family="'Geist Mono', monospace" letter-spacing="0.12em">LEGEND</text>
<rect x="510" y="558" width="14" height="10" rx="2" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="530" y="567" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Frontend / UI</text>
<rect x="510" y="576" width="14" height="10" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="530" y="585" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Backend / API</text>
<rect x="510" y="594" width="14" height="10" rx="2" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="530" y="603" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Cloud / Service</text>
<rect x="510" y="612" width="14" height="10" rx="2" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="1"/>
<text x="530" y="621" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Database</text>
<rect x="510" y="630" width="14" height="10" rx="2" fill="rgba(82,83,78,0.10)" stroke="#65655c" stroke-width="1"/>
<text x="530" y="639" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">External / User</text>
<!-- Arrow types -->
<line x1="510" y1="655" x2="524" y2="655" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<text x="530" y="659" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">HTTP / API call</text>
<line x1="510" y1="671" x2="524" y2="671" stroke="#f7591f" stroke-width="1.2" stroke-dasharray="4,3" marker-end="url(#arrow-accent)"/>
<text x="530" y="675" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Auth flow</text>
<line x1="510" y1="687" x2="524" y2="687" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<text x="530" y="691" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Internal connection</text>
<rect x="510" y="698" width="14" height="10" rx="2" fill="transparent" stroke="rgba(247,89,31,0.45)" stroke-width="1" stroke-dasharray="3,3"/>
<text x="530" y="707" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Security group</text>
</svg>
</div>
<!-- Info Cards -->
<div class="cards">
<div class="card">
<div class="card-header">
<span class="card-dot coral"></span>
<h3>Card Title 1</h3>
</div>
<ul>
<li>Item one</li>
<li>Item two</li>
<li>Item three</li>
<li>Item four</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<span class="card-dot ink"></span>
<h3>Card Title 2</h3>
</div>
<ul>
<li>Item one</li>
<li>Item two</li>
<li>Item three</li>
<li>Item four</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<span class="card-dot muted"></span>
<h3>Card Title 3</h3>
</div>
<ul>
<li>Item one</li>
<li>Item two</li>
<li>Item three</li>
<li>Item four</li>
</ul>
</div>
</div>
<!-- Footer -->
<div class="footer">
<span>[Project Name] · Architecture Overview</span>
<span>[Date]</span>
</div>
</div>
</body>
</html>