Files
bible/demo/web/templates/base.html

312 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{ define "demo_doc_start" }}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ .Title }}</title>
<link rel="stylesheet" href="/static/css/app.css">
</head>
<body>
{{ template "demo_nav" . }}
{{ template "demo_app_shell" . }}
<main class="page">
{{ end }}
{{ define "demo_doc_end" }}
</main>
<script src="/static/js/app.js" defer></script>
</body>
</html>
{{ end }}
{{ define "demo_masthead" }}
<header class="masthead">
<p class="label">{{ index . "label" }}</p>
<h1>{{ index . "title" }}</h1>
<p class="lead">{{ index . "lead" }}</p>
{{ if index . "back_url" }}
<p class="meta" style="margin-top:10px;"><a class="text-link" href="{{ index . "back_url" }}">{{ index . "back_text" }}</a></p>
{{ end }}
{{ if index . "links_html" }}
{{ index . "links_html" }}
{{ end }}
</header>
{{ end }}
{{ define "demo_app_shell" }}
<header class="app-shell" id="app-shell">
<div class="app-shell-inner">
<div>
<p class="app-shell-kicker">Demo Application Shell</p>
<h1 class="app-shell-title">Universal Operations Console</h1>
<p class="app-shell-subtitle">Reference shell for server-rendered Go web apps using shared design-code contracts.</p>
</div>
<div class="app-shell-statuses" aria-label="Application status">
<span class="shell-pill shell-pill-env">ENV: demo</span>
<span class="shell-pill shell-pill-db">DB: connected</span>
<span class="shell-pill shell-pill-user">operator@demo · admin</span>
</div>
</div>
</header>
{{ end }}
{{ define "base.html" }}
{{ template "demo_doc_start" . }}
<header class="masthead" id="home-overview">
<p class="label">Submodule-First Design Kit</p>
<h1>{{ .Title }}</h1>
<p class="lead">A universal design-code workspace for Go web applications: reusable rules, demo-first UI patterns, and canonical development contracts for AI-assisted implementation.</p>
<div class="button-demo-row" style="margin-top:12px;">
{{ range .Patterns }}
{{ if .Link }}
<a class="chip-link" href="{{ .Link }}">{{ .Name }}</a>
{{ end }}
{{ end }}
</div>
</header>
<section class="panel" id="home-design-approach">
<div class="panel-head"><h2>Design Approach</h2></div>
<div class="grid">
<article class="card">
<h3>Contract First</h3>
<p>UI behavior is defined as explicit contracts (filters, pagination, modal steps, timeline grouping) before implementation details. Demo pages act as executable specs.</p>
</article>
<article class="card">
<h3>Server-Rendered by Default</h3>
<p>Patterns target Go server-rendered apps first (net/http or Gin with templates). Interactivity is additive and must preserve deterministic URL/query contracts.</p>
</article>
<article class="card">
<h3>Reusable, Not Branded</h3>
<p>Shared patterns standardize behavior and structure while leaving visual branding, domain terminology, and business logic to each host project.</p>
</article>
</div>
</section>
<section class="panel" id="home-workflow">
<div class="panel-head"><h2>Development Workflow Standard</h2></div>
<div class="timeline-cards">
<article class="timeline-card">
<div class="timeline-card-top"><h3>1. Describe the contract</h3></div>
<p class="meta">Update Bible + pattern contract first: routes, query params, states, edge cases, and UI semantics.</p>
</article>
<article class="timeline-card">
<div class="timeline-card-top"><h3>2. Implement in demo</h3></div>
<p class="meta">Build the pattern in the demo app as a live reference page with realistic state transitions and test coverage.</p>
</article>
<article class="timeline-card">
<div class="timeline-card-top"><h3>3. Publish as bundle</h3></div>
<p class="meta">Encode reusable docs and templates in the design kit and expose them as bundles for host repositories.</p>
</article>
<article class="timeline-card">
<div class="timeline-card-top"><h3>4. Apply in host repos</h3></div>
<p class="meta">Use the sync workflow to plan and apply changes, then adapt domain-specific rules without breaking canonical UI contracts.</p>
</article>
</div>
</section>
<section class="panel" id="home-standardizes">
<div class="panel-head"><h2>What the Demo Standardizes</h2></div>
<div class="chip-row">
<span class="chip">URL-driven filters</span>
<span class="chip">Server-side pagination</span>
<span class="chip">Bulk selection semantics</span>
<span class="chip">Modal state machines</span>
<span class="chip">Import preview / confirm</span>
<span class="chip">CSV export behavior</span>
<span class="chip">Operator tooling dashboards</span>
<span class="chip">Timeline card grouping</span>
<span class="chip">Drilldown UX</span>
</div>
</section>
<section class="panel" id="home-anti-patterns">
<div class="panel-head"><h2>Anti-Patterns (Do Not Implement)</h2></div>
<div class="grid">
<article class="card">
<h3>Page-local filters on paginated tables</h3>
<p>Do not filter only the currently rendered page slice. Filters must apply to the full dataset/query scope before pagination.</p>
</article>
<article class="card">
<h3>Nested modals</h3>
<p>Do not open one modal from another modal. Use a single modal state machine with explicit stages (edit, confirm, done).</p>
</article>
<article class="card">
<h3>Implicit export scope</h3>
<p>Do not export without clear scope selection when ambiguity exists (selected, filtered, all). Make the scope explicit in UI and request.</p>
</article>
<article class="card">
<h3>Undocumented UI contracts</h3>
<p>Do not implement new interaction behavior without updating the design code (Bible, pattern contract, and demo reference page).</p>
</article>
</div>
</section>
<section class="panel" id="home-bundles">
<div class="panel-head">
<h2>Bundles</h2>
<a href="/healthz" class="pill">healthz</a>
</div>
<div class="grid">
{{ range .Bundles }}
<article class="card">
<div class="row">
<h3>{{ .Name }}</h3>
<span class="status status-{{ .Status }}">{{ .Status }}</span>
</div>
<p>{{ .Summary }}</p>
<p class="meta"><code>{{ .Bundle }}</code></p>
{{ if .Link }}
<p class="meta"><a class="text-link" href="{{ .Link }}">Open demo</a></p>
{{ end }}
</article>
{{ end }}
</div>
</section>
<section class="panel" id="home-roadmap">
<div class="panel-head">
<h2>Pattern Roadmap</h2>
</div>
<div class="grid">
{{ range .Patterns }}
<article class="card">
<div class="row">
<h3>{{ .Name }}</h3>
<span class="status status-{{ .Status }}">{{ .Status }}</span>
</div>
<p>{{ .Summary }}</p>
<p class="meta"><code>{{ .Bundle }}</code></p>
</article>
{{ end }}
</div>
</section>
{{ template "demo_doc_end" . }}
{{ end }}
{{ define "demo_nav" }}
<nav class="demo-topnav" aria-label="Demo navigation">
<div class="demo-topnav-inner">
<a class="demo-topnav-brand {{ if eq .CurrentPath "/" }}active{{ end }}" href="/">Demo Catalog</a>
<a class="demo-topnav-link {{ if eq .CurrentPath "/patterns/table" }}active{{ end }}" href="/patterns/table">Table</a>
<a class="demo-topnav-link {{ if eq .CurrentPath "/patterns/controls" }}active{{ end }}" href="/patterns/controls">Controls</a>
<a class="demo-topnav-link {{ if eq .CurrentPath "/patterns/modals" }}active{{ end }}" href="/patterns/modals">Modals</a>
<a class="demo-topnav-link {{ if eq .CurrentPath "/patterns/io" }}active{{ end }}" href="/patterns/io">Import/Export</a>
<a class="demo-topnav-link {{ if eq .CurrentPath "/patterns/forms" }}active{{ end }}" href="/patterns/forms">Forms</a>
<a class="demo-topnav-link {{ if eq .CurrentPath "/patterns/operator-tools" }}active{{ end }}" href="/patterns/operator-tools">Operator Tools</a>
<a class="demo-topnav-link {{ if eq .CurrentPath "/patterns/timeline" }}active{{ end }}" href="/patterns/timeline">Timeline</a>
</div>
</nav>
{{ end }}
{{ define "table_pattern.html" }}
{{ template "demo_doc_start" . }}
{{ template "demo_masthead" (dict "label" "Pattern Demo" "title" .Title "lead" "Server-side filtering and pagination. Filters apply to the full dataset before pagination." "back_url" "/" "back_text" "← Back to catalog") }}
<section class="panel panel-composite" id="table-module">
<div class="panel-subsection" id="table-filters">
<div class="panel-head">
<h2>Filters</h2>
<div class="button-demo-row" style="margin-top:0;">
<a href="/patterns/table#table-filters" class="btn btn-ghost btn-pair">Reset</a>
<button class="btn btn-primary btn-pair" form="table-filters-form" type="submit">Apply</button>
</div>
</div>
<form id="table-filters-form" class="filters" method="get" action="/patterns/table#table-filters">
<label>
Search
<input type="text" name="q" value="{{ .Filters.Query }}" placeholder="name / owner / status" />
</label>
<label>
Category
<select name="category">
<option value="">All</option>
{{ range .Categories }}
<option value="{{ . }}" {{ if eq $.Filters.Category . }}selected{{ end }}>{{ . }}</option>
{{ end }}
</select>
</label>
<label>
Status
<select name="status">
<option value="">All</option>
{{ range .Statuses }}
<option value="{{ . }}" {{ if eq $.Filters.Status . }}selected{{ end }}>{{ . }}</option>
{{ end }}
</select>
</label>
<label>
Rows per page
<select name="per_page">
{{ range .PerPageOpts }}
<option value="{{ . }}" {{ if eq $.PerPage . }}selected{{ end }}>{{ . }}</option>
{{ end }}
</select>
</label>
</form>
</div>
<div class="panel-subsection panel-subsection-divider" id="table-list">
<div class="panel-head">
<h2>Canonical List Page</h2>
<div class="meta">
{{ if gt .Pager.TotalItems 0 }}
Showing {{ .Pager.From }}{{ .Pager.To }} of {{ .Pager.TotalItems }}
{{ else }}
Showing 0 of 0
{{ end }}
</div>
</div>
<div class="table-wrap">
<table class="ui-table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Category</th>
<th class="status-col">Status</th>
<th>Owner</th>
<th>Updated</th>
</tr>
</thead>
<tbody>
{{ if .Rows }}
{{ range .Rows }}
<tr>
<td>{{ .ID }}</td>
<td>{{ .Name }}</td>
<td>{{ .Category }}</td>
<td class="status-col"><span class="status status-{{ .Status }}">{{ .Status }}</span></td>
<td>{{ .Owner }}</td>
<td>{{ .Updated }}</td>
</tr>
{{ end }}
{{ else }}
<tr>
<td colspan="6" class="empty-cell">No rows match current filters.</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ if gt .Pager.TotalPages 1 }}
<nav class="pager pager-dots" aria-label="Pagination">
{{ range .Pager.Links }}
{{ if .Ellipsis }}
<span class="ellipsis" aria-hidden="true"></span>
{{ else if .Current }}
<a class="current" aria-current="page" href="{{ .URL }}#table-list" aria-label="Page {{ .Label }}, current">{{ .Label }}</a>
{{ else }}
<a href="{{ .URL }}#table-list" aria-label="Go to page {{ .Label }}">{{ .Label }}</a>
{{ end }}
{{ end }}
</nav>
{{ end }}
</div>
</section>
{{ template "demo_doc_end" . }}
{{ end }}