mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-20 01:04:15 +00:00
update fonts
This commit is contained in:
@@ -31,8 +31,8 @@ func (h *HomeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
db.SetRegistryURL(featuredCards, h.RegistryURL)
|
||||
|
||||
// Fetch recently updated repositories (top 24 by last push - 6 rows at 4-col xl)
|
||||
recentCards, err := db.GetRepoCards(h.ReadOnlyDB, 24, currentUserDID, db.SortByLastUpdate)
|
||||
// Fetch recently updated repositories (top 18 by last push - 6 rows at 3-col lg)
|
||||
recentCards, err := db.GetRepoCards(h.ReadOnlyDB, 18, currentUserDID, db.SortByLastUpdate)
|
||||
if err != nil {
|
||||
log.Printf("Error fetching recent repos: %v", err)
|
||||
recentCards = []db.RepoCardData{}
|
||||
|
||||
@@ -425,13 +425,15 @@ func (h *UpdateAutoRemoveUntaggedHandler) ServeHTTP(w http.ResponseWriter, r *ht
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// validOciClients is the set of allowed OCI client values
|
||||
// validOciClients is the set of allowed OCI client values.
|
||||
// "none" means "image reference only" — no `<client> pull ` prefix.
|
||||
var validOciClients = map[string]bool{
|
||||
"docker": true,
|
||||
"podman": true,
|
||||
"buildah": true,
|
||||
"nerdctl": true,
|
||||
"crane": true,
|
||||
"none": true,
|
||||
}
|
||||
|
||||
// UpdateOciClientHandler handles updating the preferred OCI client
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -43,7 +43,6 @@
|
||||
<symbol id="loader" viewBox="0 0 24 24"><path d="M12 2v4"/><path d="m16.2 7.8 2.9-2.9"/><path d="M18 12h4"/><path d="m16.2 16.2 2.9 2.9"/><path d="M12 18v4"/><path d="m4.9 19.1 2.9-2.9"/><path d="M2 12h4"/><path d="m4.9 4.9 2.9 2.9"/></symbol>
|
||||
<symbol id="loader-2" viewBox="0 0 24 24"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></symbol>
|
||||
<symbol id="moon" viewBox="0 0 24 24"><path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/></symbol>
|
||||
<symbol id="package" viewBox="0 0 24 24"><path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z"/><path d="M12 22V12"/><polyline points="3.29 7 12 12 20.71 7"/><path d="m7.5 4.27 9 5.15"/></symbol>
|
||||
<symbol id="pencil" viewBox="0 0 24 24"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/><path d="m15 5 4 4"/></symbol>
|
||||
<symbol id="plus" viewBox="0 0 24 24"><path d="M5 12h14"/><path d="M12 5v14"/></symbol>
|
||||
<symbol id="radio-tower" viewBox="0 0 24 24"><path d="M4.9 16.1C1 12.2 1 5.8 4.9 1.9"/><path d="M7.8 4.7a6.14 6.14 0 0 0-.8 7.5"/><circle cx="12" cy="9" r="2"/><path d="M16.2 4.8c2 2 2.26 5.11.8 7.47"/><path d="M19.1 1.9a9.96 9.96 0 0 1 0 14.1"/><path d="M9.5 18h5"/><path d="m8 22 4-11 4 11"/></symbol>
|
||||
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
@@ -505,6 +505,7 @@ func NewAppViewServer(cfg *Config, branding *BrandingOverrides) (*AppViewServer,
|
||||
|
||||
mainRouter.Handle("/css/*", CacheMiddleware(http.StripPrefix("/css/", PublicSubdir("css", branding)), 31536000))
|
||||
mainRouter.Handle("/js/*", CacheMiddleware(http.StripPrefix("/js/", PublicSubdir("js", branding)), 31536000))
|
||||
mainRouter.Handle("/fonts/*", CacheMiddleware(http.StripPrefix("/fonts/", PublicSubdir("fonts", branding)), 31536000))
|
||||
mainRouter.Handle("/static/*", CacheMiddleware(http.StripPrefix("/static/", PublicSubdir("static", branding)), 31536000))
|
||||
|
||||
slog.Info("UI enabled", "home", "/", "settings", "/settings")
|
||||
|
||||
@@ -15,6 +15,82 @@
|
||||
dark --prefersdark;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
WEB FONTS — Onest (display), Figtree (body), Commit Mono (mono)
|
||||
All self-hosted under /fonts/. Variable bodies for display/body,
|
||||
static weights for mono.
|
||||
======================================== */
|
||||
|
||||
/* Onest — variable (400..800), display face */
|
||||
@font-face {
|
||||
font-family: "Onest";
|
||||
font-style: normal;
|
||||
font-weight: 400 800;
|
||||
font-display: swap;
|
||||
src: url("/fonts/onest-latin.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Onest";
|
||||
font-style: normal;
|
||||
font-weight: 400 800;
|
||||
font-display: swap;
|
||||
src: url("/fonts/onest-latin-ext.woff2") format("woff2");
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* Figtree — variable (300..900), body face */
|
||||
@font-face {
|
||||
font-family: "Figtree";
|
||||
font-style: normal;
|
||||
font-weight: 300 900;
|
||||
font-display: swap;
|
||||
src: url("/fonts/figtree-latin.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Figtree";
|
||||
font-style: normal;
|
||||
font-weight: 300 900;
|
||||
font-display: swap;
|
||||
src: url("/fonts/figtree-latin-ext.woff2") format("woff2");
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* Commit Mono — static 400/400-italic/700, mono face */
|
||||
@font-face {
|
||||
font-family: "Commit Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("/fonts/commit-mono-400.woff2") format("woff2");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Commit Mono";
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("/fonts/commit-mono-400-italic.woff2") format("woff2");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Commit Mono";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("/fonts/commit-mono-700.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
TYPE SYSTEM — semantic tokens
|
||||
Override Tailwind 4's default font stacks so `font-sans` / `font-mono`
|
||||
utilities (and DaisyUI components) pick up our vendored fonts.
|
||||
======================================== */
|
||||
@theme inline {
|
||||
--font-sans: "Figtree", ui-sans-serif, system-ui, sans-serif;
|
||||
--font-mono: "Commit Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
--font-display: "Onest", ui-sans-serif, system-ui, sans-serif;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
DARK - "Deep Ocean"
|
||||
============================================ */
|
||||
@@ -120,6 +196,19 @@
|
||||
border-color: var(--color-star);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
TYPE UTILITIES — display font + tabular numerals
|
||||
`font-display` applies Onest; use it on brand lockups and hero
|
||||
headings. `tabular-nums` aligns numeric columns in dense tables.
|
||||
======================================== */
|
||||
@utility font-display {
|
||||
font-family: var(--font-display);
|
||||
letter-spacing: 0.005em;
|
||||
}
|
||||
@utility tabular-nums {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--shadow-card-hover:
|
||||
0 8px 25px oklch(67.1% 0.05 145 / 0.2), 0 4px 12px oklch(0% 0 0 / 0.2);
|
||||
@@ -161,16 +250,32 @@
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
STICKY FOOTER LAYOUT
|
||||
STICKY FOOTER LAYOUT + BASE TYPE
|
||||
======================================== */
|
||||
@layer base {
|
||||
body {
|
||||
@apply min-h-screen flex flex-col;
|
||||
font-family: var(--font-sans);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
main {
|
||||
@apply flex-1;
|
||||
}
|
||||
|
||||
/* Cap long prose at a comfortable reading width. Pages that need to
|
||||
break out of this (dashboards, tables) override with max-w-* utilities. */
|
||||
.prose {
|
||||
max-width: 68ch;
|
||||
}
|
||||
|
||||
/* Every table gets tabular-nums by default. Registry UIs are tables of
|
||||
numbers (pull counts, sizes, CVE counts, timestamps) — digits should
|
||||
align vertically so the eye can compare rows. */
|
||||
table {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -245,6 +350,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
KEYBOARD FOCUS RING
|
||||
Applied only on :focus-visible so mouse users don't see it.
|
||||
Uses the primary hue so it reads as part of the Deep Ocean palette.
|
||||
======================================== */
|
||||
:where(a, button, [role="button"], [role="tab"], input, select, textarea, summary, [tabindex]):focus-visible {
|
||||
outline: 2px solid var(--color-primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
CUSTOM COMPONENTS (Not in DaisyUI)
|
||||
======================================== */
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
- .HasMore: bool - whether to show Load More button
|
||||
*/}}
|
||||
{{ if .Repositories }}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3{{ if eq .Columns 4 }} xl:grid-cols-4{{ end }} gap-4">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3{{ if eq .Columns 4 }} xl:grid-cols-4{{ end }} gap-6">
|
||||
{{ range .Repositories }}
|
||||
{{ template "repo-card" . }}
|
||||
{{ end }}
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
- Display: string - short form shown in the UI (e.g. "alice.bsky.social/myapp:v1.2.3")
|
||||
- Copy: string - full command copied to clipboard (e.g. "docker pull atcr.io/alice.bsky.social/myapp:v1.2.3")
|
||||
*/}}
|
||||
<div class="cmd group !w-full">
|
||||
{{ icon "package" "size-4 shrink-0 text-base-content/60" }}
|
||||
<code class="flex-1">{{ .Display }}</code>
|
||||
<button class="btn btn-ghost btn-xs shrink-0 sm:opacity-0 sm:group-hover:opacity-100 focus:opacity-100 transition-opacity" data-cmd="{{ .Copy }}" aria-label="Copy pull command to clipboard">
|
||||
<div class="cmd group !w-full !bg-base-100">
|
||||
{{ icon "terminal" "size-4 shrink-0 text-base-content/60" }}
|
||||
<code class="flex-1 min-w-0">{{ .Display }}</code>
|
||||
<button class="btn btn-ghost btn-xs absolute right-1 top-1/2 -translate-y-1/2 sm:opacity-0 sm:group-hover:opacity-100 focus:opacity-100 transition-opacity" data-cmd="{{ .Copy }}" aria-label="Copy pull command to clipboard">
|
||||
{{ icon "copy" "size-4" }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
<!-- Preload critical assets -->
|
||||
<link rel="preload" href="/icons.svg" as="image" type="image/svg+xml">
|
||||
<link rel="preload" href="/fonts/figtree-latin.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/fonts/commit-mono-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
|
||||
<!-- Theme: apply early to prevent flash -->
|
||||
<script>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/}}
|
||||
<section class="hero bg-base-200 min-h-[60vh] py-16 pb-24 relative overflow-hidden">
|
||||
<div class="hero-content text-center flex-col relative z-10 w-full">
|
||||
<h1 class="text-4xl md:text-5xl font-bold">your registry <span class="text-primary">at</span> sea.</h1>
|
||||
<h1 class="text-4xl md:text-5xl font-display font-bold tracking-tight">your registry <span class="text-primary">at</span> sea.</h1>
|
||||
<p class="text-lg text-base-content/70 max-w-lg mt-4">
|
||||
Push and pull Docker images on the AT Protocol.<br>
|
||||
Browse public registries or control your data.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{{ define "nav-brand" }}
|
||||
<a href="/" class="flex items-center gap-2 text-2xl font-bold text-secondary no-underline">
|
||||
<a href="/" class="flex items-center gap-2 text-2xl font-display font-bold text-secondary no-underline tracking-tight">
|
||||
<img src="/favicon-96x96.png" class="h-12 w-auto" alt="{{ .ClientName }} logo">
|
||||
{{ .ClientName }}
|
||||
{{ .ClientName }}
|
||||
</a>
|
||||
{{ end }}
|
||||
|
||||
@@ -28,12 +28,13 @@
|
||||
<option value="nerdctl"{{ if eq .OciClient "nerdctl" }} selected{{ end }}>nerdctl</option>
|
||||
<option value="buildah"{{ if eq .OciClient "buildah" }} selected{{ end }}>buildah</option>
|
||||
<option value="crane"{{ if eq .OciClient "crane" }} selected{{ end }}>crane</option>
|
||||
<option value="none"{{ if eq .OciClient "none" }} selected{{ end }}>image ref only</option>
|
||||
</select>
|
||||
<div id="pull-cmd-display" class="flex-1 min-w-0">
|
||||
{{ if .Tag }}
|
||||
{{ template "docker-command" (print (ociClientName .OciClient) " pull " .RegistryURL "/" .OwnerHandle "/" .RepoName ":" .Tag) }}
|
||||
{{ template "docker-command" (print (pullPrefix .OciClient) .RegistryURL "/" .OwnerHandle "/" .RepoName ":" .Tag) }}
|
||||
{{ else }}
|
||||
{{ template "docker-command" (print (ociClientName .OciClient) " pull " .RegistryURL "/" .OwnerHandle "/" .RepoName ":latest") }}
|
||||
{{ template "docker-command" (print (pullPrefix .OciClient) .RegistryURL "/" .OwnerHandle "/" .RepoName ":latest") }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,7 +60,8 @@
|
||||
}
|
||||
|
||||
window.updatePullCommand = function(client) {
|
||||
var cmd = client + ' pull ' + registryURL + '/' + ownerHandle + '/' + repoName + ':' + tag;
|
||||
var prefix = client === 'none' ? '' : client + ' pull ';
|
||||
var cmd = prefix + registryURL + '/' + ownerHandle + '/' + repoName + ':' + tag;
|
||||
var container = document.getElementById('pull-cmd-display');
|
||||
if (!container) return;
|
||||
var code = container.querySelector('code');
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="font-semibold text-sm truncate">
|
||||
<a href="/u/{{ .OwnerHandle }}" class="link link-primary" onclick="event.stopPropagation()">{{ .OwnerHandle }}</a>
|
||||
<span class="text-base-content/60">/</span>
|
||||
<a href="/r/{{ .OwnerHandle }}/{{ .Repository }}" class="link text-base-content hover:underline" onclick="event.stopPropagation()">{{ .Repository }}</a>
|
||||
<div class="font-semibold text-sm flex items-baseline gap-1 min-w-0">
|
||||
<a href="/u/{{ .OwnerHandle }}" class="link link-primary truncate min-w-0" onclick="event.stopPropagation()">{{ .OwnerHandle }}</a>
|
||||
<span class="text-base-content/60 shrink-0">/</span>
|
||||
<a href="/r/{{ .OwnerHandle }}/{{ .Repository }}" class="link text-base-content hover:underline truncate min-w-0" onclick="event.stopPropagation()">{{ .Repository }}</a>
|
||||
</div>
|
||||
{{ if .Tag }}
|
||||
<span class="block text-base-content/60 text-sm truncate">Tag: {{ .Tag }}</span>
|
||||
@@ -48,22 +48,22 @@
|
||||
{{ if eq .ArtifactType "helm-chart" }}
|
||||
{{ if .Tag }}
|
||||
{{ template "image-ref" (dict
|
||||
"Display" (printf "%s/%s:%s" .OwnerHandle .Repository .Tag)
|
||||
"Display" (printf "%s/%s/%s:%s" .RegistryURL .OwnerHandle .Repository .Tag)
|
||||
"Copy" (printf "helm pull oci://%s/%s/%s --version %s" .RegistryURL .OwnerHandle .Repository .Tag)) }}
|
||||
{{ else }}
|
||||
{{ template "image-ref" (dict
|
||||
"Display" (printf "%s/%s" .OwnerHandle .Repository)
|
||||
"Display" (printf "%s/%s/%s" .RegistryURL .OwnerHandle .Repository)
|
||||
"Copy" (printf "helm pull oci://%s/%s/%s" .RegistryURL .OwnerHandle .Repository)) }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ if .Tag }}
|
||||
{{ template "image-ref" (dict
|
||||
"Display" (printf "%s/%s:%s" .OwnerHandle .Repository .Tag)
|
||||
"Copy" (printf "%s pull %s/%s/%s:%s" (ociClientName .OciClient) .RegistryURL .OwnerHandle .Repository .Tag)) }}
|
||||
"Display" (printf "%s/%s/%s:%s" .RegistryURL .OwnerHandle .Repository .Tag)
|
||||
"Copy" (printf "%s%s/%s/%s:%s" (pullPrefix .OciClient) .RegistryURL .OwnerHandle .Repository .Tag)) }}
|
||||
{{ else }}
|
||||
{{ template "image-ref" (dict
|
||||
"Display" (printf "%s/%s" .OwnerHandle .Repository)
|
||||
"Copy" (printf "%s pull %s/%s/%s" (ociClientName .OciClient) .RegistryURL .OwnerHandle .Repository)) }}
|
||||
"Display" (printf "%s/%s/%s" .RegistryURL .OwnerHandle .Repository)
|
||||
"Copy" (printf "%s%s/%s/%s" (pullPrefix .OciClient) .RegistryURL .OwnerHandle .Repository)) }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
{{ if .RecentRepos }}
|
||||
<section>
|
||||
<h2 class="text-2xl font-bold mb-6">What's New</h2>
|
||||
{{ template "card-grid" (dict "Repositories" .RecentRepos "Columns" 4) }}
|
||||
{{ template "card-grid" (dict "Repositories" .RecentRepos) }}
|
||||
</section>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{{ template "nav" . }}
|
||||
|
||||
<main class="container mx-auto px-4 py-8 max-w-4xl">
|
||||
<h1 class="text-3xl font-bold mb-2">Install {{ .ClientShortName }} Credential Helper</h1>
|
||||
<h1 class="text-3xl font-display font-bold tracking-tight mb-2">Install {{ .ClientShortName }} Credential Helper</h1>
|
||||
<p class="text-base-content/70 mb-8">The {{ .ClientShortName }} credential helper enables Docker to authenticate with {{ .ClientShortName }} registries using your ATProto identity.</p>
|
||||
|
||||
<div class="space-y-12">
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<main class="container mx-auto px-4 py-8 max-w-4xl">
|
||||
<!-- Hero Section -->
|
||||
<section class="text-center mb-16">
|
||||
<h1 class="text-4xl md:text-5xl font-bold mb-4">Docker meets the decentralized web</h1>
|
||||
<h1 class="text-4xl md:text-5xl font-display font-bold tracking-tight mb-4">Docker meets the decentralized web</h1>
|
||||
<p class="text-xl text-base-content/70 max-w-2xl mx-auto">
|
||||
{{ .ClientName }} is an OCI-compliant container registry built on the AT Protocol.
|
||||
Push and pull Docker images using your Bluesky identity.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
<main class="min-h-[calc(100vh-4rem)] flex items-start justify-center px-4 pt-16 sm:pt-24">
|
||||
<div class="w-full max-w-2xl">
|
||||
<h1 class="text-3xl sm:text-4xl font-semibold text-center mb-8">Sign in to {{ .ClientName }}</h1>
|
||||
<h1 class="text-3xl sm:text-4xl font-display font-semibold tracking-tight text-center mb-8">Sign in to {{ .ClientName }}</h1>
|
||||
|
||||
{{ if .Error }}
|
||||
<div class="alert alert-error mb-6">
|
||||
@@ -31,12 +31,13 @@
|
||||
<input type="hidden" name="return_to" value="{{ .ReturnTo }}" />
|
||||
|
||||
<div class="sailor-typeahead relative order-1">
|
||||
<label for="handle" class="sr-only">Atmosphere handle or DID</label>
|
||||
<input type="text"
|
||||
id="handle"
|
||||
name="handle"
|
||||
class="input input-bordered input-lg w-full"
|
||||
placeholder="alice.bsky.social"
|
||||
autocomplete="off"
|
||||
autocomplete="username"
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{{ template "nav" . }}
|
||||
|
||||
<main class="container mx-auto px-4 py-8 max-w-4xl">
|
||||
<h1 class="text-3xl font-bold mb-2">Privacy Policy - {{ .CompanyName }} ({{ .SiteURL }})</h1>
|
||||
<h1 class="text-3xl font-display font-bold tracking-tight mb-2">Privacy Policy - {{ .CompanyName }} ({{ .SiteURL }})</h1>
|
||||
<p class="text-base-content/60 mb-8"><em>Last updated: January 2025</em></p>
|
||||
|
||||
<div class="prose prose-sm max-w-none space-y-8">
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<div class="flex gap-4 items-start">
|
||||
{{ template "repo-avatar" (dict "IconURL" .Repository.IconURL "RepositoryName" .Repository.Name "IsOwner" .IsOwner) }}
|
||||
<div class="flex-1 min-w-0">
|
||||
<h1 class="text-2xl font-bold">
|
||||
<h1 class="text-2xl md:text-3xl font-display font-bold tracking-tight">
|
||||
<a href="/u/{{ .Owner.Handle }}" class="link link-primary">{{ .Owner.Handle }}</a>
|
||||
<span class="text-base-content/60">/</span>
|
||||
<span>{{ .Repository.Name }}</span>
|
||||
@@ -502,9 +502,11 @@
|
||||
if (tab.dataset.tab === tabId) {
|
||||
tab.classList.add('border-primary', 'text-primary');
|
||||
tab.classList.remove('border-transparent', 'text-base-content/60');
|
||||
tab.setAttribute('aria-selected', 'true');
|
||||
} else {
|
||||
tab.classList.remove('border-primary', 'text-primary');
|
||||
tab.classList.add('border-transparent', 'text-base-content/60');
|
||||
tab.setAttribute('aria-selected', 'false');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{{ template "nav" . }}
|
||||
|
||||
<main class="container mx-auto px-4 py-8">
|
||||
<h1 class="text-3xl font-bold mb-6">Settings</h1>
|
||||
<h1 class="text-3xl font-display font-bold tracking-tight mb-6">Settings</h1>
|
||||
|
||||
<!-- Mobile identity info (below lg) -->
|
||||
<div class="lg:hidden mb-4 space-y-1 text-xs text-base-content/50">
|
||||
@@ -67,20 +67,21 @@
|
||||
<p class="text-base-content/70 mt-1">Customize your experience across the site.</p>
|
||||
</div>
|
||||
|
||||
<!-- OCI Client Selector -->
|
||||
<!-- Preferred Client Selector -->
|
||||
<div class="flex items-center gap-4">
|
||||
<div>
|
||||
<label class="text-sm font-medium">OCI Client</label>
|
||||
<p class="text-xs text-base-content/60">Changes how pull commands are displayed across the site.</p>
|
||||
<label for="oci-client-select" class="text-sm font-medium">Preferred client</label>
|
||||
<p id="oci-client-hint" class="text-xs text-base-content/60">Sets the pull command shown on repository pages. Choose <em>Image reference only</em> to copy just the image ref (useful for Kubernetes manifests or docker-compose).</p>
|
||||
</div>
|
||||
{{ $oci := .Profile.OciClient }}
|
||||
<select id="oci-client-select" class="select select-sm select-bordered min-w-40"
|
||||
<select id="oci-client-select" aria-describedby="oci-client-hint" class="select select-sm select-bordered min-w-40"
|
||||
onchange="htmx.ajax('POST', '/api/profile/oci-client', {values: {oci_client: this.value}, swap: 'none'})">
|
||||
<option value="docker"{{ if or (eq $oci "") (eq $oci "docker") }} selected{{ end }}>Docker</option>
|
||||
<option value="podman"{{ if eq $oci "podman" }} selected{{ end }}>Podman</option>
|
||||
<option value="buildah"{{ if eq $oci "buildah" }} selected{{ end }}>Buildah</option>
|
||||
<option value="nerdctl"{{ if eq $oci "nerdctl" }} selected{{ end }}>nerdctl</option>
|
||||
<option value="crane"{{ if eq $oci "crane" }} selected{{ end }}>crane</option>
|
||||
<option value="none"{{ if eq $oci "none" }} selected{{ end }}>Image reference only</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -189,7 +190,7 @@
|
||||
}</code></pre>
|
||||
</li>
|
||||
<li>Run any Docker command:
|
||||
<div class="mt-2">{{ template "docker-command" (print (ociClientName .OciClient) " pull " .RegistryURL "/" .Profile.Handle "/myimage") }}</div>
|
||||
<div class="mt-2">{{ template "docker-command" (print (pullPrefix .OciClient) .RegistryURL "/" .Profile.Handle "/myimage") }}</div>
|
||||
</li>
|
||||
<li>Browser will open for authorization - click Approve</li>
|
||||
<li>Done! Device is automatically authorized</li>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{{ template "nav" . }}
|
||||
|
||||
<main class="container mx-auto px-4 py-8 max-w-4xl">
|
||||
<h1 class="text-3xl font-bold mb-2">Terms of Service - {{ .CompanyName }} ({{ .SiteURL }})</h1>
|
||||
<h1 class="text-3xl font-display font-bold tracking-tight mb-2">Terms of Service - {{ .CompanyName }} ({{ .SiteURL }})</h1>
|
||||
<p class="text-base-content/60 mb-8"><em>Last updated: January 2025</em></p>
|
||||
|
||||
<p class="mb-8">These Terms of Service ("Terms") govern your use of {{ .CompanyName }} ("{{ .SiteURL }}", "the Service", "we", "us", "our"). By using the Service, you agree to these Terms. If you do not agree, do not use the Service.</p>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="text-2xl font-bold">{{ .ViewedUser.Handle }}</h1>
|
||||
<h1 class="text-2xl md:text-3xl font-display font-bold tracking-tight">{{ .ViewedUser.Handle }}</h1>
|
||||
{{ if or (eq .SupporterBadge "Captain") (eq .SupporterBadge "owner") }}
|
||||
<span class="badge badge-sm supporter-badge-owner">{{ .SupporterBadge }}</span>
|
||||
{{ else if .SupporterBadge }}
|
||||
|
||||
@@ -24,9 +24,15 @@
|
||||
{{ else }}<span class="badge badge-xs badge-secondary">Crew</span>{{ end }}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
{{ if eq .Status "online" }}<span class="text-success" title="Online">●</span>
|
||||
{{ else if eq .Status "offline" }}<span class="text-error" title="Offline">●</span>
|
||||
{{ else }}<span class="text-base-content/50" title="Unknown" aria-label="Unknown status">●</span>
|
||||
{{ if eq .Status "online" }}
|
||||
<span class="text-success" aria-hidden="true">●</span>
|
||||
<span class="sr-only">Online</span>
|
||||
{{ else if eq .Status "offline" }}
|
||||
<span class="text-error" aria-hidden="true">●</span>
|
||||
<span class="sr-only">Offline</span>
|
||||
{{ else }}
|
||||
<span class="text-base-content/50" aria-hidden="true">●</span>
|
||||
<span class="sr-only">Unknown</span>
|
||||
{{ end }}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
|
||||
@@ -73,10 +73,13 @@
|
||||
|
||||
<!-- Tab Navigation -->
|
||||
<div class="border-b border-base-300 mt-6">
|
||||
<nav class="flex gap-0 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden" role="tablist">
|
||||
<nav class="flex gap-0 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden" role="tablist" aria-label="Repository sections">
|
||||
<button class="repo-tab shrink-0 whitespace-nowrap px-4 sm:px-6 py-3 text-sm font-medium border-b-2 border-transparent text-base-content/60 transition-colors cursor-pointer"
|
||||
data-tab="overview"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
aria-controls="tab-overview"
|
||||
id="overview-tab-btn"
|
||||
onclick="switchRepoTab('overview')">
|
||||
Overview
|
||||
</button>
|
||||
@@ -84,6 +87,8 @@
|
||||
<button class="repo-tab shrink-0 whitespace-nowrap px-4 sm:px-6 py-3 text-sm font-medium border-b-2 border-transparent text-base-content/60 transition-colors cursor-pointer"
|
||||
data-tab="layers"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
aria-controls="tab-layers"
|
||||
id="layers-tab-btn"
|
||||
onclick="switchRepoTab('layers')">
|
||||
Layers
|
||||
@@ -91,6 +96,8 @@
|
||||
<button class="repo-tab shrink-0 whitespace-nowrap px-4 sm:px-6 py-3 text-sm font-medium border-b-2 border-transparent text-base-content/60 transition-colors cursor-pointer"
|
||||
data-tab="vulns"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
aria-controls="tab-vulns"
|
||||
id="vulns-tab-btn"
|
||||
onclick="switchRepoTab('vulns')">
|
||||
Vulnerabilities
|
||||
@@ -98,6 +105,8 @@
|
||||
<button class="repo-tab shrink-0 whitespace-nowrap px-4 sm:px-6 py-3 text-sm font-medium border-b-2 border-transparent text-base-content/60 transition-colors cursor-pointer"
|
||||
data-tab="sbom"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
aria-controls="tab-sbom"
|
||||
id="sbom-tab-btn"
|
||||
onclick="switchRepoTab('sbom')">
|
||||
SBOM
|
||||
@@ -106,6 +115,8 @@
|
||||
<button class="repo-tab shrink-0 whitespace-nowrap px-4 sm:px-6 py-3 text-sm font-medium border-b-2 border-transparent text-base-content/60 transition-colors cursor-pointer"
|
||||
data-tab="artifacts"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
aria-controls="tab-artifacts"
|
||||
id="artifacts-tab-btn"
|
||||
onclick="switchRepoTab('artifacts')">
|
||||
Artifacts
|
||||
@@ -114,7 +125,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Tab Panels -->
|
||||
<div id="tab-overview" class="repo-panel">
|
||||
<div id="tab-overview" class="repo-panel" role="tabpanel" aria-labelledby="overview-tab-btn" tabindex="0">
|
||||
<div id="overview-view" class="card bg-base-100 shadow-sm p-6 space-y-4 min-w-0">
|
||||
{{ if and .AIAdvisorEnabled .User .IsOwner .SelectedTag }}
|
||||
<div id="ai-advisor-section">
|
||||
@@ -169,7 +180,7 @@
|
||||
</div>
|
||||
|
||||
{{ if .SelectedTag }}
|
||||
<div id="tab-layers" class="repo-panel hidden">
|
||||
<div id="tab-layers" class="repo-panel hidden" role="tabpanel" aria-labelledby="layers-tab-btn" tabindex="0">
|
||||
<div id="layers-content">
|
||||
<div class="flex justify-center py-12">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
@@ -177,7 +188,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tab-vulns" class="repo-panel hidden">
|
||||
<div id="tab-vulns" class="repo-panel hidden" role="tabpanel" aria-labelledby="vulns-tab-btn" tabindex="0">
|
||||
<div id="vulns-content">
|
||||
<div class="flex justify-center py-12">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
@@ -185,7 +196,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tab-sbom" class="repo-panel hidden">
|
||||
<div id="tab-sbom" class="repo-panel hidden" role="tabpanel" aria-labelledby="sbom-tab-btn" tabindex="0">
|
||||
<div id="sbom-content">
|
||||
<div class="flex justify-center py-12">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
@@ -194,7 +205,7 @@
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div id="tab-artifacts" class="repo-panel hidden">
|
||||
<div id="tab-artifacts" class="repo-panel hidden" role="tabpanel" aria-labelledby="artifacts-tab-btn" tabindex="0">
|
||||
<div id="artifacts-content">
|
||||
<div class="flex justify-center py-12">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
|
||||
@@ -56,9 +56,9 @@
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ if .Entry.IsTagged }}
|
||||
{{ template "docker-command" (print (ociClientName .OciClient) " pull " .RegistryURL "/" .OwnerHandle "/" .RepoName ":" .Entry.Label) }}
|
||||
{{ template "docker-command" (print (pullPrefix .OciClient) .RegistryURL "/" .OwnerHandle "/" .RepoName ":" .Entry.Label) }}
|
||||
{{ else }}
|
||||
{{ template "docker-command" (print (ociClientName .OciClient) " pull " .RegistryURL "/" .OwnerHandle "/" .RepoName "@" .Entry.Digest) }}
|
||||
{{ template "docker-command" (print (pullPrefix .OciClient) .RegistryURL "/" .OwnerHandle "/" .RepoName "@" .Entry.Digest) }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
|
||||
{{ if .Matches }}
|
||||
<!-- CVE table -->
|
||||
<div class="overflow-y-auto max-h-[32rem]">
|
||||
<table class="table table-xs table-pin-rows w-full">
|
||||
<div class="overflow-x-auto overflow-y-auto max-h-[32rem]">
|
||||
<table class="table table-xs table-pin-rows w-full min-w-[40rem]">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>CVE</th>
|
||||
|
||||
@@ -348,6 +348,19 @@ func Templates(overrides *BrandingOverrides) (*template.Template, error) {
|
||||
return client
|
||||
},
|
||||
|
||||
// pullPrefix returns the "<client> pull " prefix for a pull command, or an
|
||||
// empty string when the user has selected "none" (image reference only).
|
||||
// Usage: {{ pullPrefix .OciClient }}
|
||||
"pullPrefix": func(client string) string {
|
||||
if client == "none" {
|
||||
return ""
|
||||
}
|
||||
if client == "" {
|
||||
return "docker pull "
|
||||
}
|
||||
return client + " pull "
|
||||
},
|
||||
|
||||
// extraCSS returns a <style> block with consumer CSS overrides, or empty string.
|
||||
"extraCSS": func() template.HTML {
|
||||
if extraCSS == "" {
|
||||
|
||||
@@ -353,8 +353,8 @@ type SailorProfileRecord struct {
|
||||
// overwrite) are deleted from PDS, and their layers are cleaned up by hold GC.
|
||||
AutoRemoveUntagged bool `json:"autoRemoveUntagged,omitempty"`
|
||||
|
||||
// OciClient is the preferred OCI client for pull commands (docker, podman, buildah, nerdctl, crane).
|
||||
// Defaults to "docker" if empty.
|
||||
// OciClient is the preferred client for pull commands (docker, podman, buildah, nerdctl, crane).
|
||||
// "none" means image reference only (no `<client> pull ` prefix). Defaults to "docker" if empty.
|
||||
OciClient string `json:"ociClient,omitempty"`
|
||||
|
||||
// AIAdvisorEnabled controls whether the AI Image Advisor feature is active for this user.
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
<symbol id="loader" viewBox="0 0 24 24"><path d="M12 2v4"/><path d="m16.2 7.8 2.9-2.9"/><path d="M18 12h4"/><path d="m16.2 16.2 2.9 2.9"/><path d="M12 18v4"/><path d="m4.9 19.1 2.9-2.9"/><path d="M2 12h4"/><path d="m4.9 4.9 2.9 2.9"/></symbol>
|
||||
<symbol id="loader-2" viewBox="0 0 24 24"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></symbol>
|
||||
<symbol id="moon" viewBox="0 0 24 24"><path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/></symbol>
|
||||
<symbol id="package" viewBox="0 0 24 24"><path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z"/><path d="M12 22V12"/><polyline points="3.29 7 12 12 20.71 7"/><path d="m7.5 4.27 9 5.15"/></symbol>
|
||||
<symbol id="pencil" viewBox="0 0 24 24"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/><path d="m15 5 4 4"/></symbol>
|
||||
<symbol id="plus" viewBox="0 0 24 24"><path d="M5 12h14"/><path d="M12 5v14"/></symbol>
|
||||
<symbol id="radio-tower" viewBox="0 0 24 24"><path d="M4.9 16.1C1 12.2 1 5.8 4.9 1.9"/><path d="M7.8 4.7a6.14 6.14 0 0 0-.8 7.5"/><circle cx="12" cy="9" r="2"/><path d="M16.2 4.8c2 2 2.26 5.11.8 7.47"/><path d="M19.1 1.9a9.96 9.96 0 0 1 0 14.1"/><path d="M9.5 18h5"/><path d="m8 22 4-11 4 11"/></symbol>
|
||||
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
Reference in New Issue
Block a user