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

Configure Feed

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

update search results page

+71 -46
+1
.tangled/workflows/lint.yaml
··· 15 15 command: | 16 16 go mod download 17 17 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.2 18 + go generate ./... 18 19 19 20 - name: Run Linter 20 21 environment:
+1
.tangled/workflows/tests.yml
··· 14 14 CGO_ENABLED: 1 15 15 command: | 16 16 go mod download 17 + go generate ./... 17 18 18 19 - name: Run Tests 19 20 environment:
+51
pkg/appview/templates/components/card-grid.html
··· 1 + {{ define "card-grid" }} 2 + {{/* 3 + Card grid component - displays repository cards in a responsive grid 4 + 5 + Required: 6 + - .Repositories: []db.RepoCardData - list of repositories to display 7 + 8 + Optional: 9 + - .Columns: int - number of columns on xl screens (3 or 4, default 3) 10 + - .EmptyMessage: string - message when no repositories (default: "No repositories found.") 11 + - .EmptyIcon: string - lucide icon name for empty state 12 + - .EmptySubtext: string - secondary text for empty state 13 + - .LoadMoreURL: string - URL for Load More button (HTMX) 14 + - .TargetID: string - HTMX target ID for Load More 15 + - .HasMore: bool - whether to show Load More button 16 + */}} 17 + {{ if .Repositories }} 18 + <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"> 19 + {{ range .Repositories }} 20 + {{ template "repo-card" . }} 21 + {{ end }} 22 + </div> 23 + {{ if and .HasMore .LoadMoreURL }} 24 + <div class="mt-6 text-center"> 25 + <button 26 + class="btn btn-outline" 27 + hx-get="{{ .LoadMoreURL }}" 28 + hx-trigger="click" 29 + hx-target="#{{ .TargetID }}" 30 + hx-swap="beforeend" 31 + > 32 + Load More 33 + </button> 34 + </div> 35 + {{ end }} 36 + {{ else }} 37 + <div class="py-12 text-center"> 38 + {{ if .EmptyIcon }} 39 + <div class="text-base-content/60 mb-4"> 40 + <i data-lucide="{{ .EmptyIcon }}" class="size-12 mx-auto mb-4"></i> 41 + <p class="text-lg">{{ or .EmptyMessage "No repositories found." }}</p> 42 + </div> 43 + {{ if .EmptySubtext }} 44 + <p class="text-base-content/40 text-sm">{{ .EmptySubtext }}</p> 45 + {{ end }} 46 + {{ else }} 47 + <p class="text-base-content/60">{{ or .EmptyMessage "No repositories found." }}</p> 48 + {{ end }} 49 + </div> 50 + {{ end }} 51 + {{ end }}
+1 -5
pkg/appview/templates/pages/home.html
··· 56 56 {{ if .RecentRepos }} 57 57 <section> 58 58 <h2 class="text-2xl font-bold mb-6">What's New</h2> 59 - <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6"> 60 - {{ range .RecentRepos }} 61 - {{ template "repo-card" . }} 62 - {{ end }} 63 - </div> 59 + {{ template "card-grid" (dict "Repositories" .RecentRepos) }} 64 60 </section> 65 61 {{ end }} 66 62 </div>
+5 -3
pkg/appview/templates/pages/privacy.html
··· 89 89 <p>If you are located in the European Economic Area (EEA), you have the following rights:</p> 90 90 91 91 <h3 class="text-lg font-medium mt-4">Right to Access</h3> 92 - <p>You may request a copy of all personal data we store about you. This includes:</p> 92 + <p>You may export a copy of all personal data we store about you via the "Export Data" button in your account settings. This export includes:</p> 93 93 <ul class="list-disc list-inside space-y-1 ml-4"> 94 94 <li>Layer records associated with your DID on our PDS</li> 95 - <li>Server logs containing your handle, DID, IP address, or actions (if retained)</li> 96 95 <li>OAuth tokens, web UI sessions, and device tokens</li> 97 96 <li>Cached PDS data</li> 98 97 <li>List of registered devices (credential helper)</li> 99 98 </ul> 99 + <p class="mt-2">For data not included in the self-service export (such as server logs), contact us and we will respond within 30 days.</p> 100 100 <p class="text-base-content/70 text-sm mt-2">Note: Data stored on your own PDS is already under your control and accessible to you directly.</p> 101 101 102 102 <h3 class="text-lg font-medium mt-6">Right to Erasure ("Right to be Forgotten")</h3> ··· 156 156 <p>If you are a California resident, you have the following rights under the California Consumer Privacy Act:</p> 157 157 158 158 <h3 class="text-lg font-medium mt-4">Right to Know</h3> 159 - <p>You may request disclosure of:</p> 159 + <p>You may export a copy of your personal data via the "Export Data" button in your account settings. You may also request disclosure of:</p> 160 160 <ul class="list-disc list-inside space-y-1 ml-4"> 161 161 <li>The categories of personal information we collect</li> 162 162 <li>The purposes for which we use your personal information</li> 163 163 <li>The categories of third parties with whom we share your personal information</li> 164 164 </ul> 165 + <p class="mt-2">For data not included in the self-service export (such as server logs), contact us and we will respond within 30 days.</p> 165 166 166 167 <h3 class="text-lg font-medium mt-6">Right to Delete</h3> 167 168 <p>You may delete your personal information via the account settings page, subject to the same technical limitations described in the GDPR section above. For data not accessible through self-service, we will respond to requests within 45 days, except where retention is necessary for:</p> ··· 305 306 <h3 class="text-lg font-medium mt-4">Self-Service (via Settings)</h3> 306 307 <p>Most data management can be done directly through your account settings at {{ .RegistryURL }}:</p> 307 308 <ul class="list-disc list-inside space-y-1 ml-4"> 309 + <li><strong>Export your data:</strong> Use the "Export Data" button in settings to download a copy of all personal data we store about you.</li> 308 310 <li><strong>Delete your data:</strong> Use the "Delete Account" button in settings. This will remove your layer records, cached data, and authentication tokens. You may also choose to have us delete <code class="bg-base-200 px-1.5 py-0.5 rounded text-sm font-mono">io.atcr.*</code> records from your PDS (requires active OAuth session).</li> 309 311 <li><strong>Revoke device tokens:</strong> Manage and revoke credential helper devices in settings.</li> 310 312 <li><strong>Update your data:</strong> Corrections happen through normal use of the service.</li>
+2 -8
pkg/appview/templates/pages/user.html
··· 53 53 <div class="text-center text-base-content/60 py-12"> 54 54 <p>This user hasn't set up their ATCR profile yet.</p> 55 55 </div> 56 - {{ else if .Repositories }} 57 - <div class="w-full grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"> 58 - {{ range .Repositories }} 59 - {{ template "repo-card" . }} 60 - {{ end }} 61 - </div> 62 56 {{ else }} 63 - <div class="text-center text-base-content/60 py-12"> 64 - <p>No images yet.</p> 57 + <div class="w-full"> 58 + {{ template "card-grid" (dict "Repositories" .Repositories "EmptyMessage" "No images yet.") }} 65 59 </div> 66 60 {{ end }} 67 61 </div>
+9 -29
pkg/appview/templates/partials/search-results.html
··· 1 1 {{/* Search results partial - renders repository cards in a grid */}} 2 - {{ if gt (len .Repositories) 0 }} 3 - <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6"> 4 - {{ range .Repositories }} 5 - {{ template "repo-card" . }} 6 - {{ end }} 7 - </div> 8 - 9 - {{ if .HasMore }} 10 - <div class="mt-6 text-center"> 11 - <button 12 - class="btn btn-outline" 13 - hx-get="/api/search-results?q={{ .SearchQuery }}&offset={{ .NextOffset }}" 14 - hx-trigger="click" 15 - hx-target="#search-results" 16 - hx-swap="beforeend" 17 - > 18 - Load More 19 - </button> 20 - </div> 21 - {{ end }} 22 - {{ else }} 23 - <div class="py-12 text-center"> 24 - <div class="text-base-content/60 mb-4"> 25 - <i data-lucide="search-x" class="size-12 mx-auto mb-4"></i> 26 - <p class="text-lg">No repositories found matching your search.</p> 27 - </div> 28 - <p class="text-base-content/40 text-sm">Try a different search term or browse the homepage.</p> 29 - </div> 30 - {{ end }} 2 + {{ template "card-grid" (dict 3 + "Repositories" .Repositories 4 + "EmptyIcon" "search-x" 5 + "EmptyMessage" "No repositories found matching your search." 6 + "EmptySubtext" "Try a different search term or browse the homepage." 7 + "LoadMoreURL" (printf "/api/search-results?q=%s&offset=%d" .SearchQuery .NextOffset) 8 + "TargetID" "search-results" 9 + "HasMore" .HasMore 10 + ) }}
+1 -1
pkg/appview/ui.go
··· 12 12 "atcr.io/pkg/appview/licenses" 13 13 ) 14 14 15 - //go:generate sh -c "cd ../.. && npm run build" 15 + //go:generate sh -c "command -v npm >/dev/null 2>&1 && cd ../.. && npm run build || echo 'npm not found, skipping build'" 16 16 17 17 //go:embed templates/**/*.html 18 18 var templatesFS embed.FS