more visual tweaks

This commit is contained in:
Evan Jarrett
2026-01-15 00:17:48 -06:00
parent eb3eed5f7a
commit 908e124917
10 changed files with 101 additions and 46 deletions
+4 -1
View File
@@ -2,6 +2,9 @@ root = "."
tmp_dir = "tmp"
[build]
# Use polling for Docker volume mounts (inotify doesn't work across mounts)
poll = true
poll_interval = 500
# Pre-build: generate assets if missing (each string is a shell command)
pre_cmd = ["go generate ./..."]
cmd = "go build -buildvcs=false -o ./tmp/atcr-appview ./cmd/appview"
@@ -12,7 +15,7 @@ exclude_regex = ["_test\\.go$", "cbor_gen\\.go$", "\\.min\\.js$"]
delay = 3000
stop_on_error = true
send_interrupt = true
kill_delay = 2000
kill_delay = 3000
[log]
time = false
+15 -2
View File
@@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"log/slog"
"net"
"net/http"
"os"
"os/signal"
@@ -464,9 +465,21 @@ func serveRegistry(cmd *cobra.Command, args []string) error {
TangledRepo: cfg.CredentialHelper.TangledRepo,
})
// Create listener with SO_REUSEADDR for hot-reload support
lc := net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
})
},
}
listener, err := lc.Listen(context.Background(), "tcp", cfg.Server.Addr)
if err != nil {
return fmt.Errorf("failed to create listener: %w", err)
}
// Create HTTP server
server := &http.Server{
Addr: cfg.Server.Addr,
Handler: mainRouter,
}
@@ -478,7 +491,7 @@ func serveRegistry(cmd *cobra.Command, args []string) error {
errChan := make(chan error, 1)
go func() {
slog.Info("Starting registry server", "addr", cfg.Server.Addr)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
if err := server.Serve(listener); err != nil && err != http.ErrServerClosed {
errChan <- err
}
}()
File diff suppressed because one or more lines are too long
+40 -6
View File
@@ -23,14 +23,16 @@
@plugin "daisyui/theme" {
name: "light";
default: true;
--color-primary: oklch(75% 0.12 175); /* #4ECDC4 teal */
--color-accent: oklch(68% 0.18 25); /* #FF6B6B coral */
--color-primary: oklch(75% 0.12 175); /* #4ECDC4 teal (body) */
--color-secondary: oklch(68% 0.18 25); /* #FF6B6B coral (cheek) */
--color-accent: oklch(52% 0.08 185); /* #2B7A78 dark teal (mane) */
}
@plugin "daisyui/theme" {
name: "dark";
--color-primary: oklch(78% 0.12 175); /* #5ED4CB slightly brighter */
--color-accent: oklch(72% 0.16 25); /* #FF8080 */
--color-primary: oklch(78% 0.12 175); /* #5ED4CB teal */
--color-secondary: oklch(72% 0.16 25); /* #FF8080 coral */
--color-accent: oklch(58% 0.09 185); /* #3D8B89 dark teal */
}
/* ========================================
@@ -38,12 +40,12 @@
======================================== */
:root {
--shadow-card-hover:
0 8px 25px oklch(75% 0.12 175 / 0.15), 0 4px 12px rgba(0, 0, 0, 0.1);
0 8px 25px oklch(75% 0.12 175 / 0.2), 0 4px 12px rgba(0, 0, 0, 0.1);
}
[data-theme="dark"] {
--shadow-card-hover:
0 8px 25px oklch(78% 0.12 175 / 0.1), 0 4px 12px rgba(0, 0, 0, 0.2);
0 8px 25px oklch(78% 0.12 175 / 0.15), 0 4px 12px rgba(0, 0, 0, 0.2);
}
/* ========================================
@@ -62,6 +64,19 @@
display: block;
}
/* ========================================
STICKY FOOTER LAYOUT
======================================== */
@layer base {
body {
@apply min-h-screen flex flex-col;
}
main {
@apply flex-1;
}
}
/* ========================================
TYPOGRAPHY (PROSE) THEME INTEGRATION
======================================== */
@@ -121,6 +136,25 @@
@apply w-62 opacity-100;
}
/* ----------------------------------------
HELM BRAND COLOR (official Helm blue #0F1689)
---------------------------------------- */
.text-helm {
@apply text-[#0F1689];
}
[data-theme="dark"] .text-helm {
@apply text-[#6B7FFF];
}
.badge-helm {
--badge-color: #0F1689;
}
[data-theme="dark"] .badge-helm {
--badge-color: #6B7FFF;
}
/* ----------------------------------------
CARD EXTENSIONS
---------------------------------------- */
+2 -1
View File
@@ -1,5 +1,6 @@
{{ define "footer" }}
<footer class="footer footer-center bg-base-200 text-base-content p-6 mt-auto">
<footer class="footer footer-center bg-base-200 text-base-content p-6 pt-20 mt-auto relative">
<img src="/static/wave-pattern.svg" alt="" class="absolute top-0 left-0 w-full h-16 pointer-events-none rotate-180" aria-hidden="true">
<nav class="flex flex-wrap justify-center items-center gap-x-2 gap-y-1 text-sm">
<a href="/privacy" class="link link-hover">Privacy</a>
<span class="text-base-content/30">·</span>
@@ -64,7 +64,7 @@
{{ template "star" (dict "IsStarred" .IsStarred "StarCount" .StarCount) }}
{{ template "pull-count" (dict "PullCount" .PullCount) }}
{{ if eq .ArtifactType "helm-chart" }}
<span class="badge badge-sm badge-soft badge-primary" title="Helm chart"><i data-lucide="anchor"></i></span>
<i data-lucide="anchor" class="size-5 text-helm" title="Helm chart"></i>
{{ end }}
</div>
{{ if not .LastUpdated.IsZero }}
+2 -2
View File
@@ -8,7 +8,7 @@
Display mode: renders as span (default)
*/}}
{{ if .Interactive }}
<button class="btn btn-sm gap-2{{ if .IsStarred }} btn-primary{{ else }} btn-ghost{{ end }}"
<button class="btn btn-sm gap-2 btn-ghost group border border-transparent hover:border-primary{{ if .IsStarred }} border-amber-400!{{ end }}"
id="star-btn"
{{ if .IsStarred }}
hx-delete="/api/stars/{{ .Handle }}/{{ .Repository }}"
@@ -18,7 +18,7 @@
hx-swap="outerHTML"
hx-on::before-request="this.disabled=true"
hx-on::after-request="if(event.detail.xhr.status===401) window.location='/auth/oauth/login'">
<i data-lucide="star" class="size-4 text-amber-400 stroke-amber-400{{ if .IsStarred }} fill-amber-400{{ end }}" id="star-icon"></i>
<i data-lucide="star" class="size-4 text-amber-400 stroke-amber-400 transition-transform group-hover:scale-110{{ if .IsStarred }} fill-amber-400{{ end }}" id="star-icon"></i>
<span id="star-count">{{ .StarCount }}</span>
</button>
{{ else }}
+9 -9
View File
@@ -75,11 +75,11 @@
{{ if .Repository.Licenses }}
{{ range parseLicenses .Repository.Licenses }}
{{ if .IsValid }}
<a href="{{ .URL }}" target="_blank" rel="noopener noreferrer" class="badge badge-md badge-secondary" title="{{ .Name }}">
<a href="{{ .URL }}" target="_blank" rel="noopener noreferrer" class="badge badge-md badge-soft badge-secondary" title="{{ .Name }}">
{{ .SPDXID }}
</a>
{{ else }}
<span class="badge badge-md badge-secondary" title="Custom license: {{ .Name }}">
<span class="badge badge-md badge-soft badge-secondary" title="Custom license: {{ .Name }}">
{{ .Name }}
</span>
{{ end }}
@@ -149,12 +149,12 @@
<div class="flex flex-wrap items-center gap-2">
<span class="font-mono font-semibold text-lg">{{ .Tag.Tag }}</span>
{{ if eq .ArtifactType "helm-chart" }}
<span class="badge badge-md badge-soft badge-primary"><i data-lucide="anchor" class="size-3"></i> Helm</span>
<span class="badge badge-md badge-soft badge-helm"><i data-lucide="anchor" class="size-3"></i> Helm</span>
{{ else if .IsMultiArch }}
<span class="badge badge-md badge-primary">Multi-arch</span>
<span class="badge badge-md badge-soft badge-primary">Multi-arch</span>
{{ end }}
{{ if .HasAttestations }}
<span class="badge badge-md badge-success"><i data-lucide="shield-check" class="size-3"></i> Attestations</span>
<span class="badge badge-md badge-soft badge-success"><i data-lucide="shield-check" class="size-3"></i> Attestations</span>
{{ end }}
</div>
<div class="flex items-center gap-2">
@@ -181,7 +181,7 @@
{{ if .Platforms }}
<div class="flex flex-wrap gap-1">
{{ range .Platforms }}
<span class="badge badge-sm badge-secondary">{{ .OS }}/{{ .Architecture }}{{ if .Variant }}/{{ .Variant }}{{ end }}</span>
<span class="badge badge-sm badge-soft badge-secondary">{{ .OS }}/{{ .Architecture }}{{ if .Variant }}/{{ .Variant }}{{ end }}</span>
{{ end }}
</div>
{{ end }}
@@ -219,12 +219,12 @@
{{ if .IsManifestList }}
<span class="flex items-center gap-1 font-medium"><i data-lucide="package" class="size-4"></i> Multi-arch</span>
{{ else if eq .ArtifactType "helm-chart" }}
<span class="flex items-center gap-1 font-medium text-primary"><i data-lucide="anchor" class="size-4"></i> Helm Chart</span>
<span class="flex items-center gap-1 font-medium text-helm"><i data-lucide="anchor" class="size-4"></i> Helm Chart</span>
{{ else }}
<span class="flex items-center gap-1 font-medium"><i data-lucide="box" class="size-4"></i> Image</span>
{{ end }}
{{ if .HasAttestations }}
<span class="badge badge-md badge-success"><i data-lucide="shield-check" class="size-3"></i> Attestations</span>
<span class="badge badge-md badge-soft badge-success"><i data-lucide="shield-check" class="size-3"></i> Attestations</span>
{{ end }}
{{ if .Pending }}
<span class="badge badge-sm badge-info"
@@ -268,7 +268,7 @@
{{ if .Platforms }}
<div class="flex flex-wrap gap-1">
{{ range .Platforms }}
<span class="badge badge-sm badge-secondary">{{ .OS }}/{{ .Architecture }}{{ if .Variant }}/{{ .Variant }}{{ end }}</span>
<span class="badge badge-sm badge-soft badge-secondary">{{ .OS }}/{{ .Architecture }}{{ if .Variant }}/{{ .Variant }}{{ end }}</span>
{{ end }}
</div>
{{ end }}
@@ -19,7 +19,7 @@
<span class="text-base-content/60 mx-1">:</span>
<span class="text-base-content/60">{{ .Tag }}</span>
{{ if eq .ArtifactType "helm-chart" }}
<span class="badge badge-xs badge-soft badge-primary"><i data-lucide="anchor"></i></span>
<span class="badge badge-xs badge-soft badge-helm"><i data-lucide="anchor"></i></span>
{{ end }}
</div>
<div class="flex items-center gap-4 shrink-0">
+26 -22
View File
@@ -573,29 +573,33 @@ func TestTemplateExecution_RepoCard(t *testing.T) {
// Sample data for repo-card template
data := struct {
OwnerHandle string
Repository string
IconURL string
Description string
StarCount int
PullCount int
IsStarred bool
ArtifactType string
Tag string
Digest string
LastUpdated time.Time
OwnerHandle string
OwnerAvatarURL string
Repository string
IconURL string
Description string
StarCount int
PullCount int
IsStarred bool
ArtifactType string
Tag string
Digest string
LastUpdated time.Time
RegistryURL string
}{
OwnerHandle: "alice.bsky.social",
Repository: "myapp",
IconURL: "",
Description: "A cool container image",
StarCount: 42,
PullCount: 1337,
IsStarred: true,
ArtifactType: "container-image",
Tag: "latest",
Digest: "sha256:abc123def456",
LastUpdated: time.Now().Add(-24 * time.Hour),
OwnerHandle: "alice.bsky.social",
OwnerAvatarURL: "",
Repository: "myapp",
IconURL: "",
Description: "A cool container image",
StarCount: 42,
PullCount: 1337,
IsStarred: true,
ArtifactType: "container-image",
Tag: "latest",
Digest: "sha256:abc123def456",
LastUpdated: time.Now().Add(-24 * time.Hour),
RegistryURL: "atcr.io",
}
buf := new(bytes.Buffer)