import { styles } from './styles.ts'
import { clientScript } from './client-script.ts'
import type { AppVersion } from '../version-shape.ts'
export function renderAppPage(input: {
appBasePath: string
hostedUrl: string
repoLabel: string
version?: AppVersion
}): string {
const base = input.appBasePath.endsWith('/')
? input.appBasePath
: `${input.appBasePath}/`
const version = input.version
return `<!doctype html>
<html lang="en" data-base="${escapeAttr(base)}" data-running-sha="${escapeAttr(version?.sha || '')}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="theme-color" content="#c8102e" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#16090c" media="(prefers-color-scheme: dark)">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Lineage">
<meta name="description" content="Commit-level lines that should count — generated files stay off the books.">
<link rel="canonical" href="${escapeAttr(input.hostedUrl)}/">
<meta property="og:type" content="website">
<meta property="og:title" content="Lineage · ${escapeAttr(input.repoLabel)}">
<meta property="og:description" content="Commit-level lines that should count — generated files stay off the books.">
<meta property="og:image" content="${escapeAttr(input.hostedUrl)}/og-image.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<title>Lineage · ${escapeHtml(input.repoLabel)}</title>
<link rel="manifest" href="${escapeAttr(base)}manifest.webmanifest">
<link rel="icon" href="${escapeAttr(base)}favicon.png" type="image/png" sizes="64x64">
<link rel="icon" href="${escapeAttr(base)}icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="${escapeAttr(base)}apple-touch-icon.png">
<style>${styles}</style>
</head>
<body>
<main class="app" id="app">
<header class="top">
<div class="brand">
<img class="mark" src="${escapeAttr(base)}pwa-192.png" width="40" height="40" alt="">
<div class="brand-copy" data-status>
<div class="title-row">
<h1>Lineage</h1>
<span class="status-mark" data-status-mark aria-hidden="true"></span>
</div>
<p class="status-text" data-status-text></p>
</div>
</div>
<div class="actions">
<button class="ghost" type="button" data-about>About</button>
<div class="install-wrap" data-install-wrap>
<button class="install install-trigger" type="button" data-install-open>
Install
</button>
<div class="install-popover" id="lineage-install-popover" popover data-install-popover>
<strong>Install Lineage</strong>
<p>Full screen, works offline, and the last series stays on this device.</p>
<button class="install" type="button" data-install>Install</button>
</div>
</div>
</div>
</header>
<div class="install-hint" data-install-hint hidden>
<span class="install-hint-icon" aria-hidden="true">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none">
<path d="M12 3v10m0-10l-3.5 3.5M12 3l3.5 3.5M5 13v5a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3v-5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</span>
<p>Install Lineage: tap <strong>Share</strong>, then <strong>Add to Home Screen</strong>.</p>
<button class="install-hint-dismiss" type="button" data-install-hint-dismiss aria-label="Dismiss install tip">×</button>
</div>
<section class="panel" data-panel aria-busy="false">
<div class="chart-wrap">
<div class="loading" data-loading hidden role="status" aria-live="polite">
<div class="loading-card">
<svg class="loading-mark" viewBox="0 0 280 92" aria-hidden="true">
<path class="loading-area a" d="M0 78 C 40 74, 70 52, 110 48 S 180 60, 220 28 S 260 18, 280 12 V 92 H 0 Z"></path>
<path class="loading-area b" d="M0 84 C 50 80, 90 70, 140 66 S 200 72, 280 40 V 92 H 0 Z"></path>
<path class="loading-line" d="M0 78 C 40 74, 70 52, 110 48 S 180 60, 220 28 S 260 18, 280 12"></path>
</svg>
<p class="loading-kicker">Lineage</p>
<h2 data-loading-title>Loading countable history</h2>
<p data-loading-detail>Reading the latest countable commits and drawing the graph.</p>
<div class="loading-bar" aria-hidden="true"><span></span></div>
</div>
</div>
<div data-chart></div>
<div class="tooltip" data-tooltip hidden></div>
</div>
<div class="controls">
<div class="modes" data-modes>
<button type="button" data-mode="cumulative" aria-pressed="true">Cumulative</button>
<button type="button" data-mode="delta">Added / removed</button>
<button type="button" data-mode="net">Net per commit</button>
</div>
<div class="presets" data-presets>
<button type="button" data-preset="7d">7 days</button>
<button type="button" data-preset="30d">30 days</button>
<button type="button" data-preset="90d">90 days</button>
<button type="button" data-preset="1y">1 year</button>
<button type="button" data-preset="all">All</button>
</div>
<div class="range">
<label>From<input id="from" type="datetime-local"></label>
<label>To<input id="to" type="datetime-local"></label>
</div>
<div class="dual-range" data-dual-range>
<div class="dual-range-track" data-range-track></div>
<label class="sr-only" for="range-from">Range start</label>
<input id="range-from" type="range" min="0" max="1" value="0" data-range-from>
<label class="sr-only" for="range-to">Range end</label>
<input id="range-to" type="range" min="0" max="1" value="1" data-range-to>
</div>
<div>
<p class="eyebrow">Type</p>
<div class="chips" data-kinds>
<span class="chip-skeleton" aria-hidden="true"></span>
<span class="chip-skeleton" aria-hidden="true"></span>
<span class="chip-skeleton" aria-hidden="true"></span>
</div>
</div>
<div>
<p class="eyebrow">Language</p>
<div class="chips" data-languages>
<span class="chip-skeleton" aria-hidden="true"></span>
<span class="chip-skeleton wide" aria-hidden="true"></span>
<span class="chip-skeleton" aria-hidden="true"></span>
<span class="chip-skeleton wide" aria-hidden="true"></span>
<span class="chip-skeleton" aria-hidden="true"></span>
<span class="chip-skeleton" aria-hidden="true"></span>
</div>
</div>
</div>
<section class="story">
<p class="eyebrow">Story</p>
<p class="story-lede">Tap a label on the chart or a card here for the longer note. These mark primitive adds, removals, and combinations — not every large diff.</p>
<div class="story-list" data-story></div>
</section>
<div class="commits" data-commits></div>
</section>
<aside class="sheet" data-sheet hidden></aside>
<aside class="sheet" data-about-sheet hidden></aside>
<div class="toast" data-toast hidden>
<div>
<strong data-toast-title>Update available</strong>
<p data-toast-text>A newer Lineage is ready. Reload to download it.</p>
</div>
<div class="toast-actions">
<button class="install" type="button" data-toast-action>Reload</button>
<button class="ghost" type="button" data-toast-dismiss>Later</button>
</div>
</div>
</main>
<script>${clientScript}</script>
</body>
</html>`
}
function escapeHtml(value: string): string {
return value
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
}
function escapeAttr(value: string): string {
return escapeHtml(value).replaceAll('"', '"')
}