- New /codes dashboard page (behind the session login, linked in the top bar):
lists every mapping by kind with Add, inline Edit+Save and Delete. Sam can put
real teacher surnames in without a rebuild (FR-17).
- Decode timetable EVENTS through the same map as periods, so an ensemble reads
'JAZZ ENSEMBLE - Ensemble Room - Mr KWO' instead of raw codes.
- teacherName splits comma- or space-separated codes ('HHL, OFG').
- SeedCodes is a one-time bootstrap while the table is empty, so a correction or
a delete is never overwritten or restored.
- Tests: decode Label/Event, the /codes page (save, refuse, csrf, delete, auth),
store re-seed behaviour. go test ./internal/... passes.
95 lines
4.1 KiB
HTML
95 lines
4.1 KiB
HTML
{{define "item.html"}}<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="color-scheme" content="light dark">
|
|
<title>{{.Title}} — Compass / Teams</title>
|
|
<link rel="stylesheet" href="/static/tokens.css">
|
|
<link rel="stylesheet" href="/static/app.css">
|
|
<script src="/static/htmx.min.js" defer></script>
|
|
<script src="/static/theme.js" defer></script>
|
|
</head>
|
|
<body class="app">
|
|
<nav class="nav-bar">
|
|
<a class="nav-bar__brand" href="/">
|
|
<span class="nav-bar__mark" aria-hidden="true"></span>
|
|
Compass / Teams
|
|
</a>
|
|
<div class="nav-bar__right">
|
|
<a class="button-utility" href="/codes">Codes</a>
|
|
<button class="button-utility" type="button" data-theme-toggle>Dark</button>
|
|
<span class="nav-bar__user">{{.Username}}</span>
|
|
<form method="post" action="/logout" class="nav-bar__logout">
|
|
<input type="hidden" name="csrf" value="{{.CSRF}}">
|
|
<button class="button-utility" type="submit">Sign out</button>
|
|
</form>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="container">
|
|
<p class="breadcrumb"><a href="/?child={{.Child.ID}}">← {{.Child.Name}}</a></p>
|
|
|
|
<article class="detail">
|
|
{{if .Flash}}<p class="flash flash--{{if eq .FlashLevel "ok"}}ok{{else}}error{{end}}" role="alert">{{.Flash}}</p>{{end}}
|
|
<header class="detail__head">
|
|
<h1 class="heading-1">{{.Item.Title}}</h1>
|
|
<p class="detail__meta">
|
|
<span class="tag tag--type">{{.Item.TypeLabel}}</span>
|
|
{{if .Item.Subject}}<span>{{.Item.Subject}}</span>{{end}}
|
|
{{if .Item.Teacher}}<span>Teacher: {{.Item.Teacher}}</span>{{end}}
|
|
{{if .Item.DueLabel}}<span class="item__due">due {{.Item.DueLabel}}</span>{{end}}
|
|
{{if .Item.StatusLabel}}<span class="tag tag--status">{{.Item.StatusLabel}}</span>{{end}}
|
|
</p>
|
|
</header>
|
|
|
|
{{if .Item.BodyLines}}
|
|
<section class="detail__body">
|
|
{{range .Item.BodyLines}}<p>{{.}}</p>{{end}}
|
|
</section>
|
|
{{end}}
|
|
|
|
<dl class="detail__facts">
|
|
<dt>Child</dt><dd>{{.Child.Name}}</dd>
|
|
<dt>Source</dt><dd>{{.Item.Source}}{{if .Item.SourcePage}} · {{.Item.SourcePage}}{{end}}</dd>
|
|
{{if .Item.Importance}}<dt>Importance</dt><dd>{{.Item.Importance}}</dd>{{end}}
|
|
<dt>Calendar</dt>
|
|
<dd>{{if .Calendar.InCalendar}}in the calendar{{if .Calendar.PushedAt}} · {{.Calendar.PushedAt}}{{end}}{{if .Calendar.UID}} · {{.Calendar.UID}}{{end}}
|
|
{{else if not .Calendar.Configured}}not configured
|
|
{{else if .Calendar.Eligible}}not written yet
|
|
{{else}}not a calendar item{{end}}</dd>
|
|
{{if .Item.ExternalRef}}<dt>Reference</dt><dd>{{.Item.ExternalRef}}</dd>{{end}}
|
|
{{if .Item.DueAt}}<dt>Due</dt><dd>{{.Item.DueLabel}}</dd>{{end}}
|
|
</dl>
|
|
|
|
<div class="detail__actions">
|
|
{{if .Item.URL}}<a class="button-primary" href="{{.Item.URL}}" rel="noreferrer noopener">Open in Compass</a>{{end}}
|
|
{{if and .Calendar.Configured .Calendar.Eligible (not .Calendar.InCalendar)}}
|
|
<form method="post" action="/items/{{.Item.ID}}/calendar">
|
|
<input type="hidden" name="csrf" value="{{.CSRF}}">
|
|
<button class="button-primary" type="submit">Add to calendar</button>
|
|
</form>
|
|
{{end}}
|
|
<form method="post" action="/items/{{.Item.ID}}/delete"
|
|
hx-post="/items/{{.Item.ID}}/delete" hx-confirm="Delete this item? It returns on the next scan if the school still lists it.">
|
|
<input type="hidden" name="csrf" value="{{.CSRF}}">
|
|
<button class="button-utility button-utility--danger" type="submit">Delete</button>
|
|
</form>
|
|
</div>
|
|
|
|
{{if not .Scan.OK}}
|
|
<p class="flash flash--error" role="alert">{{.Scan.Message}}</p>
|
|
{{end}}
|
|
</article>
|
|
</main>
|
|
|
|
<footer class="app-foot">
|
|
<span>Compass / Teams · {{.Version}} · {{.AppEnv}}</span>
|
|
<span class="app-foot__sep">·</span>
|
|
<span>up {{.ServerUp}}</span>
|
|
<span class="app-foot__sep">·</span>
|
|
<span>{{year}} Family Home Lab</span>
|
|
</footer>
|
|
</body>
|
|
</html>{{end}}
|