mirror of
https://github.com/roots/wp-packages
synced 2026-07-22 02:10:54 +08:00
Replace Go's html/template with CloudyKit/jet/v6 for server-rendered templates. Jet provides first-class parameterized blocks, template inheritance via extends/yield, and C-like expressions — eliminating the dict helper workarounds that html/template required for reusable components. Add components.html with four reusable Jet blocks: - shell(command, variant, class) — copyable command boxes (replaces ~16 duplicated instances across 6 templates) - notice(variant, class) with yield content — alert boxes with variant-based styling and content slots - input(icon, name, ...) — form inputs with icon and keyboard hint - pagination(pager, class) — pagination controls driven by pre-computed buildPagination() data Key changes: - templates.go: embed.FS loader for Jet, function registration via AddGlobal, buildPagination() helper, render() using VarMap - handlers.go: simplified render calls (no more template combinations) - router.go: *jet.Set replaces *templateSet - All 13 templates converted to Jet syntax (extends/block/yield) - Tailwind scanning unaffected (templates remain .html files) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
128 lines
12 KiB
HTML
128 lines
12 KiB
HTML
{{extends "layout.html"}}
|
|
{{import "components.html"}}
|
|
{{block title()}}{{if Package.DisplayName}}{{Package.DisplayName}}{{else}}{{Package.Name}}{{end}} — WP Packages{{end}}
|
|
{{block meta_seo()}}
|
|
<meta name="description" content="Install {{if Package.DisplayName}}{{Package.DisplayName}}{{else}}{{Package.Name}}{{end}} with WP Packages: composer require wp-{{Package.Type}}/{{Package.Name}}">
|
|
{{if AppURL}}<link rel="canonical" href="{{AppURL}}/packages/wp-{{Package.Type}}/{{Package.Name}}">{{end}}
|
|
{{end}}
|
|
{{block json_ld()}}{{jsonLD(JSONLD)|raw}}{{end}}
|
|
{{block og_meta()}}
|
|
<meta property="og:title" content="{{if Package.DisplayName}}{{Package.DisplayName}}{{else}}{{Package.Name}}{{end}} — WP Packages">
|
|
<meta property="og:description" content="Install {{if Package.DisplayName}}{{Package.DisplayName}}{{else}}{{Package.Name}}{{end}} with WP Packages: composer require wp-{{Package.Type}}/{{Package.Name}}">
|
|
{{if OGImage}}<meta property="og:image" content="{{OGImage}}">{{end}}
|
|
{{if AppURL}}<meta property="og:url" content="{{AppURL}}/packages/wp-{{Package.Type}}/{{Package.Name}}">{{end}}
|
|
<meta property="og:type" content="website">
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
<meta name="twitter:title" content="{{if Package.DisplayName}}{{Package.DisplayName}}{{else}}{{Package.Name}}{{end}} — WP Packages">
|
|
<meta name="twitter:description" content="Install {{if Package.DisplayName}}{{Package.DisplayName}}{{else}}{{Package.Name}}{{end}} with WP Packages: composer require wp-{{Package.Type}}/{{Package.Name}}">
|
|
{{if OGImage}}<meta name="twitter:image" content="{{OGImage}}">{{end}}
|
|
{{end}}
|
|
{{block body()}}
|
|
<div class="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8 py-8">
|
|
<nav aria-label="Breadcrumb" class="flex items-center gap-1.5 text-sm text-gray-500 mb-8">
|
|
<a href="/" class="hover:text-gray-900 transition-colors">Packages</a>
|
|
<svg class="w-3.5 h-3.5 opacity-40" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5"/></svg>
|
|
<span class="text-gray-900 font-medium truncate">{{if Package.DisplayName}}{{Package.DisplayName}}{{else}}{{Package.Name}}{{end}}</span>
|
|
</nav>
|
|
{{if Untagged}}
|
|
{{yield notice(variant="warning", class="mb-6") content}}
|
|
<div class="min-w-0">
|
|
{{if TrunkOnly}}<p class="font-medium">No tagged releases in SVN</p>
|
|
<p class="mt-1">This plugin releases exclusively via SVN trunk. Install with <code class="text-xs font-mono bg-amber-100 px-1 py-0.5 rounded">dev-trunk</code> — Composer will pin to a specific SVN revision in your lock file. <button onclick="openTagRequest('{{Package.Name}}')" class="font-medium underline underline-offset-2 hover:no-underline cursor-pointer">Ask the author to tag their releases</button> or see <a href="/untagged" class="font-medium underline underline-offset-2 hover:no-underline">all untagged plugins</a>.</p>
|
|
{{else}}<p class="font-medium">Latest version not tagged in SVN</p>
|
|
<p class="mt-1">WordPress.org reports version {{Package.WporgVersion}} but it doesn't match any tagged release, so the latest version isn't available as a tagged release via Composer. <button onclick="openTagRequest('{{Package.Name}}')" class="font-medium underline underline-offset-2 hover:no-underline cursor-pointer">Ask the author to tag their releases</button> or see <a href="/untagged" class="font-medium underline underline-offset-2 hover:no-underline">all untagged plugins</a>.</p>
|
|
<details class="mt-3">
|
|
<summary class="font-medium cursor-pointer hover:underline">Install latest from trunk</summary>
|
|
<p class="mt-2 text-amber-800 mb-2">Install with <code class="text-xs font-mono bg-amber-100 px-1 py-0.5 rounded">dev-trunk</code> to get the latest code. Composer will pin to a specific SVN revision in your lock file.</p>
|
|
{{yield shell(command="composer require wp-"+Package.Type+"/"+Package.Name+":dev-trunk", variant="amber")}}
|
|
</details>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
{{end}}
|
|
<div class="flex items-start gap-4 mb-6">
|
|
<div class="flex w-12 h-12 shrink-0 items-center justify-center rounded-xl bg-brand-lightest/60 ring-1 ring-brand-lighter/30">
|
|
<svg class="w-5 h-5 text-brand-primary" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21 7.5l-9-5.25L3 7.5m18 0l-9 5.25m9-5.25v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-9v9"/></svg>
|
|
</div>
|
|
<div class="min-w-0 flex-1">
|
|
<div class="flex items-center gap-2.5 flex-wrap">
|
|
<h1 class="text-2xl font-bold text-gray-900">{{if Package.DisplayName}}{{Package.DisplayName}}{{else}}{{Package.Name}}{{end}}</h1>
|
|
<span class="inline-flex items-center rounded-md bg-gray-100 px-2 py-0.5 text-xs text-gray-500">{{Package.Type}}</span>
|
|
{{if Package.CurrentVersion}}<span class="text-sm font-mono text-gray-500">v{{Package.CurrentVersion}}</span>{{end}}
|
|
</div>
|
|
<p class="text-sm text-gray-500 font-mono mt-1">wp-{{Package.Type}}/{{Package.Name}}</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center gap-3 mb-10 px-4 py-3 rounded-xl border border-gray-200/60 bg-gray-100/30 cursor-pointer hover:border-gray-300 transition-colors group" onclick="copyCmd(this,'composer require wp-{{Package.Type}}/{{Package.Name}}{{if TrunkOnly}}:dev-trunk{{end}}')">
|
|
<span class="text-gray-500 text-sm font-mono select-none">$</span>
|
|
<code class="flex-1 text-sm font-mono text-gray-900 select-all truncate">composer require wp-{{Package.Type}}/{{Package.Name}}{{if TrunkOnly}}:dev-trunk{{end}}</code>
|
|
<span class="shrink-0 text-xs text-gray-500 opacity-0 group-hover:opacity-100 transition-opacity mr-1">Click to copy</span>
|
|
<svg class="w-4 h-4 shrink-0 text-gray-400" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0 0 13.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 0 1-.75.75H9.75a.75.75 0 0 1-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 0 1-2.25 2.25H6.75A2.25 2.25 0 0 1 4.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 0 1 1.927-.184"/></svg>
|
|
</div>
|
|
<div class="grid gap-10 lg:grid-cols-[1fr_280px]">
|
|
<div class="min-w-0">
|
|
<div class="flex border-b border-gray-200" role="tablist">
|
|
<button class="px-4 pb-3 text-sm font-medium cursor-pointer border-b-2 border-brand-primary text-brand-primary" id="tab-desc" role="tab" aria-selected="true" aria-controls="panel-desc" onclick="document.getElementById('panel-desc').classList.remove('hidden');document.getElementById('panel-ver').classList.add('hidden');this.classList.add('border-brand-primary','text-brand-primary');this.classList.remove('border-transparent','text-gray-500');this.setAttribute('aria-selected','true');const o=document.getElementById('tab-ver');o.classList.remove('border-brand-primary','text-brand-primary');o.classList.add('border-transparent','text-gray-500');o.setAttribute('aria-selected','false')">Description</button>
|
|
<button class="px-4 pb-3 text-sm font-medium cursor-pointer border-b-2 border-transparent text-gray-500 hover:text-gray-700" id="tab-ver" role="tab" aria-selected="false" aria-controls="panel-ver" onclick="document.getElementById('panel-ver').classList.remove('hidden');document.getElementById('panel-desc').classList.add('hidden');this.classList.add('border-brand-primary','text-brand-primary');this.classList.remove('border-transparent','text-gray-500');this.setAttribute('aria-selected','true');const o=document.getElementById('tab-desc');o.classList.remove('border-brand-primary','text-brand-primary');o.classList.add('border-transparent','text-gray-500');o.setAttribute('aria-selected','false')">Versions ({{len(Versions)}})</button>
|
|
</div>
|
|
<div id="panel-desc" role="tabpanel" aria-labelledby="tab-desc" class="mt-8">
|
|
{{if Package.Description}}<p class="text-sm text-gray-500 leading-relaxed">{{Package.Description}}</p>
|
|
{{else}}<div class="text-center py-16"><p class="text-gray-500">No description available.</p></div>{{end}}
|
|
</div>
|
|
<div id="panel-ver" role="tabpanel" aria-labelledby="tab-ver" class="hidden mt-8">
|
|
{{if Versions}}
|
|
<ol class="rounded-xl border border-gray-200/60 overflow-hidden divide-y divide-gray-200/40 list-none m-0 p-0">
|
|
{{range i, v := Versions}}
|
|
<li class="ver-row py-3 px-4 text-sm hover:bg-gray-50/50 transition-colors{{if i >= 5}} hidden{{end}}">
|
|
<div class="flex items-center gap-2">
|
|
<span class="font-mono text-gray-900">{{v.Version}}</span>
|
|
{{if v.IsLatest}}<span class="inline-flex items-center rounded-md bg-brand-primary px-2 py-0.5 text-[10px] font-medium text-white">latest</span>{{end}}
|
|
</div>
|
|
<code class="inline-flex items-center gap-1.5 mt-1 text-xs font-mono text-gray-400 cursor-pointer hover:text-gray-600 transition-colors" onclick="copyCmd(this,'composer require wp-{{Package.Type}}/{{Package.Name}}:{{v.Version}}')"><span>composer require wp-{{Package.Type}}/{{Package.Name}}:{{v.Version}}</span><svg class="w-3.5 h-3.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0 0 13.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 0 1-.75.75H9.75a.75.75 0 0 1-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 0 1-2.25 2.25H6.75A2.25 2.25 0 0 1 4.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 0 1 1.927-.184"/></svg></code>
|
|
</li>
|
|
{{end}}
|
|
</ol>
|
|
{{if len(Versions) > 5}}
|
|
<button id="versions-toggle" class="mt-3 text-sm font-medium text-brand-primary hover:underline" onclick="
|
|
const rows = document.querySelectorAll('.ver-row');
|
|
const showing = this.dataset.expanded === '1';
|
|
for (let i = 5; i < rows.length; i++) {
|
|
rows[i].classList.toggle('hidden', showing);
|
|
}
|
|
this.dataset.expanded = showing ? '0' : '1';
|
|
this.textContent = showing ? 'Show all {{len(Versions)}} versions' : 'Show fewer versions';
|
|
" data-expanded="0">Show all {{len(Versions)}} versions</button>
|
|
{{end}}
|
|
{{else}}<div class="text-center py-16"><p class="text-gray-500">No versions available.</p></div>{{end}}
|
|
</div>
|
|
{{if MonthlyInstalls}}
|
|
<div class="mt-10">
|
|
<h2 class="text-sm font-semibold text-gray-900 mb-3">Composer Installs</h2>
|
|
{{installChart(MonthlyInstalls)|raw}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
<aside class="space-y-4">
|
|
<div class="rounded-xl border border-gray-200/60 bg-white overflow-hidden">
|
|
<div class="px-4 py-3 border-b border-gray-200/40 bg-gray-50/50">
|
|
<h2 class="text-sm font-semibold text-gray-900">Package Info</h2>
|
|
</div>
|
|
<div class="px-4">
|
|
{{if Package.CurrentVersion}}<div class="flex justify-between items-center py-2.5 border-b border-gray-200/30"><span class="text-gray-500 text-sm">Version</span><span class="text-sm text-gray-900 font-medium font-mono">{{Package.CurrentVersion}}</span></div>{{end}}
|
|
<div class="flex justify-between items-center py-2.5 border-b border-gray-200/30"><span class="text-gray-500 text-sm">Active Installs</span><span class="text-sm text-gray-900 font-medium">{{formatNumber(Package.ActiveInstalls)}}</span></div>
|
|
<div class="flex justify-between items-center py-2.5 border-b border-gray-200/30"><span class="text-gray-500 text-sm">Composer Installs</span><span class="text-sm text-gray-900 font-medium">{{formatNumber(Package.WpPackagesInstallsTotal)}}</span></div>
|
|
{{if Package.Author}}<div class="flex justify-between items-center py-2.5 border-b border-gray-200/30"><span class="text-gray-500 text-sm">Author</span><span class="text-sm text-gray-900">{{Package.Author}}</span></div>{{end}}
|
|
</div>
|
|
<div class="px-4 py-3 border-t border-gray-200/40 flex flex-col gap-2">
|
|
<a href="https://wordpress.org/{{if Package.Type == "plugin"}}plugins{{else}}themes{{end}}/{{Package.Name}}/" class="flex items-center gap-1.5 text-sm text-brand-primary hover:underline" rel="noopener">
|
|
<svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"/></svg>
|
|
WordPress.org</a>
|
|
{{if Package.Homepage}}<a href="{{Package.Homepage}}" class="flex items-center gap-1.5 text-sm text-brand-primary hover:underline" rel="noopener">
|
|
<svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"/></svg>
|
|
Homepage</a>{{end}}
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
</div>
|
|
{{end}}
|