mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-05-02 22:25:55 +00:00
page rank/speed/seo improvements
This commit is contained in:
File diff suppressed because one or more lines are too long
33
pkg/appview/public/robots.txt
Normal file
33
pkg/appview/public/robots.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
# ATCR Container Registry - robots.txt
|
||||
|
||||
User-agent: *
|
||||
|
||||
# Allow public pages
|
||||
Allow: /
|
||||
Allow: /r/
|
||||
Allow: /u/
|
||||
Allow: /search
|
||||
Allow: /install
|
||||
Allow: /privacy
|
||||
Allow: /terms
|
||||
|
||||
# Block API endpoints
|
||||
Disallow: /api/
|
||||
Disallow: /v2/
|
||||
|
||||
# Block auth and session pages
|
||||
Disallow: /auth/
|
||||
Disallow: /login
|
||||
Disallow: /settings
|
||||
Disallow: /device/
|
||||
|
||||
# Block OG image generation endpoints
|
||||
Disallow: /og/
|
||||
|
||||
# Block static assets from indexing (optional, saves crawl budget)
|
||||
Disallow: /js/
|
||||
Disallow: /css/
|
||||
Disallow: /static/
|
||||
|
||||
# Sitemap
|
||||
Sitemap: https://atcr.io/sitemap.xml
|
||||
28
pkg/appview/public/sitemap-static.xml
Normal file
28
pkg/appview/public/sitemap-static.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://atcr.io/</loc>
|
||||
<changefreq>daily</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://atcr.io/search</loc>
|
||||
<changefreq>daily</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://atcr.io/install</loc>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://atcr.io/privacy</loc>
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.3</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://atcr.io/terms</loc>
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.3</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
14
pkg/appview/public/sitemap.xml
Normal file
14
pkg/appview/public/sitemap.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<sitemap>
|
||||
<loc>https://atcr.io/sitemap-static.xml</loc>
|
||||
</sitemap>
|
||||
<!-- Future: uncomment when dynamic generation is implemented
|
||||
<sitemap>
|
||||
<loc>https://atcr.io/sitemap-users.xml</loc>
|
||||
</sitemap>
|
||||
<sitemap>
|
||||
<loc>https://atcr.io/sitemap-repos.xml</loc>
|
||||
</sitemap>
|
||||
-->
|
||||
</sitemapindex>
|
||||
@@ -8,7 +8,7 @@
|
||||
<div class="cmd group" onclick="event.stopPropagation()">
|
||||
<i data-lucide="terminal" class="size-4 shrink-0 text-base-content/60"></i>
|
||||
<code>{{ . }}</code>
|
||||
<button class="btn btn-ghost btn-xs absolute right-2 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity" onclick="event.stopPropagation(); copyToClipboard(this.getAttribute('data-cmd'))" data-cmd="{{ . }}">
|
||||
<button class="btn btn-ghost btn-xs absolute right-2 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity" onclick="event.stopPropagation(); copyToClipboard(this.getAttribute('data-cmd'))" data-cmd="{{ . }}" aria-label="Copy command to clipboard">
|
||||
<i data-lucide="copy" class="size-4"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
{{ define "head" }}
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="theme-color" content="#570df8" media="(prefers-color-scheme: light)">
|
||||
<meta name="theme-color" content="#661ae6" media="(prefers-color-scheme: dark)">
|
||||
<meta property="og:locale" content="en_US">
|
||||
|
||||
<!-- Favicons -->
|
||||
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/}}
|
||||
<section class="hero bg-base-200 min-h-[60vh] py-16 pb-24 relative overflow-hidden">
|
||||
<!-- Background mascot -->
|
||||
<img src="/amathea_manatee.png" alt="" class="absolute right-1/2 translate-x-1/2 top-[12%] md:top-[18%] lg:right-[20%] lg:top-[40%] -translate-y-1/2 w-96 md:w-md lg:w-xl opacity-30 pointer-events-none select-none" aria-hidden="true">
|
||||
<img src="/amathea_manatee.png" alt="" fetchpriority="high" class="absolute right-1/2 translate-x-1/2 top-[12%] md:top-[18%] lg:right-[20%] lg:top-[40%] -translate-y-1/2 w-96 md:w-md lg:w-xl opacity-30 pointer-events-none select-none" aria-hidden="true">
|
||||
<div class="hero-content text-center flex-col relative z-10">
|
||||
<h1 class="text-4xl md:text-5xl font-bold">your registry <span class="text-primary">at</span> sea.</h1>
|
||||
<p class="text-lg text-base-content/70 max-w-lg mt-4">
|
||||
@@ -31,7 +31,7 @@
|
||||
<div class="text-primary mb-4 flex justify-center">
|
||||
<i data-lucide="{{ .Icon }}" class="size-8"></i>
|
||||
</div>
|
||||
<h3 class="font-semibold text-lg">{{ .Title }}</h3>
|
||||
<h2 class="font-semibold text-lg">{{ .Title }}</h2>
|
||||
<p class="text-base-content/70 mt-2">{{ .Description }}</p>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{{ define "manifest-modal" }}
|
||||
<dialog class="modal modal-open" onclick="if(event.target===this)this.remove()">
|
||||
<div class="modal-box">
|
||||
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2" onclick="this.closest('dialog').remove()">✕</button>
|
||||
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2" onclick="this.closest('dialog').remove()" aria-label="Close dialog">✕</button>
|
||||
|
||||
<h2 class="text-xl font-semibold mb-4">Manifest Details</h2>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ if .IsOwner }}
|
||||
<label class="absolute inset-0 flex items-center justify-center bg-black/50 opacity-0 hover:opacity-100 transition-opacity cursor-pointer rounded-lg" for="avatar-upload">
|
||||
<label class="absolute inset-0 flex items-center justify-center bg-black/50 opacity-0 hover:opacity-100 transition-opacity cursor-pointer rounded-lg" for="avatar-upload" aria-label="Upload repository icon">
|
||||
<i data-lucide="plus" class="size-8 text-white"></i>
|
||||
</label>
|
||||
<input type="file" id="avatar-upload" name="avatar"
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
<div class="card card-interactive bg-base-200 border-2 border-base-300 p-6 flex flex-col justify-between min-h-60 w-full" onclick="window.location='/r/{{ .OwnerHandle }}/{{ .Repository }}'">
|
||||
<div class="flex gap-4 items-start">
|
||||
{{ if .IconURL }}
|
||||
<img src="{{ .IconURL }}" alt="{{ .Repository }}" class="w-12 rounded-lg object-cover shrink-0">
|
||||
<img src="{{ resizeImage .IconURL 96 }}" alt="{{ .Repository }}" loading="lazy" class="w-12 rounded-lg object-cover shrink-0">
|
||||
{{ else if .OwnerAvatarURL }}
|
||||
<img src="{{ .OwnerAvatarURL }}" alt="{{ .OwnerHandle }}" class="w-12 rounded-lg object-cover shrink-0">
|
||||
<img src="{{ resizeImage .OwnerAvatarURL 96 }}" alt="{{ .OwnerHandle }}" loading="lazy" class="w-12 rounded-lg object-cover shrink-0">
|
||||
{{ else }}
|
||||
<div class="avatar avatar-placeholder">
|
||||
<div class="bg-neutral text-neutral-content w-12 rounded-lg shadow-sm uppercase">
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>404 - Lost at Sea | ATCR</title>
|
||||
<meta name="description" content="Page not found - the requested resource doesn't exist on ATCR">
|
||||
<meta name="robots" content="noindex">
|
||||
{{ template "head" . }}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>ATCR - Distributed Container Registry</title>
|
||||
<meta name="description" content="Push and pull Docker images on the AT Protocol. Same Docker, decentralized.">
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content="ATCR - Distributed Container Registry">
|
||||
<meta property="og:description" content="Push and pull Docker images on the AT Protocol. Same Docker, decentralized.">
|
||||
@@ -17,6 +18,36 @@
|
||||
<meta name="twitter:title" content="ATCR - Distributed Container Registry">
|
||||
<meta name="twitter:description" content="Push and pull Docker images on the AT Protocol. Same Docker, decentralized.">
|
||||
<meta name="twitter:image" content="https://{{ .RegistryURL }}/og/home">
|
||||
<link rel="canonical" href="https://{{ .RegistryURL }}/">
|
||||
<!-- JSON-LD Structured Data -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Organization",
|
||||
"name": "ATCR",
|
||||
"alternateName": "AT Protocol Container Registry",
|
||||
"url": "https://{{ .RegistryURL }}",
|
||||
"logo": "https://{{ .RegistryURL }}/favicon.svg",
|
||||
"description": "Decentralized container registry using AT Protocol. Push and pull Docker images with your AT Protocol identity.",
|
||||
"sameAs": []
|
||||
}
|
||||
</script>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
"name": "ATCR",
|
||||
"url": "https://{{ .RegistryURL }}",
|
||||
"potentialAction": {
|
||||
"@type": "SearchAction",
|
||||
"target": {
|
||||
"@type": "EntryPoint",
|
||||
"urlTemplate": "https://{{ .RegistryURL }}/search?q={search_term_string}"
|
||||
},
|
||||
"query-input": "required name=search_term_string"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{{ template "head" . }}
|
||||
</head>
|
||||
<body>
|
||||
@@ -34,10 +65,10 @@
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-2xl font-bold">Featured</h2>
|
||||
<div class="flex gap-2">
|
||||
<button id="carousel-prev" class="btn btn-circle btn-ghost btn-sm">
|
||||
<button id="carousel-prev" class="btn btn-circle btn-ghost btn-sm" aria-label="Previous featured repository">
|
||||
<i data-lucide="chevron-left" class="size-5"></i>
|
||||
</button>
|
||||
<button id="carousel-next" class="btn btn-circle btn-ghost btn-sm">
|
||||
<button id="carousel-next" class="btn btn-circle btn-ghost btn-sm" aria-label="Next featured repository">
|
||||
<i data-lucide="chevron-right" class="size-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Install ATCR Credential Helper - ATCR</title>
|
||||
<meta name="description" content="Install the ATCR credential helper to push and pull containers using your AT Protocol identity">
|
||||
<link rel="canonical" href="https://{{ .RegistryURL }}/install">
|
||||
{{ template "head" . }}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Login - ATCR</title>
|
||||
<meta name="description" content="Sign in to ATCR with your AT Protocol account to push and pull container images">
|
||||
<link rel="canonical" href="https://{{ .RegistryURL }}/login">
|
||||
{{ template "head" . }}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Privacy Policy - ATCR</title>
|
||||
<meta name="description" content="ATCR privacy policy - how we collect, use, and protect your data on the decentralized container registry">
|
||||
<link rel="canonical" href="https://{{ .RegistryURL }}/privacy">
|
||||
{{ template "head" . }}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ if .Repository.Title }}{{ .Repository.Title }}{{ else }}{{ .Owner.Handle }}/{{ .Repository.Name }}{{ end }} - ATCR</title>
|
||||
<meta name="description" content="{{ if .Repository.Description }}{{ .Repository.Description }}{{ else }}Container image {{ .Owner.Handle }}/{{ .Repository.Name }} on ATCR{{ end }}">
|
||||
<link rel="canonical" href="https://{{ .RegistryURL }}/r/{{ .Owner.Handle }}/{{ .Repository.Name }}">
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content="{{ .Owner.Handle }}/{{ .Repository.Name }} - ATCR">
|
||||
<meta property="og:description" content="{{ if .Repository.Description }}{{ .Repository.Description }}{{ else }}Container image on ATCR{{ end }}">
|
||||
@@ -17,6 +19,28 @@
|
||||
<meta name="twitter:title" content="{{ .Owner.Handle }}/{{ .Repository.Name }} - ATCR">
|
||||
<meta name="twitter:description" content="{{ if .Repository.Description }}{{ .Repository.Description }}{{ else }}Container image on ATCR{{ end }}">
|
||||
<meta name="twitter:image" content="https://{{ .RegistryURL }}/og/r/{{ .Owner.Handle }}/{{ .Repository.Name }}">
|
||||
<!-- JSON-LD Structured Data -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "SoftwareSourceCode",
|
||||
"name": "{{ .Owner.Handle }}/{{ .Repository.Name }}",
|
||||
"description": {{ if .Repository.Description }}"{{ .Repository.Description }}"{{ else }}"Container image on ATCR"{{ end }},
|
||||
"codeRepository": "https://{{ .RegistryURL }}/r/{{ .Owner.Handle }}/{{ .Repository.Name }}",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "{{ .Owner.Handle }}",
|
||||
"url": "https://{{ .RegistryURL }}/u/{{ .Owner.Handle }}"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "ATCR",
|
||||
"url": "https://{{ .RegistryURL }}"
|
||||
}{{ if .Repository.Licenses }},
|
||||
"license": "{{ .Repository.Licenses }}"{{ end }}{{ if .Repository.SourceURL }},
|
||||
"isBasedOn": "{{ .Repository.SourceURL }}"{{ end }}
|
||||
}
|
||||
</script>
|
||||
{{ template "head" . }}
|
||||
</head>
|
||||
<body>
|
||||
@@ -87,7 +111,7 @@
|
||||
<!-- Pull Command -->
|
||||
<div class="space-y-2">
|
||||
{{ if eq .ArtifactType "helm-chart" }}
|
||||
<h3 class="font-semibold">Pull this chart</h3>
|
||||
<p class="font-semibold">Pull this chart</p>
|
||||
{{ if .Tags }}
|
||||
{{ $firstTag := index .Tags 0 }}
|
||||
{{ template "docker-command" (print "helm pull oci://" $.RegistryURL "/" $.Owner.Handle "/" $.Repository.Name " --version " $firstTag.Tag.Tag) }}
|
||||
@@ -95,7 +119,7 @@
|
||||
{{ template "docker-command" (print "helm pull oci://" $.RegistryURL "/" $.Owner.Handle "/" $.Repository.Name) }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
<h3 class="font-semibold">Pull this image</h3>
|
||||
<p class="font-semibold">Pull this image</p>
|
||||
{{ if .Tags }}
|
||||
{{ $firstTag := index .Tags 0 }}
|
||||
{{ template "docker-command" (print "docker pull " $.RegistryURL "/" $.Owner.Handle "/" $.Repository.Name ":" $firstTag.Tag.Tag) }}
|
||||
@@ -149,7 +173,8 @@
|
||||
hx-delete="/api/images/{{ $.Repository.Name }}/tags/{{ .Tag.Tag }}"
|
||||
hx-confirm="Delete tag {{ .Tag.Tag }}?"
|
||||
hx-target="#tag-{{ sanitizeID .Tag.Tag }}"
|
||||
hx-swap="outerHTML">
|
||||
hx-swap="outerHTML"
|
||||
aria-label="Delete tag">
|
||||
<i data-lucide="trash-2" class="size-4"></i>
|
||||
</button>
|
||||
{{ end }}
|
||||
@@ -159,7 +184,7 @@
|
||||
<div class="flex flex-wrap justify-between items-center gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<code class="font-mono text-xs text-base-content/60 truncate max-w-40" title="{{ .Tag.Digest }}">{{ .Tag.Digest }}</code>
|
||||
<button class="btn btn-ghost btn-xs" onclick="copyToClipboard('{{ .Tag.Digest }}')"><i data-lucide="copy" class="size-3"></i></button>
|
||||
<button class="btn btn-ghost btn-xs" onclick="copyToClipboard('{{ .Tag.Digest }}')" aria-label="Copy digest to clipboard"><i data-lucide="copy" class="size-3"></i></button>
|
||||
</div>
|
||||
{{ if .Platforms }}
|
||||
<div class="flex flex-wrap gap-1">
|
||||
@@ -222,7 +247,7 @@
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<code class="font-mono text-xs text-base-content/60 truncate max-w-40" title="{{ .Manifest.Digest }}">{{ .Manifest.Digest }}</code>
|
||||
<button class="btn btn-ghost btn-xs" onclick="copyToClipboard('{{ .Manifest.Digest }}')"><i data-lucide="copy" class="size-3"></i></button>
|
||||
<button class="btn btn-ghost btn-xs" onclick="copyToClipboard('{{ .Manifest.Digest }}')" aria-label="Copy digest to clipboard"><i data-lucide="copy" class="size-3"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -231,7 +256,8 @@
|
||||
</time>
|
||||
{{ if $.IsOwner }}
|
||||
<button class="btn btn-ghost btn-sm text-error"
|
||||
onclick="deleteManifest('{{ $.Repository.Name }}', '{{ .Manifest.Digest }}', '{{ sanitizeID .Manifest.Digest }}')">
|
||||
onclick="deleteManifest('{{ $.Repository.Name }}', '{{ .Manifest.Digest }}', '{{ sanitizeID .Manifest.Digest }}')"
|
||||
aria-label="Delete manifest">
|
||||
<i data-lucide="trash-2" class="size-4"></i>
|
||||
</button>
|
||||
{{ end }}
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Search{{ if .SearchQuery }}: {{ .SearchQuery }}{{ end }} - ATCR</title>
|
||||
<meta name="description" content="{{ if .SearchQuery }}Search results for '{{ .SearchQuery }}' on ATCR container registry{{ else }}Search for container images on ATCR, the decentralized container registry{{ end }}">
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content="Search{{ if .SearchQuery }}: {{ .SearchQuery }}{{ end }} - ATCR">
|
||||
<meta property="og:description" content="{{ if .SearchQuery }}Search results for '{{ .SearchQuery }}' on ATCR container registry{{ else }}Search for container images on ATCR{{ end }}">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://{{ .RegistryURL }}/search{{ if .SearchQuery }}?q={{ .SearchQuery }}{{ end }}">
|
||||
<meta property="og:site_name" content="ATCR">
|
||||
{{ template "head" . }}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Settings - ATCR</title>
|
||||
<meta name="description" content="Manage your ATCR account settings, authorized devices, and storage preferences">
|
||||
<meta name="robots" content="noindex">
|
||||
{{ template "head" . }}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Terms of Service - ATCR</title>
|
||||
<meta name="description" content="ATCR terms of service - rules and guidelines for using the decentralized container registry">
|
||||
<link rel="canonical" href="https://{{ .RegistryURL }}/terms">
|
||||
{{ template "head" . }}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ .ViewedUser.Handle }} - ATCR</title>
|
||||
<meta name="description" content="Container images by {{ .ViewedUser.Handle }} on ATCR, the decentralized container registry">
|
||||
<link rel="canonical" href="https://{{ .RegistryURL }}/u/{{ .ViewedUser.Handle }}">
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content="{{ .ViewedUser.Handle }} - ATCR">
|
||||
<meta property="og:description" content="Container images by {{ .ViewedUser.Handle }} on ATCR">
|
||||
@@ -17,6 +19,19 @@
|
||||
<meta name="twitter:title" content="{{ .ViewedUser.Handle }} - ATCR">
|
||||
<meta name="twitter:description" content="Container images by {{ .ViewedUser.Handle }} on ATCR">
|
||||
<meta name="twitter:image" content="https://{{ .RegistryURL }}/og/u/{{ .ViewedUser.Handle }}">
|
||||
<!-- JSON-LD Structured Data -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ProfilePage",
|
||||
"mainEntity": {
|
||||
"@type": "Person",
|
||||
"name": "{{ .ViewedUser.Handle }}",
|
||||
"url": "https://{{ .RegistryURL }}/u/{{ .ViewedUser.Handle }}"{{ if .ViewedUser.Avatar }},
|
||||
"image": "{{ .ViewedUser.Avatar }}"{{ end }}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{{ template "head" . }}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -104,6 +105,20 @@ func Templates() (*template.Template, error) {
|
||||
}
|
||||
return dict
|
||||
},
|
||||
|
||||
"resizeImage": func(imgURL string, width int) string {
|
||||
if imgURL == "" {
|
||||
return ""
|
||||
}
|
||||
// Only apply Cloudflare Image Resizing to imgs.blue URLs
|
||||
parsed, err := url.Parse(imgURL)
|
||||
if err != nil || parsed.Host != "imgs.blue" {
|
||||
return imgURL
|
||||
}
|
||||
// Cloudflare uses /cdn-cgi/image/width=X/ path format
|
||||
parsed.Path = fmt.Sprintf("/cdn-cgi/image/width=%d%s", width, parsed.Path)
|
||||
return parsed.String()
|
||||
},
|
||||
}
|
||||
|
||||
tmpl := template.New("").Funcs(funcMap)
|
||||
|
||||
Reference in New Issue
Block a user