diff --git a/CLAUDE.md b/CLAUDE.md index 816c8ba..c87c11b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -525,7 +525,7 @@ This ensures: ### Key Design Decisions 1. **No fork of distribution**: Uses distribution as library, extends via middleware -2. **Hybrid storage**: Manifests in ATProto (small, federated), blobs in S3 or BYOS (cheap, scalable) +2. **Hybrid storage**: Manifests in ATProto (small), blobs in S3 or BYOS (cheap, scalable) 3. **Content addressing**: Manifests stored by digest, blobs deduplicated globally 4. **ATProto-native**: Manifests are first-class ATProto records, discoverable via AT Protocol 5. **OCI compliant**: Fully compatible with Docker/containerd/podman diff --git a/cmd/appview/serve.go b/cmd/appview/serve.go index 0b31183..59f4e2f 100644 --- a/cmd/appview/serve.go +++ b/cmd/appview/serve.go @@ -338,8 +338,28 @@ func serveRegistry(cmd *cobra.Command, args []string) error { // Mount static files if UI is enabled if uiSessionStore != nil && uiTemplates != nil { - // Mount static files - mainRouter.Handle("/static/*", http.StripPrefix("/static/", appview.StaticHandler())) + // Register dynamic routes for root-level files (favicons, manifests, etc.) + staticHandler := appview.StaticHandler() + rootFiles, err := appview.StaticRootFiles() + if err != nil { + slog.Warn("Failed to scan static root files", "error", err) + } else { + for _, filename := range rootFiles { + // Create a closure to capture the filename + file := filename + mainRouter.Get("/"+file, func(w http.ResponseWriter, r *http.Request) { + // Serve the specific file from static root + r.URL.Path = "/" + file + staticHandler.ServeHTTP(w, r) + }) + } + slog.Info("Registered dynamic root file routes", "count", len(rootFiles), "files", rootFiles) + } + + // Mount subdirectory routes with clean paths + mainRouter.Handle("/css/*", http.StripPrefix("/css/", appview.StaticSubdir("css"))) + mainRouter.Handle("/js/*", http.StripPrefix("/js/", appview.StaticSubdir("js"))) + mainRouter.Handle("/static/*", http.StripPrefix("/static/", appview.StaticSubdir("static"))) slog.Info("UI enabled", "home", "/", "settings", "/settings") } diff --git a/docs/APPVIEW-UI-V1.md b/docs/APPVIEW-UI-V1.md index 57705dc..48d0319 100644 --- a/docs/APPVIEW-UI-V1.md +++ b/docs/APPVIEW-UI-V1.md @@ -4,7 +4,7 @@ The ATCR AppView UI provides a web interface for discovering, managing, and configuring container images in the ATCR registry. Version 1 focuses on three core pages that leverage existing functionality: -1. **Front Page** - Federated image discovery via firehose +1. **Front Page** - Distributed image discovery via firehose 2. **Settings Page** - Profile and hold configuration 3. **Personal Page** - Manage your images and tags @@ -204,7 +204,7 @@ Jetstream is simpler and filters events server-side. ## Page Specifications -### 1. Front Page - Federated Discovery +### 1. Front Page - Distributed Discovery **URL:** `/ui/` or `/ui/explore` diff --git a/docs/EMBEDDED_PDS.md b/docs/EMBEDDED_PDS.md index f4901d7..4d9c6eb 100644 --- a/docs/EMBEDDED_PDS.md +++ b/docs/EMBEDDED_PDS.md @@ -14,7 +14,7 @@ Several ATProto projects face similar challenges with large data storage: | **stream.place** | Video segments | Stream info, chat | Embedded "static PDS" | | **ATCR** | Container blobs | Manifests, comments, builds | Embedded PDS in hold service | -**Common problem:** Large binary data can't realistically live in user PDSs, but application metadata needs a federated home. +**Common problem:** Large binary data can't realistically live in user PDSs, but application metadata needs a distributed home. **ATCR's approach:** Each hold service is a full ATProto actor with its own embedded PDS for **shared data** (captain + crew records, not user-specific data). This PDS stores access control and metadata about the hold itself. diff --git a/pkg/appview/static/apple-touch-icon.png b/pkg/appview/static/apple-touch-icon.png new file mode 100644 index 0000000..9c791c3 Binary files /dev/null and b/pkg/appview/static/apple-touch-icon.png differ diff --git a/pkg/appview/static/favicon-96x96.png b/pkg/appview/static/favicon-96x96.png new file mode 100644 index 0000000..b986682 Binary files /dev/null and b/pkg/appview/static/favicon-96x96.png differ diff --git a/pkg/appview/static/favicon.ico b/pkg/appview/static/favicon.ico new file mode 100644 index 0000000..e1d1acf Binary files /dev/null and b/pkg/appview/static/favicon.ico differ diff --git a/pkg/appview/static/favicon.svg b/pkg/appview/static/favicon.svg new file mode 100644 index 0000000..b458180 --- /dev/null +++ b/pkg/appview/static/favicon.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/pkg/appview/static/site.webmanifest b/pkg/appview/static/site.webmanifest new file mode 100644 index 0000000..ccf313a --- /dev/null +++ b/pkg/appview/static/site.webmanifest @@ -0,0 +1,21 @@ +{ + "name": "MyWebSite", + "short_name": "MySite", + "icons": [ + { + "src": "/web-app-manifest-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/web-app-manifest-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/pkg/appview/static/install.ps1 b/pkg/appview/static/static/install.ps1 similarity index 100% rename from pkg/appview/static/install.ps1 rename to pkg/appview/static/static/install.ps1 diff --git a/pkg/appview/static/install.sh b/pkg/appview/static/static/install.sh similarity index 100% rename from pkg/appview/static/install.sh rename to pkg/appview/static/static/install.sh diff --git a/pkg/appview/static/web-app-manifest-192x192.png b/pkg/appview/static/web-app-manifest-192x192.png new file mode 100644 index 0000000..e1aa38e Binary files /dev/null and b/pkg/appview/static/web-app-manifest-192x192.png differ diff --git a/pkg/appview/static/web-app-manifest-512x512.png b/pkg/appview/static/web-app-manifest-512x512.png new file mode 100644 index 0000000..29bf440 Binary files /dev/null and b/pkg/appview/static/web-app-manifest-512x512.png differ diff --git a/pkg/appview/templates/components/head.html b/pkg/appview/templates/components/head.html new file mode 100644 index 0000000..dc1bfa4 --- /dev/null +++ b/pkg/appview/templates/components/head.html @@ -0,0 +1,20 @@ +{{ define "head" }} + + + + + + + + + + + + + + + + + + +{{ end }} diff --git a/pkg/appview/templates/layouts/base.html b/pkg/appview/templates/layouts/base.html deleted file mode 100644 index 10b27ab..0000000 --- a/pkg/appview/templates/layouts/base.html +++ /dev/null @@ -1,24 +0,0 @@ - - -
- - -