Files
modern-glance/internal/glance/templates/admin-page.html
T
uhlwoogiandClaude Opus 4.7 2e198a19b4 Add in-app edit UI for dashboard config
A web editor at /edit for managing pages and widgets without hand-editing YAML:

- Page list and per-page widget views with breadcrumb navigation
- Add/delete pages, add/delete/reorder widgets within a column
- Per-widget textarea editor with curated starter templates, widget-specific
  help (example, full field reference, link to upstream docs), and inline
  error rendering that preserves the user's edits on validation failure
- Pre-save validation via newConfigFromYAML; atomic temp+rename writes with
  .bak backup; YAML edits go through yaml.Node so comments and unresolved
  ${env:X}/${secret:X} tokens survive round-trips
- Auth gate: editing requires auth.users to be configured, or
  admin.allow-without-auth: true as an explicit opt-in for trusted networks
- Pencil button on the dashboard near the theme picker for quick access
- Admin views read fresh from disk so the list updates immediately after
  saves rather than lagging the fsnotify watcher

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 14:12:18 +00:00

80 lines
4.0 KiB
HTML

{{- template "document.html" . }}
{{- define "document-title" }}Edit {{ .Page.Title }} - {{ .App.Config.Branding.AppName }}{{ end }}
{{- define "document-body" }}
<div class="flex flex-column body-content">
<main class="content-bounds" style="padding-block: 2rem;">
<div class="margin-bottom-15">
<a class="color-subdue" href="{{ .App.Config.Server.BaseURL }}/edit">← Edit</a>
</div>
<h1 class="size-h1">{{ .Page.Title }}</h1>
<p class="color-subdue margin-bottom-25">/{{ .Page.Slug }}</p>
{{- if .Page.HeadWidgets }}
<h2 class="size-h2 margin-bottom-10">Head widgets</h2>
<ul class="list list-gap-10 margin-bottom-25">
{{- range .Page.HeadWidgets }}
<li>
<a class="color-primary" href="{{ $.App.Config.Server.BaseURL }}/edit/pages/{{ $.Page.Slug }}/widgets/-1/{{ .WidgetIndex }}">
{{ if .Title }}{{ .Title }}{{ else }}<em>(untitled)</em>{{ end }}
</a>
<span class="color-subdue"> — {{ .Type }}</span>
</li>
{{- end }}
</ul>
{{- end }}
<h2 class="size-h2 margin-bottom-10">Columns</h2>
{{- if not .Page.Columns }}
<p class="color-subdue">No columns configured on this page. Edit the YAML manually to add columns — column editing comes in a later phase.</p>
{{- end }}
{{- range $colIdx, $col := .Page.Columns }}
<section class="margin-bottom-25">
<h3 class="size-h3 margin-bottom-10">
Column {{ $col.Index }}
<span class="color-subdue size-h5">({{ if $col.Size }}{{ $col.Size }}{{ else }}default{{ end }})</span>
</h3>
{{- if not $col.Widgets }}
<p class="color-subdue">No widgets in this column.</p>
{{- else }}
<ul class="list list-gap-10 margin-bottom-15">
{{- range $col.Widgets }}
<li class="flex items-center gap-10">
<div class="grow">
<a class="color-primary" href="{{ $.App.Config.Server.BaseURL }}/edit/pages/{{ $.Page.Slug }}/widgets/{{ .ColumnIndex }}/{{ .WidgetIndex }}">
{{ if .Title }}{{ .Title }}{{ else }}<em>(untitled)</em>{{ end }}
</a>
<span class="color-subdue"> — {{ .Type }}</span>
</div>
<form method="post" action="{{ $.App.Config.Server.BaseURL }}/edit/api/pages/{{ $.Page.Slug }}/widgets/{{ .ColumnIndex }}/{{ .WidgetIndex }}/move?dir=up">
<button type="submit" {{ if .IsFirst }}disabled{{ end }}></button>
</form>
<form method="post" action="{{ $.App.Config.Server.BaseURL }}/edit/api/pages/{{ $.Page.Slug }}/widgets/{{ .ColumnIndex }}/{{ .WidgetIndex }}/move?dir=down">
<button type="submit" {{ if .IsLast }}disabled{{ end }}></button>
</form>
<form method="post" action="{{ $.App.Config.Server.BaseURL }}/edit/api/pages/{{ $.Page.Slug }}/widgets/{{ .ColumnIndex }}/{{ .WidgetIndex }}/delete"
onsubmit="return confirm('Delete this widget?');">
<button type="submit" class="color-negative">Delete</button>
</form>
</li>
{{- end }}
</ul>
{{- end }}
<form method="get" action="{{ $.App.Config.Server.BaseURL }}/edit/pages/{{ $.Page.Slug }}/widgets/{{ $col.Index }}/new" class="flex gap-10 items-center">
<select name="type" required>
<option value="">— add widget —</option>
{{- range $.WidgetTypes }}
<option value="{{ . }}">{{ . }}</option>
{{- end }}
</select>
<button type="submit">Configure & add</button>
</form>
</section>
{{- end }}
</main>
{{ template "footer.html" . }}
</div>
{{- end }}