Files
scarf/site/template.html.tmpl
T
Alan Wizemann 6175bee27d feat(site): dogfood the Scarf dashboard format as the catalog website
Adds site/ with vanilla HTML + CSS + ~300 lines of JavaScript that
renders ProjectDashboard JSON directly in the browser. Each template's
detail page shows a live preview of the exact dashboard the user will
get post-install — the catalog IS the dogfood.

site/widgets.js mirrors the Swift widget dispatcher:
- stat (big number + colored icon + optional subtitle)
- progress (0..1 bar)
- text with inline markdown subset (headings, bold/italic, inline code,
  code fences, bullet + numbered lists, links)
- table (plain HTML)
- list (with up/down/unknown status badges)
- chart (SVG line + bar — no Chart.js dependency)
- webview (sandboxed iframe)
- unknown (placeholder so the page doesn't silently omit widgets)

Plus the renderMarkdown helper used by the template detail page to
display the bundle's README.

site/index.html.tmpl + site/template.html.tmpl are substitution-only —
the Python regenerator swaps {{CARDS}}, {{COUNT}}, {{COUNT_PLURAL}},
{{NAME}}, {{DESC}}, {{VERSION}}, {{AUTHOR_HTML}}, {{TAGS_HTML}},
{{INSTALL_URL_ENCODED}}, {{SCARF_INSTALL_URL}}. The detail page fetches
dashboard.json + README.md at page load and hands them to widgets.js.
No client-side framework, no bundler, no npm.

site/styles.css: minimal CSS with scarf green accent, prefers-color-
scheme dark support, responsive at 680px. One file, ~280 lines.

build-catalog.py extended to copy dashboard.json + README.md out of each
bundle into its detail dir so widgets.js can fetch them without
reaching across directories (and so gh-pages doesn't need to serve zip
contents at request time).

Two new Python tests: end-to-end site rendering (both cards, install
URL wiring, static asset copy, per-template dashboard + README copy)
and the {{COUNT_PLURAL}} singular-vs-plural flip. 16/16 Python tests
green.

Smoke-tested locally with python3 -m http.server: every endpoint
(index, catalog.json, detail HTML, per-template dashboard.json + README,
widgets.js) returns 200. The .gh-pages-worktree/appcast.xml +
.gh-pages-worktree/index.html are untouched — the catalog is purely
additive under /templates/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:35:46 +02:00

87 lines
2.9 KiB
Cheetah

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{NAME}} — Scarf Templates</title>
<meta name="description" content="{{DESC}}">
<link rel="stylesheet" href="../styles.css">
<link rel="icon" type="image/png" href="../assets/icon.png">
</head>
<body>
<header class="site-header">
<a class="brand" href="..">
<img src="../assets/icon.png" alt="" width="40" height="40">
<span class="brand-name">Scarf Templates</span>
</a>
<nav class="site-nav">
<a href="..">Catalog</a>
<a href="https://github.com/awizemann/scarf">GitHub</a>
<a href="https://github.com/awizemann/scarf/blob/main/templates/CONTRIBUTING.md">Contribute</a>
</nav>
</header>
<main class="detail">
<section class="detail-header">
<div>
<h1>{{NAME}} <span class="version">v{{VERSION}}</span></h1>
<p class="desc">{{DESC}}</p>
<p class="meta">
<span class="author">by {{AUTHOR_HTML}}</span>
<span class="id">{{ID}}</span>
<span class="category">{{CATEGORY}}</span>
</p>
<p class="tags">{{TAGS_HTML}}</p>
</div>
<div class="install-actions">
<a class="btn btn-primary" href="{{SCARF_INSTALL_URL}}">Install with Scarf</a>
<a class="btn btn-secondary" href="{{INSTALL_URL_ENCODED}}">Download .scarftemplate</a>
</div>
</section>
<section class="detail-dashboard">
<h2>Live dashboard preview</h2>
<p class="detail-dashboard-note">
Exactly what you'll see inside Scarf after install. Values shown here are
placeholders; the agent updates them each time the cron job runs.
</p>
<div id="dashboard-preview"></div>
</section>
<section class="detail-readme">
<h2>README</h2>
<div id="readme-body"></div>
</section>
</main>
<footer class="site-footer">
<p>
Scarf is open source:
<a href="https://github.com/awizemann/scarf">github.com/awizemann/scarf</a>.
</p>
</footer>
<script src="../widgets.js"></script>
<script>
// Fetch + render dashboard + README at page load. Both files live
// alongside index.html in this template's detail dir.
(async function () {
const dashboardEl = document.getElementById("dashboard-preview");
const readmeEl = document.getElementById("readme-body");
try {
const d = await fetch("dashboard.json").then(r => r.json());
ScarfWidgets.renderDashboard(dashboardEl, d);
} catch (e) {
dashboardEl.textContent = "Could not load dashboard preview.";
}
try {
const md = await fetch("README.md").then(r => r.text());
readmeEl.innerHTML = ScarfWidgets.renderMarkdown(md);
} catch (e) {
readmeEl.textContent = "Could not load README.";
}
})();
</script>
</body>
</html>