A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go
81
fork

Configure Feed

Select the types of activity you want to include in your feed.

make navbar a component

+55 -50
+1
pkg/appview/config.go
··· 251 251 // Auto-detect from HTTP addr 252 252 if httpAddr[0] == ':' { 253 253 // Just a port, assume localhost 254 + // Use "127.0.0.1" per RFC 8252 (OAuth servers reject "localhost") 254 255 return fmt.Sprintf("http://127.0.0.1%s", httpAddr) 255 256 } 256 257
+5
pkg/appview/templates/components/nav-brand.html
··· 1 + {{ define "nav-brand" }} 2 + <div class="nav-brand"> 3 + <a href="/"><span class="at-protocol">at://</span>Container Registry</a> 4 + </div> 5 + {{ end }}
+7
pkg/appview/templates/components/nav-search.html
··· 1 + {{ define "nav-search" }} 2 + <div class="nav-search"> 3 + <form action="/search" method="get"> 4 + <input type="text" name="q" placeholder="Search images..." value="{{ .Query }}" /> 5 + </form> 6 + </div> 7 + {{ end }}
+3
pkg/appview/templates/components/nav-theme-toggle.html
··· 1 + {{ define "nav-theme-toggle" }} 2 + <button id="theme-toggle" onclick="toggleTheme()" class="btn-link theme-toggle-btn" aria-label="Toggle theme"></button> 3 + {{ end }}
+27
pkg/appview/templates/components/nav-user.html
··· 1 + {{ define "nav-user" }} 2 + {{ if .User }} 3 + <div class="user-dropdown"> 4 + <button class="user-menu-btn" id="user-menu-btn" aria-expanded="false" aria-haspopup="true"> 5 + {{ if .User.Avatar }} 6 + <img src="{{ .User.Avatar }}" alt="{{ .User.Handle }}" class="user-avatar"> 7 + {{ else }} 8 + <div class="user-avatar-placeholder">{{ firstChar .User.Handle }}</div> 9 + {{ end }} 10 + <span class="user-handle">@{{ .User.Handle }}</span> 11 + <svg class="dropdown-arrow" width="12" height="12" viewBox="0 0 12 12" fill="currentColor"> 12 + <path d="M6 9L1 4h10z"/> 13 + </svg> 14 + </button> 15 + <div class="dropdown-menu" id="user-dropdown-menu" hidden> 16 + <a href="/u/{{ .User.Handle }}" class="dropdown-item">Your Repositories</a> 17 + <a href="/settings" class="dropdown-item">Settings</a> 18 + <hr class="dropdown-divider"> 19 + <form action="/auth/logout" method="POST"> 20 + <button type="submit" class="dropdown-item logout-btn">Logout</button> 21 + </form> 22 + </div> 23 + </div> 24 + {{ else }} 25 + <a href="/auth/oauth/login?return_to=/" class="btn-primary">Login</a> 26 + {{ end }} 27 + {{ end }}
+11 -34
pkg/appview/templates/components/nav.html
··· 1 1 {{ define "nav" }} 2 2 <nav class="navbar"> 3 - <div class="nav-brand"> 4 - <a href="/"><span class="at-protocol">at://</span>Container Registry</a> 3 + {{ template "nav-brand" }} 4 + {{ template "nav-search" . }} 5 + <div class="nav-links"> 6 + {{ template "nav-theme-toggle" }} 7 + {{ template "nav-user" . }} 5 8 </div> 9 + </nav> 10 + {{ end }} 6 11 7 - <div class="nav-search"> 8 - <form action="/search" method="get"> 9 - <input type="text" name="q" placeholder="Search images..." value="{{ .Query }}" /> 10 - </form> 11 - </div> 12 - 12 + {{ define "nav-simple" }} 13 + <nav class="navbar"> 14 + {{ template "nav-brand" }} 13 15 <div class="nav-links"> 14 - <button id="theme-toggle" onclick="toggleTheme()" class="btn-link theme-toggle-btn" aria-label="Toggle theme"></button> 15 - {{ if .User }} 16 - <div class="user-dropdown"> 17 - <button class="user-menu-btn" id="user-menu-btn" aria-expanded="false" aria-haspopup="true"> 18 - {{ if .User.Avatar }} 19 - <img src="{{ .User.Avatar }}" alt="{{ .User.Handle }}" class="user-avatar"> 20 - {{ else }} 21 - <div class="user-avatar-placeholder">{{ firstChar .User.Handle }}</div> 22 - {{ end }} 23 - <span class="user-handle">@{{ .User.Handle }}</span> 24 - <svg class="dropdown-arrow" width="12" height="12" viewBox="0 0 12 12" fill="currentColor"> 25 - <path d="M6 9L1 4h10z"/> 26 - </svg> 27 - </button> 28 - <div class="dropdown-menu" id="user-dropdown-menu" hidden> 29 - <a href="/u/{{ .User.Handle }}" class="dropdown-item">Your Repositories</a> 30 - <a href="/settings" class="dropdown-item">Settings</a> 31 - <hr class="dropdown-divider"> 32 - <form action="/auth/logout" method="POST"> 33 - <button type="submit" class="dropdown-item logout-btn">Logout</button> 34 - </form> 35 - </div> 36 - </div> 37 - {{ else }} 38 - <a href="/auth/oauth/login?return_to=/" class="btn-primary">Login</a> 39 - {{ end }} 16 + {{ template "nav-theme-toggle" }} 40 17 </div> 41 18 </nav> 42 19 {{ end }}
+1 -5
pkg/appview/templates/pages/login.html
··· 6 6 {{ template "head" . }} 7 7 </head> 8 8 <body> 9 - <nav class="navbar"> 10 - <div class="nav-brand"> 11 - <a href="/">ATCR</a> 12 - </div> 13 - </nav> 9 + {{ template "nav-simple" . }} 14 10 15 11 <main class="container"> 16 12 <div class="login-page">
-11
pkg/auth/oauth/client.go
··· 62 62 } else { 63 63 config = oauth.NewLocalhostConfig(redirectURI, scopes) 64 64 65 - // Append client_name to localhost client ID query string 66 - if clientName != "" { 67 - u, err := url.Parse(config.ClientID) 68 - if err == nil { 69 - q := u.Query() 70 - q.Set("client_name", clientName) 71 - u.RawQuery = q.Encode() 72 - config.ClientID = u.String() 73 - } 74 - } 75 - 76 65 slog.Info("Using public OAuth client (localhost development)") 77 66 } 78 67