{{ .NoticeTitle }}
+{{ .NoticeBody }}
+diff --git a/viewer/handler.go b/viewer/handler.go index 725d2cd..75d85f6 100644 --- a/viewer/handler.go +++ b/viewer/handler.go @@ -62,7 +62,7 @@ func newHandler(opts HandlerOptions) http.Handler { return } - page, err := buildPageData([]byte(payload), title) + page, err := buildPageData([]byte(payload), title, RenderOptions{}) if err != nil { if opts.Standalone { html, renderErr := web.RenderUpload(pageData{ diff --git a/viewer/model.go b/viewer/model.go index b21fcdb..7b006c1 100644 --- a/viewer/model.go +++ b/viewer/model.go @@ -1,11 +1,15 @@ package viewer type pageData struct { - Title string - HasSnapshot bool - Error string - Meta []fieldRow - Sections []sectionView + Title string + HasSnapshot bool + Error string + NoticeTitle string + NoticeBody string + DownloadArchiveURL string + DownloadArchiveLabel string + Meta []fieldRow + Sections []sectionView } type sectionView struct { diff --git a/viewer/render.go b/viewer/render.go index ea26e06..48a7bd7 100644 --- a/viewer/render.go +++ b/viewer/render.go @@ -81,16 +81,33 @@ var preferredColumns = map[string][]string{ "other": {"name", "value", "unit"}, } +type RenderOptions struct { + DownloadArchiveURL string + DownloadArchiveLabel string + NoticeTitle string + NoticeBody string +} + func RenderHTML(snapshot []byte, title string) ([]byte, error) { - page, err := buildPageData(snapshot, title) + return RenderHTMLWithOptions(snapshot, title, RenderOptions{}) +} + +func RenderHTMLWithOptions(snapshot []byte, title string, opts RenderOptions) ([]byte, error) { + page, err := buildPageData(snapshot, title, opts) if err != nil { return nil, err } return web.Render(page) } -func buildPageData(snapshot []byte, title string) (pageData, error) { - page := pageData{Title: title} +func buildPageData(snapshot []byte, title string, opts RenderOptions) (pageData, error) { + page := pageData{ + Title: title, + NoticeTitle: strings.TrimSpace(opts.NoticeTitle), + NoticeBody: strings.TrimSpace(opts.NoticeBody), + DownloadArchiveURL: strings.TrimSpace(opts.DownloadArchiveURL), + DownloadArchiveLabel: strings.TrimSpace(opts.DownloadArchiveLabel), + } if strings.TrimSpace(string(snapshot)) == "" { return page, nil } diff --git a/web/static/view.css b/web/static/view.css index 5873d5b..d53236d 100644 --- a/web/static/view.css +++ b/web/static/view.css @@ -31,6 +31,10 @@ body { } .page-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16px; padding: 24px 28px 18px; border-bottom: 1px solid rgba(0, 0, 0, 0.08); } @@ -46,6 +50,22 @@ body { color: var(--muted); } +.header-actions { + display: flex; + align-items: center; +} + +.header-action { + display: inline-block; + text-decoration: none; + border-radius: 999px; + background: var(--accent); + color: #fff; + padding: 10px 16px; + font-weight: 700; + white-space: nowrap; +} + .page-main { width: min(1500px, calc(100vw - 32px)); margin: 0 auto; @@ -54,6 +74,7 @@ body { .empty-panel, .meta-panel, +.notice-panel, .section-card, .upload-panel { background: var(--panel); @@ -67,6 +88,7 @@ body { .empty-panel h2, .section-card h2, .meta-panel h2, +.notice-panel h2, .upload-panel h2 { display: block; margin: 0 0 12px; @@ -74,6 +96,7 @@ body { } .empty-panel p, +.notice-panel p, .upload-panel p { margin: 0; color: var(--muted); @@ -259,6 +282,10 @@ body { } @media (max-width: 720px) { + .page-header { + flex-direction: column; + } + .page-main { width: min(100vw - 20px, 1500px); } diff --git a/web/templates/view.html b/web/templates/view.html index 583566b..1a4a48a 100644 --- a/web/templates/view.html +++ b/web/templates/view.html @@ -11,9 +11,21 @@
{{ .NoticeBody }}
+