initial commit

This commit is contained in:
2026-08-16 21:18:45 -05:00
commit 1e05a01bcf
122 changed files with 29178 additions and 0 deletions
+184
View File
@@ -0,0 +1,184 @@
{{/* Shared building blocks used across pages. */}}
{{define "sidebar"}}
<nav class="sidebar-nav" aria-label="Main navigation">
<a class="sidebar-link {{if eq .Nav "dashboard"}}active{{end}}" href="/">
<i class="bi bi-speedometer2"></i><span>Dashboard</span>
</a>
<div class="sidebar-heading">DNS</div>
<a class="sidebar-link {{if eq .Nav "zones"}}active{{end}}" href="/zones">
<i class="bi bi-diagram-3"></i><span>Forward Zones</span>
</a>
<a class="sidebar-link {{if eq .Nav "zones-reverse"}}active{{end}}" href="/zones/reverse">
<i class="bi bi-arrow-left-right"></i><span>Reverse Zones</span>
</a>
<a class="sidebar-link {{if eq .Nav "records"}}active{{end}}" href="/records">
<i class="bi bi-list-columns-reverse"></i><span>Records</span>
</a>
<a class="sidebar-link {{if eq .Nav "resolver"}}active{{end}}" href="/resolver">
<i class="bi bi-globe2"></i><span>Resolver</span>
</a>
<a class="sidebar-link {{if eq .Nav "cache"}}active{{end}}" href="/cache">
<i class="bi bi-lightning-charge"></i><span>Cache</span>
</a>
<div class="sidebar-heading">Policies</div>
<a class="sidebar-link {{if eq .Nav "networks"}}active{{end}}" href="/policies/networks">
<i class="bi bi-router"></i><span>Client Networks</span>
</a>
<a class="sidebar-link {{if eq .Nav "blacklists"}}active{{end}}" href="/policies/blacklists">
<i class="bi bi-shield-slash"></i><span>Blacklists</span>
</a>
<a class="sidebar-link {{if eq .Nav "allowlists"}}active{{end}}" href="/policies/allowlists">
<i class="bi bi-shield-check"></i><span>Allowlists</span>
</a>
<a class="sidebar-link {{if eq .Nav "policies"}}active{{end}}" href="/policies">
<i class="bi bi-sliders"></i><span>Rules</span>
</a>
<div class="sidebar-heading">Operations</div>
<a class="sidebar-link {{if eq .Nav "querylog"}}active{{end}}" href="/querylog">
<i class="bi bi-journal-text"></i><span>Query Log</span>
</a>
<a class="sidebar-link {{if eq .Nav "audit"}}active{{end}}" href="/audit">
<i class="bi bi-clipboard-check"></i><span>Audit Log</span>
</a>
<a class="sidebar-link {{if eq .Nav "tools"}}active{{end}}" href="/tools">
<i class="bi bi-tools"></i><span>Tools</span>
</a>
<div class="sidebar-heading">Settings</div>
<a class="sidebar-link {{if eq .Nav "settings"}}active{{end}}" href="/settings/dns">
<i class="bi bi-gear"></i><span>Settings</span>
</a>
<a class="sidebar-link {{if eq .Nav "account"}}active{{end}}" href="/account">
<i class="bi bi-person-badge"></i><span>Account</span>
</a>
</nav>
{{end}}
{{/* Page header: title, optional subtitle and a slot for actions. */}}
{{define "pageheader"}}
<div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-4">
<div>
<h1 class="page-title">{{.Title}}</h1>
{{if .Subtitle}}<p class="text-body-secondary mb-0">{{.Subtitle}}</p>{{end}}
</div>
{{if .Actions}}<div class="d-flex flex-wrap gap-2">{{.Actions}}</div>{{end}}
</div>
{{end}}
{{/* A statistic tile. Pass: Label, Value, Icon, Sub, Tone. */}}
{{define "stat"}}
<div class="col-6 col-md-4 col-xl-3">
<div class="card stat-card h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start">
<div class="stat-label">{{.Label}}</div>
{{if .Icon}}<i class="bi {{.Icon}} stat-icon {{with .Tone}}text-{{.}}{{end}}"></i>{{end}}
</div>
<div class="stat-value">{{.Value}}</div>
{{if .Sub}}<div class="stat-sub">{{.Sub}}</div>{{end}}
</div>
</div>
</div>
{{end}}
{{/* Empty state. Pass: Icon, Title, Message, optional Action (safe HTML). */}}
{{define "empty"}}
<div class="empty-state text-center py-5">
<i class="bi {{.Icon}} empty-icon"></i>
<h2 class="h5 mt-3 mb-2">{{.Title}}</h2>
<p class="text-body-secondary mx-auto" style="max-width: 34rem;">{{.Message}}</p>
{{if .Action}}<div class="mt-3">{{.Action}}</div>{{end}}
</div>
{{end}}
{{/* Pagination. Pass: P (pagination struct), Q (url.Values). */}}
{{define "pagination"}}
{{$p := .P}}{{$q := .Q}}
{{if gt $p.Pages 1}}
<nav class="d-flex flex-wrap justify-content-between align-items-center gap-2 mt-3" aria-label="Pagination">
<div class="text-body-secondary small">
Showing {{num $p.From}}{{num $p.To}} of {{num $p.Total}}
</div>
<ul class="pagination pagination-sm mb-0">
<li class="page-item {{if not $p.HasPrev}}disabled{{end}}">
<a class="page-link" href="{{withQuery $q "page" 1}}" aria-label="First page">&laquo;</a>
</li>
<li class="page-item {{if not $p.HasPrev}}disabled{{end}}">
<a class="page-link" href="{{withQuery $q "page" (sub $p.Page 1)}}" aria-label="Previous page">&lsaquo;</a>
</li>
{{range $n := pages $p.Page $p.Pages}}
<li class="page-item {{if eq $n $p.Page}}active{{end}}">
<a class="page-link" href="{{withQuery $q "page" $n}}">{{$n}}</a>
</li>
{{end}}
<li class="page-item {{if not $p.HasNext}}disabled{{end}}">
<a class="page-link" href="{{withQuery $q "page" (add $p.Page 1)}}" aria-label="Next page">&rsaquo;</a>
</li>
<li class="page-item {{if not $p.HasNext}}disabled{{end}}">
<a class="page-link" href="{{withQuery $q "page" $p.Pages}}" aria-label="Last page">&raquo;</a>
</li>
</ul>
</nav>
{{else if gt $p.Total 0}}
<div class="text-body-secondary small mt-3">{{num $p.Total}} result{{if ne $p.Total 1}}s{{end}}</div>
{{end}}
{{end}}
{{/* A destructive submit button that opens the shared confirmation modal.
Pass: Action, CSRF, Label, Message, optional Icon, Class, ReturnTo. */}}
{{define "confirmform"}}
<form method="post" action="{{.Action}}" class="d-inline js-confirm" data-confirm="{{.Message}}">
<input type="hidden" name="_csrf" value="{{.CSRF}}">
{{if .ReturnTo}}<input type="hidden" name="return_to" value="{{.ReturnTo}}">{{end}}
{{range $k, $v := .Fields}}<input type="hidden" name="{{$k}}" value="{{$v}}">{{end}}
<button type="submit" class="{{if .Class}}{{.Class}}{{else}}btn btn-sm btn-outline-danger{{end}}"
{{if .Title}}title="{{.Title}}"{{end}}>
{{if .Icon}}<i class="bi {{.Icon}}"></i>{{end}}{{if .Label}} {{.Label}}{{end}}
</button>
</form>
{{end}}
{{/* A plain post button with no confirmation. Same fields as confirmform. */}}
{{define "postform"}}
<form method="post" action="{{.Action}}" class="d-inline">
<input type="hidden" name="_csrf" value="{{.CSRF}}">
{{if .ReturnTo}}<input type="hidden" name="return_to" value="{{.ReturnTo}}">{{end}}
{{range $k, $v := .Fields}}<input type="hidden" name="{{$k}}" value="{{$v}}">{{end}}
<button type="submit" class="{{if .Class}}{{.Class}}{{else}}btn btn-sm btn-outline-secondary{{end}}"
{{if .Title}}title="{{.Title}}"{{end}}>
{{if .Icon}}<i class="bi {{.Icon}}"></i>{{end}}{{if .Label}} {{.Label}}{{end}}
</button>
</form>
{{end}}
{{/* Settings sub-navigation. Pass the active key as .Subnav. */}}
{{define "settingsnav"}}
<ul class="nav nav-pills settings-nav mb-4 flex-wrap gap-1">
<li class="nav-item"><a class="nav-link {{if eq .Subnav "dns"}}active{{end}}" href="/settings/dns">DNS</a></li>
<li class="nav-item"><a class="nav-link {{if eq .Subnav "resolver"}}active{{end}}" href="/settings/resolver">Resolver</a></li>
<li class="nav-item"><a class="nav-link {{if eq .Subnav "cache"}}active{{end}}" href="/settings/cache">Cache</a></li>
<li class="nav-item"><a class="nav-link {{if eq .Subnav "http"}}active{{end}}" href="/settings/http">Web Server</a></li>
<li class="nav-item"><a class="nav-link {{if eq .Subnav "logging"}}active{{end}}" href="/settings/logging">Logging</a></li>
<li class="nav-item"><a class="nav-link {{if eq .Subnav "database"}}active{{end}}" href="/settings/database">Database</a></li>
<li class="nav-item"><a class="nav-link {{if eq .Subnav "api"}}active{{end}}" href="/settings/api">API</a></li>
<li class="nav-item"><a class="nav-link {{if eq .Subnav "account"}}active{{end}}" href="/account">Authentication</a></li>
</ul>
{{end}}
{{/* Marks a field that needs a restart to take effect. */}}
{{define "restartbadge"}}
<span class="badge text-bg-warning-subtle border border-warning-subtle text-warning-emphasis ms-1"
title="Changing this requires a restart">restart required</span>
{{end}}