feat(studio): twelve more starting points so a name is not stuck with a landing page
The four templates covered a launch page and a link hub. Everyone else — a writer, a restaurant, a shop, a project that ships releases — started from Blank and rebuilt the same scaffolding by hand. These twelve cover the shapes people actually asked for, each one written to be overwritten: plain copy that reads as an instruction, no images to source, no JavaScript to keep working. Every entry now carries its own card text and filter category, and the top-bar list is generated from the map, so adding the thirteenth is one object literal and nothing else.
This commit is contained in:
parent
8227fbd1f8
commit
3d9301d239
1 changed files with 650 additions and 1 deletions
651
js/studio.js
651
js/studio.js
|
|
@ -187,9 +187,23 @@ async function importLive({ confirmIfDirty = true } = {}) {
|
|||
function notice(text) { $("notice-text").textContent = text; $("notice").hidden = false; }
|
||||
|
||||
// ---------- templates ----------
|
||||
// Every entry carries its own card text: `label` and `tag` are what the
|
||||
// picker shows, `cat` is the filter it answers to. The bodies are written to
|
||||
// be thrown away — each line is a prompt for the owner to overwrite — so they
|
||||
// deliberately have no translation entries; the studio's chrome does.
|
||||
//
|
||||
// Class names are prefixed per template (.pf-, .bi-, .rs-, …) so a template
|
||||
// and any sx-* section dropped on top of it never fight over a selector.
|
||||
// Palettes rotate light-neutral / dark-neutral / warm / acid so the gallery
|
||||
// never shows four of the same page in a row.
|
||||
const TEMPLATES = {
|
||||
blank: { html: `<section style="padding:60px 20px;text-align:center"><h1>${esc(name)}</h1><p>Start building.</p></section>`, css: `body{font-family:system-ui,sans-serif;margin:0;color:#111}` },
|
||||
blank: {
|
||||
label: "Blank page", tag: "Start from nothing.", cat: "special",
|
||||
html: `<section style="padding:60px 20px;text-align:center"><h1>${esc(name)}</h1><p>Start building.</p></section>`,
|
||||
css: `body{font-family:system-ui,sans-serif;margin:0;color:#111}`,
|
||||
},
|
||||
landing: {
|
||||
label: "Landing page", tag: "Hero, three features, call to action.", cat: "landing",
|
||||
html: `
|
||||
<header class="hero">
|
||||
<h1>Hello from ${esc(name)}</h1>
|
||||
|
|
@ -215,6 +229,7 @@ body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;col
|
|||
.foot{text-align:center;padding:28px;color:#6a7488;font-size:13px;border-top:1px solid #e6e9f0}`,
|
||||
},
|
||||
profile: {
|
||||
label: "Profile / link hub", tag: "Avatar, bio and a stack of links.", cat: "special",
|
||||
html: `
|
||||
<main class="card">
|
||||
<div class="avatar">★</div>
|
||||
|
|
@ -235,6 +250,7 @@ h1{margin:0 0 6px;font-size:26px}
|
|||
.link:hover{border-color:#d6ff3d}`,
|
||||
},
|
||||
business: {
|
||||
label: "Business one-pager", tag: "About, services, hours, contact.", cat: "business",
|
||||
html: `
|
||||
<nav class="nav"><b>${esc(name)}</b><span><a href="#about">About</a><a href="#services">Services</a><a href="#contact">Contact</a></span></nav>
|
||||
<header class="top"><h1>We are open</h1><p>Say what you do in one sentence.</p></header>
|
||||
|
|
@ -257,6 +273,626 @@ body{margin:0;font-family:Georgia,serif;color:#2b1d12;background:#fff8f0}
|
|||
.grid b{display:block;margin-bottom:6px}
|
||||
.foot{text-align:center;padding:24px;color:#8a6d55;font-size:13px}`,
|
||||
},
|
||||
|
||||
// --- light neutral ---
|
||||
portfolio: {
|
||||
label: "Portfolio", tag: "A grid of work, one line about you.", cat: "landing",
|
||||
html: `
|
||||
<header class="pf-top">
|
||||
<div class="pf-in">
|
||||
<b>${esc(name)}</b>
|
||||
<nav><a href="#work">Work</a><a href="#about">About</a><a href="mailto:">Hire me</a></nav>
|
||||
</div>
|
||||
</header>
|
||||
<section class="pf-hero">
|
||||
<h1>I design things that<br>hold up under use.</h1>
|
||||
<p>Two sentences on what you make and who you make it for. Leave out the adjectives you would not say out loud.</p>
|
||||
</section>
|
||||
<section id="work" class="pf-work">
|
||||
<article class="pf-item"><div class="pf-shot"></div><h3>Project one</h3><p>What it was, what you did, what changed.</p></article>
|
||||
<article class="pf-item"><div class="pf-shot"></div><h3>Project two</h3><p>What it was, what you did, what changed.</p></article>
|
||||
<article class="pf-item"><div class="pf-shot"></div><h3>Project three</h3><p>What it was, what you did, what changed.</p></article>
|
||||
<article class="pf-item"><div class="pf-shot"></div><h3>Project four</h3><p>What it was, what you did, what changed.</p></article>
|
||||
</section>
|
||||
<section id="about" class="pf-about">
|
||||
<h2>About</h2>
|
||||
<p>Where you are, what you use, what you are looking for next. A working email beats a contact form.</p>
|
||||
<a class="pf-mail" href="mailto:">hello@example</a>
|
||||
</section>
|
||||
<footer class="pf-foot">© ${new Date().getFullYear()} ${esc(name)}</footer>`,
|
||||
css: `
|
||||
body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;color:#15181d;background:#fafafa;line-height:1.6}
|
||||
.pf-top{border-bottom:1px solid #e6e7ea;background:#fff}
|
||||
.pf-in{max-width:1040px;margin:0 auto;padding:18px 24px;display:flex;justify-content:space-between;align-items:center}
|
||||
.pf-in b{font-size:16px;letter-spacing:-.01em}
|
||||
.pf-in a{margin-left:20px;color:#5a6069;text-decoration:none;font-size:14px}
|
||||
.pf-in a:hover{color:#15181d}
|
||||
.pf-hero{max-width:1040px;margin:0 auto;padding:88px 24px 56px}
|
||||
.pf-hero h1{font-size:52px;line-height:1.08;letter-spacing:-.025em;margin:0 0 20px;font-weight:600}
|
||||
.pf-hero p{max-width:560px;color:#5a6069;font-size:18px;margin:0}
|
||||
.pf-work{max-width:1040px;margin:0 auto;padding:0 24px 64px;display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:36px 28px}
|
||||
.pf-shot{aspect-ratio:4/3;border-radius:12px;background:linear-gradient(135deg,#eceef1,#dfe2e7);margin-bottom:16px}
|
||||
.pf-item h3{margin:0 0 6px;font-size:18px;font-weight:600}
|
||||
.pf-item p{margin:0;color:#5a6069;font-size:15px}
|
||||
.pf-about{border-top:1px solid #e6e7ea;background:#fff}
|
||||
.pf-about h2{font-size:15px;text-transform:uppercase;letter-spacing:.12em;color:#8b9099;margin:0 0 14px}
|
||||
.pf-about,.pf-about>*{max-width:1040px;margin-left:auto;margin-right:auto}
|
||||
.pf-about{padding:56px 24px}
|
||||
.pf-about p{max-width:620px;margin:0 0 18px;font-size:17px}
|
||||
.pf-mail{color:#15181d;font-weight:600;border-bottom:2px solid #15181d;text-decoration:none;padding-bottom:1px}
|
||||
.pf-foot{max-width:1040px;margin:0 auto;padding:28px 24px;color:#8b9099;font-size:13px}
|
||||
@media(max-width:600px){.pf-hero h1{font-size:34px}.pf-in nav a{margin-left:12px}}`,
|
||||
},
|
||||
"blog-post": {
|
||||
label: "Blog post", tag: "One article — title, byline, body, replies.", cat: "blog",
|
||||
html: `
|
||||
<header class="bp-top"><a href="/">${esc(name)}</a><a href="/archive/">Archive</a></header>
|
||||
<article class="bp">
|
||||
<p class="bp-kicker">Essays</p>
|
||||
<h1>The title goes here, and it can run to two lines</h1>
|
||||
<p class="bp-meta">By an author · ${new Date().toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric" })} · 6 min</p>
|
||||
<p class="bp-lead">The opening paragraph does the work of a subtitle. Say what the reader gets if they stay.</p>
|
||||
<p>A normal paragraph. Long-form type wants a measure of around 70 characters and generous leading — that is what the CSS below is doing, and it is the one thing worth keeping when you rewrite this.</p>
|
||||
<h2>A section heading</h2>
|
||||
<p>Another paragraph. Links look <a href="#">like this</a>, and a phrase can be <em>emphasised</em> or made <strong>strong</strong> without changing the rhythm of the line.</p>
|
||||
<blockquote>A pulled quote earns its indent when it is someone else's sentence, not a louder version of your own.</blockquote>
|
||||
<p>Close on something concrete. What changed, what you would do differently, where the reader goes next.</p>
|
||||
</article>
|
||||
<section class="bp-replies">
|
||||
<h2>Replies</h2>
|
||||
<p class="bp-none">No replies yet.</p>
|
||||
</section>
|
||||
<footer class="bp-foot">© ${new Date().getFullYear()} ${esc(name)}</footer>`,
|
||||
css: `
|
||||
body{margin:0;background:#fffefb;color:#1b1a17;font-family:Georgia,'Times New Roman',serif;line-height:1.7}
|
||||
.bp-top{display:flex;gap:20px;max-width:720px;margin:0 auto;padding:22px 24px;font-family:system-ui,sans-serif;font-size:14px}
|
||||
.bp-top a{color:#6f6a60;text-decoration:none}
|
||||
.bp-top a:first-child{font-weight:600;color:#1b1a17}
|
||||
.bp{max-width:680px;margin:0 auto;padding:20px 24px 56px}
|
||||
.bp-kicker{font-family:system-ui,sans-serif;font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:#b5561f;margin:0 0 14px}
|
||||
.bp h1{font-size:42px;line-height:1.15;letter-spacing:-.015em;margin:0 0 16px}
|
||||
.bp-meta{font-family:system-ui,sans-serif;font-size:14px;color:#8a8579;margin:0 0 32px}
|
||||
.bp-lead{font-size:21px;color:#3d3a34;margin:0 0 28px}
|
||||
.bp p{font-size:18px;margin:0 0 24px}
|
||||
.bp h2{font-size:26px;margin:40px 0 14px;letter-spacing:-.01em}
|
||||
.bp a{color:#b5561f}
|
||||
.bp blockquote{margin:32px 0;padding:4px 0 4px 24px;border-left:3px solid #e6dfd2;color:#57524a;font-style:italic;font-size:19px}
|
||||
.bp-replies{max-width:680px;margin:0 auto;padding:32px 24px;border-top:1px solid #e6dfd2}
|
||||
.bp-replies h2{font-family:system-ui,sans-serif;font-size:14px;letter-spacing:.1em;text-transform:uppercase;color:#8a8579;margin:0 0 12px}
|
||||
.bp-none{color:#8a8579;font-size:16px;margin:0}
|
||||
.bp-foot{max-width:680px;margin:0 auto;padding:24px;color:#a8a294;font-size:13px;font-family:system-ui,sans-serif}
|
||||
@media(max-width:600px){.bp h1{font-size:30px}.bp-lead{font-size:18px}}`,
|
||||
},
|
||||
resume: {
|
||||
label: "Résumé", tag: "One page: skills, history, a way to reach you.", cat: "special",
|
||||
html: `
|
||||
<main class="cv">
|
||||
<header class="cv-head">
|
||||
<div><h1>Your Name</h1><p class="cv-role">What you do · City</p></div>
|
||||
<p class="cv-reach"><a href="mailto:">hello@example</a><br><a href="https://">${esc(name)}</a></p>
|
||||
</header>
|
||||
<section class="cv-sec">
|
||||
<h2>Summary</h2>
|
||||
<p>Three lines at most. What you build, how long you have been doing it, and the kind of problem you want next.</p>
|
||||
</section>
|
||||
<section class="cv-sec">
|
||||
<h2>Skills</h2>
|
||||
<ul class="cv-tags"><li>One</li><li>Two</li><li>Three</li><li>Four</li><li>Five</li><li>Six</li></ul>
|
||||
</section>
|
||||
<section class="cv-sec">
|
||||
<h2>Experience</h2>
|
||||
<div class="cv-row"><b>Role</b><span>Company · 2024 — now</span><p>What you owned and what measurably changed because of it.</p></div>
|
||||
<div class="cv-row"><b>Role</b><span>Company · 2021 — 2024</span><p>What you owned and what measurably changed because of it.</p></div>
|
||||
<div class="cv-row"><b>Role</b><span>Company · 2018 — 2021</span><p>What you owned and what measurably changed because of it.</p></div>
|
||||
</section>
|
||||
<section class="cv-sec">
|
||||
<h2>Education</h2>
|
||||
<div class="cv-row"><b>Degree</b><span>Institution · 2018</span></div>
|
||||
</section>
|
||||
<p class="cv-print">Ctrl/Cmd + P prints this page straight to a PDF — the print rules below drop the shadow and the margins.</p>
|
||||
</main>`,
|
||||
css: `
|
||||
body{margin:0;background:#f4f5f7;color:#15181d;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.6}
|
||||
.cv{max-width:760px;margin:40px auto;background:#fff;padding:48px 52px;border-radius:4px;box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||
.cv-head{display:flex;justify-content:space-between;align-items:flex-start;gap:20px;padding-bottom:24px;border-bottom:2px solid #15181d;margin-bottom:8px}
|
||||
.cv-head h1{margin:0;font-size:32px;letter-spacing:-.02em}
|
||||
.cv-role{margin:4px 0 0;color:#5a6069}
|
||||
.cv-reach{margin:0;text-align:right;font-size:14px;line-height:1.7}
|
||||
.cv-reach a{color:#15181d}
|
||||
.cv-sec{padding:24px 0;border-bottom:1px solid #eceef1}
|
||||
.cv-sec h2{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:#8b9099;margin:0 0 14px}
|
||||
.cv-sec>p{margin:0;max-width:60ch}
|
||||
.cv-tags{list-style:none;display:flex;flex-wrap:wrap;gap:8px;padding:0;margin:0}
|
||||
.cv-tags li{background:#f0f1f4;border-radius:6px;padding:5px 11px;font-size:14px}
|
||||
.cv-row{margin-bottom:18px}
|
||||
.cv-row:last-child{margin-bottom:0}
|
||||
.cv-row b{font-size:16px}
|
||||
.cv-row span{display:block;color:#8b9099;font-size:14px;margin-bottom:5px}
|
||||
.cv-row p{margin:0;color:#41464e;max-width:62ch}
|
||||
.cv-print{margin:24px 0 0;font-size:14px;color:#8b9099}
|
||||
@media print{body{background:#fff}.cv{box-shadow:none;margin:0;padding:0}.cv-print{display:none}}
|
||||
@media(max-width:620px){.cv{margin:0;padding:28px 22px}.cv-head{flex-direction:column}.cv-reach{text-align:left}}`,
|
||||
},
|
||||
|
||||
// --- dark neutral ---
|
||||
"blog-index": {
|
||||
label: "Blog", tag: "A list of posts with tags down the side.", cat: "blog",
|
||||
html: `
|
||||
<header class="bi-top">
|
||||
<div class="bi-in"><b>${esc(name)}</b><nav><a href="/">Posts</a><a href="/about/">About</a><a href="/feed.xml">RSS</a></nav></div>
|
||||
</header>
|
||||
<div class="bi-body">
|
||||
<main class="bi-list">
|
||||
<article class="bi-post"><time>12 September ${new Date().getFullYear()}</time><h2><a href="#">The most recent post</a></h2><p>One or two sentences of the opening, enough to decide whether to click.</p></article>
|
||||
<article class="bi-post"><time>28 August ${new Date().getFullYear()}</time><h2><a href="#">Something else worth writing down</a></h2><p>One or two sentences of the opening, enough to decide whether to click.</p></article>
|
||||
<article class="bi-post"><time>03 August ${new Date().getFullYear()}</time><h2><a href="#">A shorter note</a></h2><p>One or two sentences of the opening, enough to decide whether to click.</p></article>
|
||||
<article class="bi-post"><time>17 July ${new Date().getFullYear()}</time><h2><a href="#">Notes from a thing that broke</a></h2><p>One or two sentences of the opening, enough to decide whether to click.</p></article>
|
||||
</main>
|
||||
<aside class="bi-side">
|
||||
<h3>Tags</h3>
|
||||
<ul class="bi-tags"><li><a href="#">writing</a></li><li><a href="#">bitcoin cash</a></li><li><a href="#">self-hosting</a></li><li><a href="#">sia</a></li><li><a href="#">notes</a></li></ul>
|
||||
<h3>Elsewhere</h3>
|
||||
<ul class="bi-tags"><li><a href="https://">Nostr</a></li><li><a href="mailto:">Email</a></li></ul>
|
||||
</aside>
|
||||
</div>
|
||||
<footer class="bi-foot">© ${new Date().getFullYear()} ${esc(name)} · no trackers, no newsletter pop-up</footer>`,
|
||||
css: `
|
||||
body{margin:0;background:#0d1015;color:#e3e6eb;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.65}
|
||||
a{color:#e3e6eb}
|
||||
.bi-top{border-bottom:1px solid #1f242c}
|
||||
.bi-in{max-width:980px;margin:0 auto;padding:20px 24px;display:flex;justify-content:space-between;align-items:center}
|
||||
.bi-in b{font-size:16px}
|
||||
.bi-in a{margin-left:20px;color:#8d96a5;text-decoration:none;font-size:14px}
|
||||
.bi-in a:hover{color:#fff}
|
||||
.bi-body{max-width:980px;margin:0 auto;padding:48px 24px;display:grid;grid-template-columns:1fr 220px;gap:56px;align-items:start}
|
||||
.bi-post{padding-bottom:30px;margin-bottom:30px;border-bottom:1px solid #1f242c}
|
||||
.bi-post:last-child{border:0;margin:0;padding:0}
|
||||
.bi-post time{font-size:13px;color:#6d7787;letter-spacing:.02em}
|
||||
.bi-post h2{margin:6px 0 8px;font-size:24px;letter-spacing:-.015em;line-height:1.25}
|
||||
.bi-post h2 a{text-decoration:none}
|
||||
.bi-post h2 a:hover{color:#8ab4ff}
|
||||
.bi-post p{margin:0;color:#98a1b0}
|
||||
.bi-side h3{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:#6d7787;margin:0 0 12px}
|
||||
.bi-side h3+ul+h3{margin-top:28px}
|
||||
.bi-tags{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:7px}
|
||||
.bi-tags a{display:inline-block;background:#161b22;border:1px solid #232933;border-radius:6px;padding:4px 10px;font-size:13px;color:#98a1b0;text-decoration:none}
|
||||
.bi-tags a:hover{border-color:#3a434f;color:#fff}
|
||||
.bi-foot{border-top:1px solid #1f242c;padding:24px;text-align:center;color:#6d7787;font-size:13px}
|
||||
@media(max-width:760px){.bi-body{grid-template-columns:1fr;gap:40px}}`,
|
||||
},
|
||||
docs: {
|
||||
label: "Documentation", tag: "Sidebar contents, one long article.", cat: "special",
|
||||
html: `
|
||||
<header class="dc-top"><b>${esc(name)} docs</b><input class="dc-find" type="search" placeholder="Search (wire this up later)"></header>
|
||||
<div class="dc-body">
|
||||
<nav class="dc-nav">
|
||||
<h4>Getting started</h4>
|
||||
<a class="on" href="#install">Install</a><a href="#config">Configure</a><a href="#first">First run</a>
|
||||
<h4>Reference</h4>
|
||||
<a href="#cli">Commands</a><a href="#api">HTTP API</a><a href="#errors">Errors</a>
|
||||
<h4>Help</h4>
|
||||
<a href="#faq">FAQ</a>
|
||||
</nav>
|
||||
<main class="dc-main">
|
||||
<h1 id="install">Install</h1>
|
||||
<p>One paragraph saying what the reader is about to do and how long it takes. Then the command.</p>
|
||||
<pre class="dc-pre"><code>curl -fsSL https://${esc(name)}/install.sh | sh</code></pre>
|
||||
<h2 id="config">Configure</h2>
|
||||
<p>What to edit and where it lives. Say what the defaults are so most readers can stop here.</p>
|
||||
<table class="dc-tab"><thead><tr><th>Key</th><th>Default</th><th>What it does</th></tr></thead>
|
||||
<tbody><tr><td>port</td><td>8080</td><td>Where it listens.</td></tr><tr><td>data_dir</td><td>./data</td><td>Where state is kept.</td></tr><tr><td>log_level</td><td>info</td><td>How loud it is.</td></tr></tbody></table>
|
||||
<h2 id="first">First run</h2>
|
||||
<p>The happy path, end to end, with the output the reader should actually see.</p>
|
||||
<div class="dc-note"><b>Note</b> Anything that will bite a reader at 2am goes in a box like this one.</div>
|
||||
</main>
|
||||
</div>`,
|
||||
css: `
|
||||
body{margin:0;background:#0f1216;color:#dfe3e9;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.7}
|
||||
.dc-top{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:14px 22px;border-bottom:1px solid #1d222a;background:#0b0e12;position:sticky;top:0}
|
||||
.dc-top b{font-size:15px}
|
||||
.dc-find{background:#151a21;border:1px solid #252b35;border-radius:8px;padding:7px 12px;color:#dfe3e9;font:inherit;font-size:13px;width:min(280px,45vw)}
|
||||
.dc-body{display:grid;grid-template-columns:230px 1fr;max-width:1120px;margin:0 auto}
|
||||
.dc-nav{padding:28px 18px;border-right:1px solid #1d222a;position:sticky;top:57px;align-self:start;max-height:calc(100vh - 57px);overflow:auto}
|
||||
.dc-nav h4{font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:#68727f;margin:22px 0 8px}
|
||||
.dc-nav h4:first-child{margin-top:0}
|
||||
.dc-nav a{display:block;padding:5px 10px;border-radius:7px;color:#98a1af;text-decoration:none;font-size:14px}
|
||||
.dc-nav a:hover{background:#151a21;color:#fff}
|
||||
.dc-nav a.on{background:#1b2230;color:#8ab4ff}
|
||||
.dc-main{padding:36px 40px 80px;max-width:760px}
|
||||
.dc-main h1{font-size:34px;letter-spacing:-.02em;margin:0 0 14px}
|
||||
.dc-main h2{font-size:23px;letter-spacing:-.01em;margin:44px 0 12px;padding-top:12px;border-top:1px solid #1d222a}
|
||||
.dc-main p{color:#aeb6c2;margin:0 0 18px}
|
||||
.dc-pre{background:#0a0d11;border:1px solid #1d222a;border-radius:10px;padding:14px 16px;overflow:auto;font-size:13.5px;color:#a7e3b0}
|
||||
.dc-tab{width:100%;border-collapse:collapse;font-size:14px;margin:0 0 18px}
|
||||
.dc-tab th{text-align:left;color:#68727f;font-weight:600;font-size:12px;letter-spacing:.08em;text-transform:uppercase;padding:0 12px 8px 0;border-bottom:1px solid #1d222a}
|
||||
.dc-tab td{padding:9px 12px 9px 0;border-bottom:1px solid #161b22;color:#aeb6c2}
|
||||
.dc-note{border-left:3px solid #8ab4ff;background:#131a26;border-radius:0 8px 8px 0;padding:12px 16px;color:#aeb6c2;font-size:14.5px}
|
||||
.dc-note b{color:#8ab4ff;margin-right:6px}
|
||||
@media(max-width:820px){.dc-body{grid-template-columns:1fr}.dc-nav{position:static;max-height:none;border-right:0;border-bottom:1px solid #1d222a}.dc-main{padding:28px 22px 64px}}`,
|
||||
},
|
||||
agency: {
|
||||
label: "Agency", tag: "Case studies, services, the people behind them.", cat: "business",
|
||||
html: `
|
||||
<header class="ag-top"><div class="ag-in"><b>${esc(name)}</b><nav><a href="#work">Work</a><a href="#services">Services</a><a href="#team">Team</a><a class="ag-cta" href="#contact">Start a project</a></nav></div></header>
|
||||
<section class="ag-hero">
|
||||
<h1>We take the awkward half of the problem.</h1>
|
||||
<p>One sentence on what you do, one on who for. Resist listing technologies here — the work below does that better.</p>
|
||||
</section>
|
||||
<section id="work" class="ag-work">
|
||||
<h2 class="ag-lab">Selected work</h2>
|
||||
<div class="ag-cases">
|
||||
<a class="ag-case" href="#"><div class="ag-shot"></div><h3>Client one</h3><p>The thing that was broken, and the number that moved.</p></a>
|
||||
<a class="ag-case" href="#"><div class="ag-shot"></div><h3>Client two</h3><p>The thing that was broken, and the number that moved.</p></a>
|
||||
<a class="ag-case" href="#"><div class="ag-shot"></div><h3>Client three</h3><p>The thing that was broken, and the number that moved.</p></a>
|
||||
</div>
|
||||
</section>
|
||||
<section id="services" class="ag-serv">
|
||||
<h2 class="ag-lab">What we do</h2>
|
||||
<div class="ag-grid">
|
||||
<div><b>Strategy</b><p>Deciding what not to build.</p></div>
|
||||
<div><b>Design</b><p>Interfaces that survive a real user.</p></div>
|
||||
<div><b>Engineering</b><p>Shipping it, then keeping it up.</p></div>
|
||||
<div><b>Support</b><p>Being reachable after launch.</p></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="team" class="ag-team">
|
||||
<h2 class="ag-lab">Who you would work with</h2>
|
||||
<div class="ag-people"><div><span class="ag-face"></span><b>A. Person</b><i>Partner</i></div><div><span class="ag-face"></span><b>B. Person</b><i>Design</i></div><div><span class="ag-face"></span><b>C. Person</b><i>Engineering</i></div></div>
|
||||
</section>
|
||||
<footer id="contact" class="ag-foot"><h2>Tell us what is stuck.</h2><a class="ag-cta big" href="mailto:">hello@example</a><p>© ${new Date().getFullYear()} ${esc(name)}</p></footer>`,
|
||||
css: `
|
||||
body{margin:0;background:#101114;color:#eceef2;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.6}
|
||||
.ag-top{border-bottom:1px solid #1e2026}
|
||||
.ag-in{max-width:1080px;margin:0 auto;padding:18px 24px;display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap}
|
||||
.ag-in b{font-size:16px}
|
||||
.ag-in a{margin-left:22px;color:#9aa0ad;text-decoration:none;font-size:14px}
|
||||
.ag-in a:hover{color:#fff}
|
||||
.ag-cta{background:#eceef2;color:#101114 !important;padding:8px 16px;border-radius:999px;font-weight:600}
|
||||
.ag-hero{max-width:1080px;margin:0 auto;padding:96px 24px 72px}
|
||||
.ag-hero h1{font-size:56px;line-height:1.05;letter-spacing:-.03em;margin:0 0 20px;max-width:14ch}
|
||||
.ag-hero p{max-width:540px;color:#9aa0ad;font-size:18px;margin:0}
|
||||
.ag-lab{font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:#6a7280;margin:0 0 24px;font-weight:600}
|
||||
.ag-work,.ag-serv,.ag-team{max-width:1080px;margin:0 auto;padding:56px 24px;border-top:1px solid #1e2026}
|
||||
.ag-cases{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:28px}
|
||||
.ag-case{text-decoration:none;color:inherit}
|
||||
.ag-shot{aspect-ratio:16/10;border-radius:10px;background:linear-gradient(135deg,#1c1f26,#272b34);margin-bottom:14px}
|
||||
.ag-case h3{margin:0 0 5px;font-size:18px}
|
||||
.ag-case p{margin:0;color:#9aa0ad;font-size:15px}
|
||||
.ag-case:hover .ag-shot{background:linear-gradient(135deg,#242832,#333844)}
|
||||
.ag-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:28px}
|
||||
.ag-grid b{display:block;margin-bottom:5px;font-size:17px}
|
||||
.ag-grid p{margin:0;color:#9aa0ad;font-size:15px}
|
||||
.ag-people{display:flex;gap:40px;flex-wrap:wrap}
|
||||
.ag-face{display:block;width:72px;height:72px;border-radius:50%;background:#272b34;margin-bottom:10px}
|
||||
.ag-people b{display:block;font-size:15px}
|
||||
.ag-people i{color:#6a7280;font-size:13.5px;font-style:normal}
|
||||
.ag-foot{border-top:1px solid #1e2026;text-align:center;padding:72px 24px 40px}
|
||||
.ag-foot h2{font-size:38px;letter-spacing:-.02em;margin:0 0 24px}
|
||||
.ag-cta.big{display:inline-block;margin-left:0;padding:13px 26px;font-size:16px}
|
||||
.ag-foot p{color:#6a7280;font-size:13px;margin:40px 0 0}
|
||||
@media(max-width:640px){.ag-hero{padding:56px 24px 40px}.ag-hero h1{font-size:36px}.ag-foot h2{font-size:26px}.ag-in nav a{margin-left:14px}}`,
|
||||
},
|
||||
|
||||
// --- warm ---
|
||||
restaurant: {
|
||||
label: "Restaurant", tag: "Menu, hours, the address, a table.", cat: "business",
|
||||
html: `
|
||||
<header class="rs-hero">
|
||||
<p class="rs-kick">Since ${new Date().getFullYear() - 7}</p>
|
||||
<h1>${esc(name)}</h1>
|
||||
<p class="rs-sub">Small kitchen, short menu, everything cooked the day you eat it.</p>
|
||||
<a class="rs-btn" href="#book">Book a table</a>
|
||||
</header>
|
||||
<section class="rs-menu">
|
||||
<h2>Menu</h2>
|
||||
<div class="rs-cols">
|
||||
<div>
|
||||
<h3>To start</h3>
|
||||
<div class="rs-item"><span>Bread, olive oil, salt</span><b>4</b></div>
|
||||
<div class="rs-item"><span>Soup of the day</span><b>7</b></div>
|
||||
<div class="rs-item"><span>Grilled vegetables, yoghurt</span><b>9</b></div>
|
||||
<h3>Mains</h3>
|
||||
<div class="rs-item"><span>Fish of the day</span><b>19</b></div>
|
||||
<div class="rs-item"><span>Slow lamb, beans</span><b>21</b></div>
|
||||
<div class="rs-item"><span>Mushroom orzo</span><b>16</b></div>
|
||||
</div>
|
||||
<div>
|
||||
<h3>Sweet</h3>
|
||||
<div class="rs-item"><span>Yoghurt, honey, walnut</span><b>6</b></div>
|
||||
<div class="rs-item"><span>Chocolate, olive oil</span><b>7</b></div>
|
||||
<h3>To drink</h3>
|
||||
<div class="rs-item"><span>House red, glass</span><b>5</b></div>
|
||||
<div class="rs-item"><span>House white, glass</span><b>5</b></div>
|
||||
<div class="rs-item"><span>Coffee</span><b>3</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="rs-fine">Prices include tax. Tell us about allergies when you book — the menu changes weekly.</p>
|
||||
</section>
|
||||
<section class="rs-when">
|
||||
<div><h3>Hours</h3><p>Tuesday – Saturday<br>18:00 – 23:00<br>Sunday lunch 13:00 – 16:00<br>Closed Monday</p></div>
|
||||
<div><h3>Where</h3><p>Street 1<br>City<br><a href="https://">Open in maps →</a></p></div>
|
||||
<div id="book"><h3>Book</h3><p><a class="rs-btn small" href="tel:">Call us</a><br><a href="mailto:">Or send an email</a></p></div>
|
||||
</section>
|
||||
<footer class="rs-foot">© ${new Date().getFullYear()} ${esc(name)}</footer>`,
|
||||
css: `
|
||||
body{margin:0;background:#fdf6ec;color:#3a2a1c;font-family:Georgia,'Times New Roman',serif;line-height:1.65}
|
||||
.rs-hero{text-align:center;padding:88px 24px 72px;background:#5c2f16;color:#fdf6ec}
|
||||
.rs-kick{letter-spacing:.24em;text-transform:uppercase;font-size:11px;margin:0 0 16px;color:#d9a86c;font-family:system-ui,sans-serif}
|
||||
.rs-hero h1{font-size:54px;margin:0 0 14px;letter-spacing:.01em;font-weight:400}
|
||||
.rs-sub{max-width:460px;margin:0 auto 28px;color:#e8cfb3;font-size:17px}
|
||||
.rs-btn{display:inline-block;background:#d9a86c;color:#3a2a1c;padding:12px 26px;border-radius:2px;text-decoration:none;font-family:system-ui,sans-serif;font-weight:600;font-size:14px;letter-spacing:.04em}
|
||||
.rs-btn.small{padding:9px 18px;font-size:13px;margin-bottom:8px}
|
||||
.rs-menu{max-width:860px;margin:0 auto;padding:64px 24px 48px}
|
||||
.rs-menu h2{text-align:center;font-size:13px;letter-spacing:.2em;text-transform:uppercase;color:#9a7550;font-family:system-ui,sans-serif;margin:0 0 36px;font-weight:600}
|
||||
.rs-cols{display:grid;grid-template-columns:1fr 1fr;gap:20px 56px}
|
||||
.rs-cols h3{font-size:20px;font-weight:400;margin:28px 0 12px;font-style:italic;color:#5c2f16}
|
||||
.rs-cols h3:first-child{margin-top:0}
|
||||
.rs-item{display:flex;justify-content:space-between;align-items:baseline;gap:12px;padding:6px 0;border-bottom:1px dotted #d8c3a8}
|
||||
.rs-item b{font-weight:400;color:#9a7550}
|
||||
.rs-fine{text-align:center;color:#9a7550;font-size:14px;margin:36px 0 0;font-family:system-ui,sans-serif}
|
||||
.rs-when{max-width:860px;margin:0 auto;padding:40px 24px 64px;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:36px;border-top:1px solid #e6d5bf}
|
||||
.rs-when h3{font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:#9a7550;font-family:system-ui,sans-serif;margin:0 0 10px}
|
||||
.rs-when p{margin:0}
|
||||
.rs-when a{color:#5c2f16}
|
||||
.rs-foot{text-align:center;padding:24px;background:#5c2f16;color:#c9a883;font-size:13px;font-family:system-ui,sans-serif}
|
||||
@media(max-width:620px){.rs-hero h1{font-size:38px}.rs-cols{grid-template-columns:1fr;gap:0}}`,
|
||||
},
|
||||
event: {
|
||||
label: "Event", tag: "Date, venue, agenda, speakers, RSVP.", cat: "business",
|
||||
html: `
|
||||
<header class="ev-top">
|
||||
<p class="ev-date">14 November ${new Date().getFullYear()} · City</p>
|
||||
<h1>A one-day thing<br>worth travelling for</h1>
|
||||
<p class="ev-sub">Eight talks, one room, no parallel tracks. Lunch is included and the coffee is good.</p>
|
||||
<a class="ev-btn" href="#rsvp">Reserve a seat</a>
|
||||
<p class="ev-left">62 of 120 seats left</p>
|
||||
</header>
|
||||
<section class="ev-sec">
|
||||
<h2>Agenda</h2>
|
||||
<div class="ev-line"><time>09:30</time><div><b>Doors and coffee</b><p>Come early, the good seats go first.</p></div></div>
|
||||
<div class="ev-line"><time>10:00</time><div><b>Opening talk</b><p>Speaker name — the title of the talk.</p></div></div>
|
||||
<div class="ev-line"><time>11:15</time><div><b>Second talk</b><p>Speaker name — the title of the talk.</p></div></div>
|
||||
<div class="ev-line"><time>12:30</time><div><b>Lunch</b><p>Included. Say what you cannot eat when you RSVP.</p></div></div>
|
||||
<div class="ev-line"><time>14:00</time><div><b>Workshops</b><p>Three rooms, pick one on the day.</p></div></div>
|
||||
<div class="ev-line"><time>17:00</time><div><b>Close and drinks</b><p>Around the corner, on us.</p></div></div>
|
||||
</section>
|
||||
<section class="ev-sec alt">
|
||||
<h2>Speakers</h2>
|
||||
<div class="ev-spk"><div><span class="ev-face"></span><b>A. Person</b><i>What they work on</i></div><div><span class="ev-face"></span><b>B. Person</b><i>What they work on</i></div><div><span class="ev-face"></span><b>C. Person</b><i>What they work on</i></div><div><span class="ev-face"></span><b>D. Person</b><i>What they work on</i></div></div>
|
||||
</section>
|
||||
<section id="rsvp" class="ev-sec">
|
||||
<h2>RSVP</h2>
|
||||
<form class="ev-form" method="post">
|
||||
<input type="text" name="name" placeholder="Your name" required>
|
||||
<input type="email" name="email" placeholder="Email" required>
|
||||
<input type="text" name="diet" placeholder="Anything you cannot eat">
|
||||
<button type="submit" class="ev-btn">Hold my seat</button>
|
||||
</form>
|
||||
<p class="ev-fine">This form needs somewhere to post to. Until you set one up, put an email address here instead.</p>
|
||||
</section>
|
||||
<footer class="ev-foot">${esc(name)} · Venue, Street 1, City · © ${new Date().getFullYear()}</footer>`,
|
||||
css: `
|
||||
body{margin:0;background:#fff9f2;color:#2f2418;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.6}
|
||||
.ev-top{text-align:center;padding:80px 24px 64px;background:linear-gradient(160deg,#c2410c,#7c2d12);color:#fff4e8}
|
||||
.ev-date{letter-spacing:.18em;text-transform:uppercase;font-size:12px;margin:0 0 18px;color:#fdba74}
|
||||
.ev-top h1{font-size:50px;line-height:1.08;letter-spacing:-.02em;margin:0 0 18px;font-weight:700}
|
||||
.ev-sub{max-width:520px;margin:0 auto 30px;color:#fed7aa;font-size:17px}
|
||||
.ev-btn{display:inline-block;background:#fff4e8;color:#7c2d12;padding:13px 28px;border-radius:10px;text-decoration:none;font-weight:700;border:0;font:inherit;font-weight:700;cursor:pointer}
|
||||
.ev-left{margin:14px 0 0;font-size:13px;color:#fdba74}
|
||||
.ev-sec{max-width:760px;margin:0 auto;padding:56px 24px}
|
||||
.ev-sec.alt{max-width:none;background:#fdefe0}
|
||||
.ev-sec.alt>*{max-width:760px;margin-left:auto;margin-right:auto}
|
||||
.ev-sec h2{font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:#a16207;margin:0 0 24px}
|
||||
.ev-line{display:grid;grid-template-columns:78px 1fr;gap:18px;padding:14px 0;border-top:1px solid #f0dcc6}
|
||||
.ev-line time{color:#c2410c;font-weight:700;font-size:15px;font-variant-numeric:tabular-nums}
|
||||
.ev-line b{display:block;font-size:16px}
|
||||
.ev-line p{margin:2px 0 0;color:#6b5844;font-size:15px}
|
||||
.ev-spk{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:28px}
|
||||
.ev-face{display:block;width:76px;height:76px;border-radius:50%;background:#f3ddc4;margin-bottom:10px}
|
||||
.ev-spk b{display:block;font-size:15px}
|
||||
.ev-spk i{font-style:normal;color:#8a7358;font-size:13.5px}
|
||||
.ev-form{display:grid;gap:10px;max-width:420px}
|
||||
.ev-form input{padding:12px 14px;border:1px solid #e6d3ba;border-radius:10px;font:inherit;background:#fff}
|
||||
.ev-form input:focus{outline:2px solid #c2410c;outline-offset:1px}
|
||||
.ev-form .ev-btn{background:#c2410c;color:#fff4e8;justify-self:start}
|
||||
.ev-fine{color:#8a7358;font-size:13.5px;margin:14px 0 0;max-width:420px}
|
||||
.ev-foot{text-align:center;padding:26px;background:#7c2d12;color:#fdba74;font-size:13px}
|
||||
@media(max-width:620px){.ev-top h1{font-size:34px}.ev-line{grid-template-columns:64px 1fr;gap:12px}}`,
|
||||
},
|
||||
newsletter: {
|
||||
label: "Newsletter", tag: "One promise, one field, the back issues.", cat: "landing",
|
||||
html: `
|
||||
<main class="nl">
|
||||
<header class="nl-head">
|
||||
<p class="nl-kick">${esc(name)}</p>
|
||||
<h1>One letter a week about the thing you actually care about.</h1>
|
||||
<p class="nl-sub">Say what is in it and how often it lands. Then say what you will never do with the address — people read that line.</p>
|
||||
<form class="nl-form" method="post">
|
||||
<input type="email" name="email" placeholder="you@example" required>
|
||||
<button type="submit">Subscribe</button>
|
||||
</form>
|
||||
<p class="nl-fine">No tracking pixels. Unsubscribe from the bottom of any issue.</p>
|
||||
</header>
|
||||
<section class="nl-past">
|
||||
<h2>Past issues</h2>
|
||||
<a class="nl-item" href="#"><b>#014 — The title of the issue</b><span>12 September ${new Date().getFullYear()}</span><p>The one-line summary that makes the archive worth scrolling.</p></a>
|
||||
<a class="nl-item" href="#"><b>#013 — Another title</b><span>05 September ${new Date().getFullYear()}</span><p>The one-line summary that makes the archive worth scrolling.</p></a>
|
||||
<a class="nl-item" href="#"><b>#012 — And another</b><span>29 August ${new Date().getFullYear()}</span><p>The one-line summary that makes the archive worth scrolling.</p></a>
|
||||
</section>
|
||||
<footer class="nl-foot">© ${new Date().getFullYear()} ${esc(name)} · <a href="mailto:">write back</a></footer>
|
||||
</main>`,
|
||||
css: `
|
||||
body{margin:0;background:#fbf3e9;color:#2e261c;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.65}
|
||||
.nl{max-width:620px;margin:0 auto;padding:0 24px}
|
||||
.nl-head{padding:88px 0 56px}
|
||||
.nl-kick{font-family:Georgia,serif;font-style:italic;color:#a8743a;margin:0 0 20px;font-size:17px}
|
||||
.nl-head h1{font-size:40px;line-height:1.18;letter-spacing:-.02em;margin:0 0 20px;font-weight:700}
|
||||
.nl-sub{color:#6d5d49;font-size:17px;margin:0 0 28px}
|
||||
.nl-form{display:flex;gap:8px;flex-wrap:wrap}
|
||||
.nl-form input{flex:1;min-width:200px;padding:14px 16px;border:1px solid #ddc9ab;border-radius:10px;font:inherit;background:#fff}
|
||||
.nl-form input:focus{outline:2px solid #a8743a;outline-offset:1px}
|
||||
.nl-form button{padding:14px 24px;border:0;border-radius:10px;background:#2e261c;color:#fbf3e9;font:inherit;font-weight:600;cursor:pointer}
|
||||
.nl-form button:hover{background:#4a3d2d}
|
||||
.nl-fine{color:#8b7c66;font-size:13.5px;margin:14px 0 0}
|
||||
.nl-past{padding:8px 0 48px;border-top:1px solid #e8d8c0}
|
||||
.nl-past h2{font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:#a08a6c;margin:32px 0 18px}
|
||||
.nl-item{display:block;text-decoration:none;color:inherit;padding:16px 0;border-bottom:1px solid #eee1cd}
|
||||
.nl-item b{display:block;font-size:17px;margin-bottom:2px}
|
||||
.nl-item span{display:block;font-size:13px;color:#a08a6c;margin-bottom:6px}
|
||||
.nl-item p{margin:0;color:#6d5d49;font-size:15px}
|
||||
.nl-item:hover b{color:#a8743a}
|
||||
.nl-foot{padding:28px 0 40px;color:#a08a6c;font-size:13px}
|
||||
.nl-foot a{color:#a8743a}
|
||||
@media(max-width:560px){.nl-head{padding:56px 0 40px}.nl-head h1{font-size:30px}}`,
|
||||
},
|
||||
|
||||
// --- acid ---
|
||||
"shop-lite": {
|
||||
label: "Small shop", tag: "A few products, paid to your own address.", cat: "business",
|
||||
html: `
|
||||
<header class="sh-top"><b>${esc(name)}</b><span class="sh-pay">Paid in Bitcoin Cash · straight to your wallet</span></header>
|
||||
<section class="sh-hero"><h1>Four things worth making.</h1><p>Say what you sell and why you make it. One honest paragraph beats a carousel.</p></section>
|
||||
<section class="sh-grid">
|
||||
<article class="sh-card"><div class="sh-img"></div><h3>Product one</h3><p>What it is, what it is made of, how big it is.</p><div class="sh-buy"><b>0.05 BCH</b><a class="sh-btn" href="bitcoincash:">Pay</a></div></article>
|
||||
<article class="sh-card"><div class="sh-img"></div><h3>Product two</h3><p>What it is, what it is made of, how big it is.</p><div class="sh-buy"><b>0.08 BCH</b><a class="sh-btn" href="bitcoincash:">Pay</a></div></article>
|
||||
<article class="sh-card"><div class="sh-img"></div><h3>Product three</h3><p>What it is, what it is made of, how big it is.</p><div class="sh-buy"><b>0.12 BCH</b><a class="sh-btn" href="bitcoincash:">Pay</a></div></article>
|
||||
<article class="sh-card"><div class="sh-img"></div><h3>Product four</h3><p>What it is, what it is made of, how big it is.</p><div class="sh-buy"><b>0.20 BCH</b><a class="sh-btn" href="bitcoincash:">Pay</a></div></article>
|
||||
</section>
|
||||
<section class="sh-how">
|
||||
<h2>How ordering works</h2>
|
||||
<ol><li>Tap Pay — your wallet opens with the address and amount filled in.</li><li>Send the payment, then email the transaction id and where it should go.</li><li>It ships within three working days, tracked.</li></ol>
|
||||
<p class="sh-note">Put your real cashaddr in each Pay link (<code>bitcoincash:q…?amount=0.05</code>) and a real address to email. No checkout server, no card fees, no chargebacks — and no refunds unless you offer them, so say what you do.</p>
|
||||
</section>
|
||||
<footer class="sh-foot">© ${new Date().getFullYear()} ${esc(name)} · <a href="mailto:">orders@example</a></footer>`,
|
||||
css: `
|
||||
body{margin:0;background:#0a0c08;color:#eef3e4;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.6}
|
||||
.sh-top{display:flex;justify-content:space-between;align-items:center;gap:14px;flex-wrap:wrap;padding:16px 26px;border-bottom:1px solid #1d2417}
|
||||
.sh-top b{font-size:16px}
|
||||
.sh-pay{font-size:12.5px;color:#c6ff4a;letter-spacing:.02em}
|
||||
.sh-hero{max-width:900px;margin:0 auto;padding:72px 24px 44px}
|
||||
.sh-hero h1{font-size:46px;letter-spacing:-.025em;line-height:1.08;margin:0 0 16px}
|
||||
.sh-hero p{max-width:520px;color:#9caa8c;font-size:17px;margin:0}
|
||||
.sh-grid{max-width:900px;margin:0 auto;padding:0 24px 56px;display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:22px}
|
||||
.sh-card{background:#11150d;border:1px solid #1d2417;border-radius:14px;padding:16px}
|
||||
.sh-img{aspect-ratio:1;border-radius:10px;background:linear-gradient(135deg,#1a2012,#242c19);margin-bottom:14px}
|
||||
.sh-card h3{margin:0 0 5px;font-size:17px}
|
||||
.sh-card p{margin:0 0 14px;color:#9caa8c;font-size:14.5px}
|
||||
.sh-buy{display:flex;justify-content:space-between;align-items:center;gap:10px}
|
||||
.sh-buy b{color:#c6ff4a;font-size:15px;font-variant-numeric:tabular-nums}
|
||||
.sh-btn{background:#c6ff4a;color:#0a0c08;text-decoration:none;font-weight:700;font-size:13.5px;padding:8px 16px;border-radius:8px}
|
||||
.sh-btn:hover{background:#d9ff7e}
|
||||
.sh-how{max-width:900px;margin:0 auto;padding:40px 24px 64px;border-top:1px solid #1d2417}
|
||||
.sh-how h2{font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:#6f7d60;margin:0 0 18px}
|
||||
.sh-how ol{margin:0 0 20px;padding-left:20px;color:#c3cdb7;max-width:62ch}
|
||||
.sh-how li{margin-bottom:7px}
|
||||
.sh-note{color:#7f8d70;font-size:14px;margin:0;max-width:66ch}
|
||||
.sh-note code{background:#11150d;border:1px solid #1d2417;border-radius:5px;padding:1px 6px;font-size:12.5px;color:#c6ff4a}
|
||||
.sh-foot{padding:24px;text-align:center;color:#6f7d60;font-size:13px;border-top:1px solid #1d2417}
|
||||
.sh-foot a{color:#9caa8c}
|
||||
@media(max-width:560px){.sh-hero{padding:48px 24px 32px}.sh-hero h1{font-size:32px}}`,
|
||||
},
|
||||
"coming-soon": {
|
||||
label: "Coming soon", tag: "A date, a way to be told, nothing else.", cat: "landing",
|
||||
html: `
|
||||
<main class="cs">
|
||||
<p class="cs-kick">${esc(name)}</p>
|
||||
<h1>Something is being built here.</h1>
|
||||
<p class="cs-sub">One sentence on what it is. One on when. Vagueness reads as vapour, so give a real month.</p>
|
||||
<div class="cs-clock">
|
||||
<div><b>14</b><span>days</span></div>
|
||||
<div><b>06</b><span>hours</span></div>
|
||||
<div><b>32</b><span>minutes</span></div>
|
||||
<div><b>09</b><span>seconds</span></div>
|
||||
</div>
|
||||
<p class="cs-when">Opening 14 November ${new Date().getFullYear()} — edit these numbers by hand, or drop in the Countdown widget from the Widgets panel to make them run.</p>
|
||||
<form class="cs-form" method="post">
|
||||
<input type="email" name="email" placeholder="you@example">
|
||||
<button type="submit">Tell me when</button>
|
||||
</form>
|
||||
<p class="cs-or">or follow along: <a href="https://">Nostr</a> · <a href="https://">Mastodon</a> · <a href="mailto:">Email</a></p>
|
||||
</main>
|
||||
<footer class="cs-foot">© ${new Date().getFullYear()} ${esc(name)}</footer>`,
|
||||
css: `
|
||||
body{margin:0;min-height:100vh;display:flex;flex-direction:column;background:#070a04;color:#e9f2dc;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.6;background-image:radial-gradient(circle at 50% 0,rgba(198,255,74,.12),transparent 60%)}
|
||||
.cs{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:72px 24px 48px}
|
||||
.cs-kick{font-family:ui-monospace,Menlo,monospace;letter-spacing:.2em;text-transform:uppercase;font-size:12px;color:#c6ff4a;margin:0 0 24px}
|
||||
.cs h1{font-size:46px;line-height:1.1;letter-spacing:-.025em;margin:0 0 16px;max-width:16ch}
|
||||
.cs-sub{max-width:480px;color:#93a184;font-size:17px;margin:0 0 40px}
|
||||
.cs-clock{display:flex;gap:14px;flex-wrap:wrap;justify-content:center;margin-bottom:18px}
|
||||
.cs-clock div{background:rgba(198,255,74,.07);border:1px solid rgba(198,255,74,.22);border-radius:12px;padding:16px 20px;min-width:84px}
|
||||
.cs-clock b{display:block;font-size:34px;font-variant-numeric:tabular-nums;color:#c6ff4a;line-height:1.1}
|
||||
.cs-clock span{font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:#7c8a6d}
|
||||
.cs-when{color:#7c8a6d;font-size:13.5px;max-width:52ch;margin:0 0 40px}
|
||||
.cs-form{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;width:min(420px,100%)}
|
||||
.cs-form input{flex:1;min-width:190px;padding:13px 16px;border-radius:10px;border:1px solid rgba(255,255,255,.14);background:#0d1208;color:#e9f2dc;font:inherit}
|
||||
.cs-form input:focus{outline:2px solid #c6ff4a;outline-offset:1px}
|
||||
.cs-form button{padding:13px 22px;border:0;border-radius:10px;background:#c6ff4a;color:#070a04;font:inherit;font-weight:700;cursor:pointer}
|
||||
.cs-or{margin:22px 0 0;color:#7c8a6d;font-size:14px}
|
||||
.cs-or a{color:#c6ff4a;text-decoration:none}
|
||||
.cs-or a:hover{text-decoration:underline}
|
||||
.cs-foot{text-align:center;padding:20px;color:#5d6a50;font-size:12.5px}
|
||||
@media(max-width:520px){.cs h1{font-size:32px}.cs-clock div{padding:12px 14px;min-width:68px}.cs-clock b{font-size:26px}}`,
|
||||
},
|
||||
changelog: {
|
||||
label: "Changelog", tag: "What shipped, when, and what broke.", cat: "special",
|
||||
html: `
|
||||
<header class="cl-top">
|
||||
<div class="cl-in"><b>${esc(name)}</b><nav><a href="/">Home</a><a href="/docs/">Docs</a><a href="#">Feed</a></nav></div>
|
||||
</header>
|
||||
<section class="cl-intro">
|
||||
<h1>Changelog</h1>
|
||||
<p>Every release, newest first. Dates are the day the build went out, not the day the work started.</p>
|
||||
</section>
|
||||
<main class="cl">
|
||||
<article class="cl-rel">
|
||||
<div class="cl-ver"><b>0.4.0</b><time>12 Sep ${new Date().getFullYear()}</time></div>
|
||||
<div class="cl-body">
|
||||
<p class="cl-tags"><span class="t add">added</span><span class="t chg">changed</span></p>
|
||||
<ul><li>The thing people kept asking for, in one line.</li><li>Another thing, phrased as what the user can now do.</li><li>A setting moved. Say where it went.</li></ul>
|
||||
</div>
|
||||
</article>
|
||||
<article class="cl-rel">
|
||||
<div class="cl-ver"><b>0.3.2</b><time>28 Aug ${new Date().getFullYear()}</time></div>
|
||||
<div class="cl-body">
|
||||
<p class="cl-tags"><span class="t fix">fixed</span></p>
|
||||
<ul><li>The crash on the thing. Say what triggered it — people want to know if it was them.</li><li>A slow query that is no longer slow.</li></ul>
|
||||
</div>
|
||||
</article>
|
||||
<article class="cl-rel">
|
||||
<div class="cl-ver"><b>0.3.0</b><time>17 Jul ${new Date().getFullYear()}</time></div>
|
||||
<div class="cl-body">
|
||||
<p class="cl-tags"><span class="t add">added</span><span class="t brk">breaking</span></p>
|
||||
<ul><li>The new capability, in the user's words.</li><li><b>Breaking:</b> what you have to change before upgrading, and what happens if you do not.</li></ul>
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
<footer class="cl-foot">© ${new Date().getFullYear()} ${esc(name)}</footer>`,
|
||||
css: `
|
||||
body{margin:0;background:#08090a;color:#e8ecef;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.65}
|
||||
.cl-top{border-bottom:1px solid #191c1f}
|
||||
.cl-in{max-width:820px;margin:0 auto;padding:18px 24px;display:flex;justify-content:space-between;align-items:center}
|
||||
.cl-in b{font-size:15px}
|
||||
.cl-in a{margin-left:20px;color:#7e8792;text-decoration:none;font-size:14px}
|
||||
.cl-in a:hover{color:#fff}
|
||||
.cl-intro{max-width:820px;margin:0 auto;padding:56px 24px 32px}
|
||||
.cl-intro h1{font-size:38px;letter-spacing:-.025em;margin:0 0 10px}
|
||||
.cl-intro p{margin:0;color:#8b949e;max-width:56ch}
|
||||
.cl{max-width:820px;margin:0 auto;padding:0 24px 40px}
|
||||
.cl-rel{display:grid;grid-template-columns:130px 1fr;gap:28px;padding:28px 0;border-top:1px solid #191c1f}
|
||||
.cl-ver b{display:block;font-size:19px;font-variant-numeric:tabular-nums;color:#d4ff4f}
|
||||
.cl-ver time{display:block;color:#6e7681;font-size:13px;margin-top:3px}
|
||||
.cl-tags{margin:0 0 10px;display:flex;gap:6px;flex-wrap:wrap}
|
||||
.t{font-size:11px;letter-spacing:.08em;text-transform:uppercase;font-weight:600;padding:3px 9px;border-radius:999px;border:1px solid}
|
||||
.t.add{color:#d4ff4f;border-color:rgba(212,255,79,.35);background:rgba(212,255,79,.08)}
|
||||
.t.fix{color:#7ee3b0;border-color:rgba(126,227,176,.35);background:rgba(126,227,176,.08)}
|
||||
.t.chg{color:#8ab4ff;border-color:rgba(138,180,255,.35);background:rgba(138,180,255,.08)}
|
||||
.t.brk{color:#ff8fa3;border-color:rgba(255,143,163,.35);background:rgba(255,143,163,.08)}
|
||||
.cl-body ul{margin:0;padding-left:20px;color:#b6bec7}
|
||||
.cl-body li{margin-bottom:7px}
|
||||
.cl-body b{color:#ff8fa3}
|
||||
.cl-foot{border-top:1px solid #191c1f;padding:24px;text-align:center;color:#6e7681;font-size:13px}
|
||||
@media(max-width:620px){.cl-rel{grid-template-columns:1fr;gap:10px}.cl-ver{display:flex;align-items:baseline;gap:12px}.cl-ver time{margin:0}}`,
|
||||
},
|
||||
};
|
||||
|
||||
// ---------- editor ----------
|
||||
|
|
@ -526,6 +1162,19 @@ $("picker").addEventListener("click", (e) => {
|
|||
const b = e.target.closest("[data-tpl]"); if (!b) return;
|
||||
loadTemplate(b.dataset.tpl); $("picker").hidden = true; status("Template loaded — edit, then Publish");
|
||||
});
|
||||
// The template list in the top bar is generated from TEMPLATES, so adding a
|
||||
// template is a one-place change.
|
||||
(function fillTemplateSelect() {
|
||||
const sel = $("tpl-select");
|
||||
const first = sel.options[0]; // "Templates…" — keep the node, i18n owns its text
|
||||
sel.innerHTML = "";
|
||||
sel.appendChild(first);
|
||||
for (const [key, t] of Object.entries(TEMPLATES)) {
|
||||
const o = document.createElement("option");
|
||||
o.value = key; o.textContent = t.label || key;
|
||||
sel.appendChild(o);
|
||||
}
|
||||
})();
|
||||
$("tpl-select").addEventListener("change", (e) => {
|
||||
const v = e.target.value; e.target.value = "";
|
||||
if (!v) return;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue