Files
Roster/web/index.html
T

210 lines
9.9 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.
<!doctype html>
<html lang="en" data-theme="system">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#102d3d">
<title>Roster Formatter</title>
<script src="/static/theme.js"></script>
<link rel="stylesheet" href="/static/styles.css">
<script src="/static/app.js" defer></script>
</head>
<body
data-default-month="__DEFAULT_MONTH__"
data-retention-months="__RETENTION_MONTHS__"
data-max-upload-mb="__MAX_UPLOAD_MB__"
>
<header class="site-header">
<a class="brand" href="/" aria-label="Roster Formatter home">
<img src="/assets/logo.png" alt="River of Glory Church">
</a>
<div class="header-actions">
<div class="theme-switch" role="group" aria-label="Color theme">
<button class="theme-option" type="button" data-theme-choice="system" aria-pressed="true">System</button>
<button class="theme-option" type="button" data-theme-choice="light" aria-pressed="false">Light</button>
<button class="theme-option" type="button" data-theme-choice="dark" aria-pressed="false">Dark</button>
</div>
<span class="local-badge"><span aria-hidden="true"></span> Local &amp; private</span>
</div>
</header>
<main>
<section class="intro" aria-labelledby="page-title">
<p class="eyebrow">Roster formatter</p>
<h1 id="page-title">From current roster to ready-to-share PNG.</h1>
<p class="lede">
Upload the one-page PDF, confirm its month, and download the formatted image.
The current layout is preserved unless you intentionally change an advanced value.
</p>
<div class="format-facts" aria-label="Output details">
<span>PNG</span>
<span>1650 × 1275 px</span>
<span>150 DPI</span>
</div>
</section>
<div class="workspace">
<section class="card form-card" aria-labelledby="format-heading">
<div class="card-heading">
<div>
<p class="step-label">New export</p>
<h2 id="format-heading">Format a roster</h2>
</div>
<span class="defaults-status" id="defaults-status">Saved defaults</span>
</div>
<form id="roster-form" action="/format" method="post" enctype="multipart/form-data">
<label class="drop-zone" id="drop-zone" for="roster-file">
<input id="roster-file" name="roster" type="file" accept="application/pdf,.pdf">
<span class="upload-mark" aria-hidden="true">↑</span>
<span class="drop-title" id="drop-title">Choose your roster PDF</span>
<span class="drop-copy" id="drop-copy">or drag it here · one-page landscape Letter · up to __MAX_UPLOAD_MB__ MB</span>
</label>
<div class="field-block">
<label for="month">Roster month</label>
<div class="month-row">
<input id="month" name="month" type="month" value="__DEFAULT_MONTH__" required>
<button class="text-button" id="suggested-month" type="button">Use suggested</button>
</div>
<p class="field-help">This controls the label and downloaded filename.</p>
</div>
<details class="advanced" id="advanced-settings">
<summary>
<span>
<strong>Advanced adjustments</strong>
<small>Use only when this month needs a nudge.</small>
</span>
<span class="chevron" aria-hidden="true">⌄</span>
</summary>
<div class="advanced-body">
<div class="advanced-heading">
<p>Values use PDF points. Saved defaults prefill every new roster.</p>
<div class="layout-actions">
<button class="text-button" id="reset-layout" type="button">Reset changes</button>
<button class="text-button" id="factory-layout" type="button">Use original values</button>
</div>
</div>
<fieldset>
<legend>Roster content</legend>
<div class="setting-grid">
<label>
Vertical shift
<input name="content_shift" type="number" value="__CONTENT_SHIFT__" data-default="__CONTENT_SHIFT__" data-factory="__FACTORY_CONTENT_SHIFT__" data-layout-input step="1" min="-300" max="500" required>
</label>
<label>
Bottom trim
<input name="bottom_margin" type="number" value="__BOTTOM_MARGIN__" data-default="__BOTTOM_MARGIN__" data-factory="__FACTORY_BOTTOM_MARGIN__" data-layout-input step="1" min="0" max="500" required>
</label>
</div>
</fieldset>
<fieldset>
<legend>Logo</legend>
<div class="setting-grid setting-grid--three">
<label>
X position
<input name="logo_x" type="number" value="__LOGO_X__" data-default="__LOGO_X__" data-factory="__FACTORY_LOGO_X__" data-layout-input step="1" min="-1000" max="2000" required>
</label>
<label>
Y position
<input name="logo_y" type="number" value="__LOGO_Y__" data-default="__LOGO_Y__" data-factory="__FACTORY_LOGO_Y__" data-layout-input step="1" min="-1000" max="2000" required>
</label>
<label>
Scale
<input name="logo_scale" type="number" value="__LOGO_SCALE__" data-default="__LOGO_SCALE__" data-factory="__FACTORY_LOGO_SCALE__" data-layout-input step="0.01" min="0.01" max="2" required>
</label>
</div>
</fieldset>
<fieldset>
<legend>Date label</legend>
<div class="setting-grid setting-grid--three">
<label>
X position
<input name="date_x" type="number" value="__DATE_X__" data-default="__DATE_X__" data-factory="__FACTORY_DATE_X__" data-layout-input step="1" min="-1000" max="2000" required>
</label>
<label>
Y position
<input name="date_y" type="number" value="__DATE_Y__" data-default="__DATE_Y__" data-factory="__FACTORY_DATE_Y__" data-layout-input step="1" min="-1000" max="2000" required>
</label>
<label>
Font size
<input name="date_font_size" type="number" value="__DATE_FONT_SIZE__" data-default="__DATE_FONT_SIZE__" data-factory="__FACTORY_DATE_FONT_SIZE__" data-layout-input step="1" min="8" max="200" required>
</label>
</div>
</fieldset>
<div class="save-defaults-row">
<p id="layout-message" role="status" aria-live="polite" hidden></p>
<button class="secondary-button save-defaults-button" id="save-layout-defaults" type="button">Save as defaults</button>
</div>
<p class="canvas-lock">
The page canvas and 150-DPI export stay fixed, even when these values change.
</p>
</div>
</details>
<div class="form-message" id="form-message" role="alert" hidden></div>
<button class="primary-button" id="format-button" type="submit">
<span class="button-label">Format roster</span>
<span class="button-arrow" aria-hidden="true">→</span>
</button>
</form>
</section>
<aside class="side-column">
<section class="card result-card" id="result-card" aria-labelledby="result-heading" aria-live="polite" tabindex="-1" hidden>
<div class="result-heading">
<div>
<p class="step-label">Ready</p>
<h2 id="result-heading">Your formatted roster</h2>
</div>
<span class="success-mark" aria-hidden="true">✓</span>
</div>
<div class="preview-shell">
<img id="result-preview" alt="Preview of the formatted roster">
</div>
<p class="result-name" id="result-name"></p>
<div class="result-actions">
<a class="primary-button" id="download-result" href="#" download>Download PNG</a>
<button class="secondary-button" id="format-another" type="button">Format another</button>
</div>
</section>
<section class="card history-card" aria-labelledby="history-heading">
<div class="card-heading compact-heading">
<div>
<p class="step-label">Saved locally</p>
<h2 id="history-heading">Recent rosters</h2>
</div>
<button class="icon-button" id="refresh-history" type="button" aria-label="Refresh recent rosters">↻</button>
</div>
<div id="history-list" class="history-list" aria-live="polite">
<p class="empty-state">Loading saved rosters…</p>
</div>
<p class="retention-note" id="retention-note">
Saved roster PNGs outside the __RETENTION_MONTHS__-month window are removed automatically.
</p>
</section>
<section class="privacy-note" aria-label="Privacy information">
<span aria-hidden="true">⌂</span>
<p>
Processing happens on this machine. Uploads and working PDFs are deleted as soon as the PNG is made.
</p>
</section>
</aside>
</div>
</main>
<footer>
<span>River of Glory · Roster tools</span>
<span>Fixed 11 × 8.5 in canvas</span>
</footer>
</body>
</html>