mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-04-23 18:00:32 +00:00
107 lines
6.2 KiB
HTML
107 lines
6.2 KiB
HTML
{{ define "digest" }}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
{{ template "head" . }}
|
|
{{ template "meta" .Meta }}
|
|
</head>
|
|
<body>
|
|
{{ template "nav" . }}
|
|
|
|
<main id="main-content" class="container mx-auto px-4 py-8">
|
|
<div class="space-y-6">
|
|
<!-- Breadcrumb -->
|
|
<div class="text-sm breadcrumbs min-w-0">
|
|
<ul>
|
|
<li class="min-w-0"><a href="/u/{{ .Owner.Handle }}" class="link link-primary truncate">{{ .Owner.Handle }}</a></li>
|
|
<li class="min-w-0"><a href="/r/{{ .Owner.Handle }}/{{ .Repository }}" class="link link-primary truncate">{{ .Repository }}</a></li>
|
|
<li class="min-w-0"><code class="font-mono text-xs truncate">{{ truncateDigest (trimPrefix "sha256:" .Manifest.Digest) 16 }}</code></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Digest Header -->
|
|
<div class="card bg-base-200 shadow-sm border border-base-300 p-6 space-y-3">
|
|
<div class="flex flex-wrap items-start justify-between gap-4">
|
|
<div class="space-y-2 min-w-0">
|
|
<!-- Title: tags or truncated digest -->
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
{{ if .Manifest.Tags }}
|
|
<h1 class="text-xl font-bold">{{ range $i, $tag := .Manifest.Tags }}{{ if $i }}{{ if lt $i 3 }}, {{ end }}{{ end }}{{ if lt $i 3 }}{{ $tag }}{{ end }}{{ end }}{{ if gt (len .Manifest.Tags) 3 }} <span class="text-sm font-normal text-base-content/60" title="{{ range $i, $tag := .Manifest.Tags }}{{ if $i }}, {{ end }}{{ $tag }}{{ end }}">+{{ sub (len .Manifest.Tags) 3 }} more</span>{{ end }}</h1>
|
|
{{ else }}
|
|
<h1 class="text-xl font-bold font-mono" title="{{ .Manifest.Digest }}">{{ truncateDigest (trimPrefix "sha256:" .Manifest.Digest) 16 }}</h1>
|
|
{{ end }}
|
|
{{ if .Manifest.IsManifestList }}
|
|
<span class="badge badge-md badge-soft badge-accent">Multi-arch</span>
|
|
{{ else if eq .Manifest.ArtifactType "helm-chart" }}
|
|
<span class="badge badge-md badge-soft badge-helm">{{ icon "helm" "size-3" }} Helm</span>
|
|
{{ end }}
|
|
{{ if .Manifest.HasAttestations }}
|
|
<span class="badge badge-md badge-soft badge-success">{{ icon "shield-check" "size-3" }} Attested</span>
|
|
{{ end }}
|
|
</div>
|
|
<!-- Digest (small) -->
|
|
<div class="flex items-center gap-2 text-base-content/70">
|
|
<code class="font-mono text-xs" title="{{ .Manifest.Digest }}">{{ truncateDigest (trimPrefix "sha256:" .Manifest.Digest) 16 }}</code>
|
|
<button class="btn btn-ghost btn-xs" data-action="copy" data-copy="{{ .Manifest.Digest }}" aria-label="Copy digest">{{ icon "copy" "size-3" }}</button>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center gap-2 shrink-0">
|
|
<span class="text-base-content text-sm flex items-center gap-1" title="{{ .Manifest.CreatedAt.Format "2006-01-02T15:04:05Z07:00" }}">{{ icon "history" "size-4" }}{{ timeAgoShort .Manifest.CreatedAt }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{{ if .Manifest.IsManifestList }}
|
|
<!-- Architecture Dropdown -->
|
|
<div class="flex items-center gap-3 pt-2 border-t border-base-300">
|
|
<label for="arch-select" class="text-sm font-medium whitespace-nowrap">{{ icon "cpu" "size-4" }} Architecture</label>
|
|
<select id="arch-select" class="select select-sm select-bordered"
|
|
name="digest"
|
|
hx-get="/api/digest-content/{{ .Owner.Handle }}/{{ .Repository }}"
|
|
hx-trigger="change"
|
|
hx-target="#digest-content"
|
|
hx-swap="innerHTML"
|
|
hx-indicator="#arch-loading">
|
|
{{ range .Manifest.Platforms }}
|
|
<option value="{{ .Digest }}"{{ if eq .Digest $.SelectedPlatform }} selected{{ end }}>{{ .OS }}/{{ .Architecture }}{{ if .Variant }}/{{ .Variant }}{{ end }}{{ if .CompressedSize }} ({{ humanizeBytes .CompressedSize }}){{ end }}</option>
|
|
{{ end }}
|
|
</select>
|
|
<span id="arch-loading" class="htmx-indicator" aria-hidden="true">
|
|
{{ icon "loader" "size-4 animate-spin" }}
|
|
</span>
|
|
</div>
|
|
{{ end }}
|
|
</div>
|
|
|
|
<!-- Upgrade Banner (HTMX lazy-loaded) -->
|
|
<div id="upgrade-banner"
|
|
hx-get="/api/upgrade-banner/{{ .Owner.Handle }}/{{ .Repository }}?digest={{ .Manifest.Digest }}{{ if .Manifest.HoldEndpoint }}&holdEndpoint={{ .Manifest.HoldEndpoint }}{{ end }}"
|
|
hx-trigger="load"
|
|
hx-swap="innerHTML">
|
|
</div>
|
|
|
|
<!-- Content: Layers + Vulnerabilities -->
|
|
<div id="digest-content">
|
|
{{ if .Manifest.IsManifestList }}
|
|
<!-- Auto-load selected platform -->
|
|
{{ if .Manifest.Platforms }}
|
|
<div hx-get="/api/digest-content/{{ .Owner.Handle }}/{{ .Repository }}?digest={{ .SelectedPlatform }}"
|
|
hx-trigger="load"
|
|
hx-target="#digest-content"
|
|
hx-swap="innerHTML"
|
|
class="flex items-center justify-center py-12">
|
|
{{ icon "loader" "size-6 animate-spin text-base-content/40" }}
|
|
<span class="ml-2 text-base-content/60">Loading layers and vulnerabilities...</span>
|
|
</div>
|
|
{{ end }}
|
|
{{ else }}
|
|
{{ template "digest-content" . }}
|
|
{{ end }}
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
{{ template "footer" . }}
|
|
</body>
|
|
</html>
|
|
{{ end }}
|