Initial commit — Bar Pivoine cocktail recipe site

Hugo Extended site with 426 cocktail recipes from the open cocktail dataset.
Dark amber/gold editorial aesthetic, Tailwind CSS v4, Alpine.js client-side
search and filtering, HTMX page transitions, Docker + nginx production build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 11:53:45 +02:00
commit b3b9fb7ac6
462 changed files with 9012 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
<!doctype html>
<html lang="{{ .Site.LanguageCode }}" class="scroll-smooth">
<head>
{{- partial "head.html" . -}}
</head>
<body
class="bg-bg text-ink font-sans min-h-screen flex flex-col antialiased"
hx-boost="true"
hx-select="#main-content"
hx-target="#main-content"
hx-swap="outerHTML"
hx-push-url="true"
>
<!-- HTMX progress bar -->
<div id="progress-bar" aria-hidden="true"></div>
{{- partial "nav.html" . -}}
<main id="main-content" class="flex-1" hx-history-elt>
{{- block "main" . }}{{- end }}
</main>
{{- partial "footer.html" . -}}
<!-- HTMX -->
<script src="https://unpkg.com/htmx.org@2.0.4/dist/htmx.min.js"></script>
<!-- Site JS — must load before Alpine so cocktailSearch() is defined -->
{{- $js := resources.Get "js/main.js" -}}
{{- if eq hugo.Environment "production" -}}
{{- $js = $js | minify | fingerprint "sha256" -}}
{{- end -}}
<script
src="{{ $js.RelPermalink }}"
{{ if eq hugo.Environment "production" }}integrity="{{ $js.Data.Integrity }}"{{ end }}
defer
></script>
<!-- Alpine.js -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.8/dist/cdn.min.js"></script>
{{- block "scripts" . }}{{- end }}
{{- if and (eq hugo.Environment "production") .Site.Params.umamiId -}}
<script defer src="{{ .Site.Params.umamiSrc }}" data-website-id="{{ .Site.Params.umamiId }}"></script>
{{- end -}}
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
{{ define "main" }}
<div class="bg-bg-deep border-b border-warm/10">
<div class="max-w-[1280px] mx-auto px-8 max-[860px]:px-5 py-16">
<div class="eyebrow mb-3">Archive</div>
<h1 class="display text-[clamp(36px,6vw,72px)] mb-4">{{ .Title }}</h1>
</div>
</div>
<div class="max-w-[1280px] mx-auto px-8 max-[860px]:px-5 py-16">
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 mb-12">
{{- range .Paginator.Pages -}}
{{- partial "cocktail-card.html" . -}}
{{- end -}}
</div>
{{- if gt .Paginator.TotalPages 1 -}}
{{- partial "pagination.html" . -}}
{{- end -}}
</div>
{{ end }}
+6
View File
@@ -0,0 +1,6 @@
{{ define "main" }}
<div class="max-w-[1280px] mx-auto px-8 max-[860px]:px-5 py-20">
<h1 class="display text-[clamp(36px,5vw,64px)] mb-8">{{ .Title }}</h1>
<div class="prose text-ink-soft leading-relaxed">{{ .Content }}</div>
</div>
{{ end }}
+98
View File
@@ -0,0 +1,98 @@
{{ define "main" }}
{{- $taxType := .Type -}}
{{- $taxIcon := "❖" -}}
{{- if eq $taxType "glasses" -}}{{- $taxIcon = "▽" -}}
{{- else if eq $taxType "ingredients" -}}{{- $taxIcon = "✦" -}}
{{- else if eq $taxType "categories" -}}{{- $taxIcon = "❖" -}}
{{- end -}}
{{- $cnt := len .Pages -}}
{{- $siblings := slice -}}
{{- $allTerms := index .Site.Taxonomies $taxType -}}
{{- if $allTerms -}}
{{- range $allTerms.ByCount -}}
{{- if ne .Page.Title $.Title -}}
{{- $siblings = $siblings | append . -}}
{{- end -}}
{{- end -}}
{{- end -}}
<div class="max-w-[1280px] mx-auto px-8 max-[860px]:px-5 pb-[90px]">
<!-- Breadcrumbs -->
<nav class="flex gap-[11px] items-center font-mono text-[11px] tracking-[0.1em] uppercase text-ink-faint pt-10 pb-8 flex-wrap">
<a href="/" class="text-ink-mute hover:text-gold-2 transition-colors duration-[160ms]">Bar Pivoine</a>
<span>/</span>
<a href="/{{ .Type }}/" class="text-ink-mute hover:text-gold-2 transition-colors duration-[160ms]">{{ .Type | title }}</a>
<span>/</span>
<span class="text-gold">{{ .Title }}</span>
</nav>
<!-- Tax hero -->
<header class="pb-[46px]">
<div class="text-gold text-[56px] leading-none mb-4">{{ $taxIcon }}</div>
<h1 class="display text-[clamp(44px,6.4vw,80px)]">{{ .Title }}</h1>
<p class="text-ink-soft text-[16px] mt-4">{{ $cnt }} {{ if eq $cnt 1 }}recipe{{ else }}recipes{{ end }}</p>
</header>
<!-- Grid -->
{{- if .Paginator.Pages -}}
<div class="grid [grid-template-columns:repeat(auto-fill,minmax(258px,1fr))] gap-[22px] max-[560px]:[grid-template-columns:repeat(auto-fill,minmax(150px,1fr))] max-[560px]:gap-3.5 mb-12">
{{- range .Paginator.Pages -}}
{{- partial "cocktail-card.html" . -}}
{{- end -}}
</div>
<!-- Hugo pagination -->
{{- if gt .Paginator.TotalPages 1 -}}
<nav class="flex items-center justify-center gap-[6px] pt-14 flex-wrap" aria-label="pages">
{{- if .Paginator.HasPrev -}}
<a href="{{ .Paginator.Prev.URL }}" class="inline-flex items-center gap-[7px] font-mono text-[12px] tracking-[0.1em] uppercase text-ink-soft bg-transparent border border-warm/10 rounded-full px-5 py-[11px] transition-all duration-[180ms] hover:border-gold hover:text-gold-2">
{{- partial "icon.html" "arrow-left" -}} Prev
</a>
{{- else -}}
<span class="inline-flex items-center gap-[7px] font-mono text-[12px] tracking-[0.1em] uppercase text-ink-soft bg-transparent border border-warm/10 rounded-full px-5 py-[11px] opacity-[0.28] cursor-default">
{{- partial "icon.html" "arrow-left" -}} Prev
</span>
{{- end -}}
<div class="flex items-center gap-[2px]">
{{- range .Paginator.Pagers -}}
<a
href="{{ .URL }}"
class="{{ if eq . $.Paginator }}bg-gold text-[#1a1206] font-semibold pointer-events-none{{ else }}bg-transparent text-ink-mute hover:text-ink hover:bg-warm/[0.07]{{ end }} font-mono text-[13px] w-[38px] h-[38px] rounded-full flex items-center justify-center transition-all duration-[150ms]"
{{ if eq . $.Paginator }}aria-current="page"{{ end }}
>{{ .PageNumber }}</a>
{{- end -}}
</div>
{{- if .Paginator.HasNext -}}
<a href="{{ .Paginator.Next.URL }}" class="inline-flex items-center gap-[7px] font-mono text-[12px] tracking-[0.1em] uppercase text-ink-soft bg-transparent border border-warm/10 rounded-full px-5 py-[11px] transition-all duration-[180ms] hover:border-gold hover:text-gold-2">
Next {{- partial "icon.html" "arrow-right" -}}
</a>
{{- else -}}
<span class="inline-flex items-center gap-[7px] font-mono text-[12px] tracking-[0.1em] uppercase text-ink-soft bg-transparent border border-warm/10 rounded-full px-5 py-[11px] opacity-[0.28] cursor-default">
Next {{- partial "icon.html" "arrow-right" -}}
</span>
{{- end -}}
</nav>
{{- end -}}
{{- else -}}
<p class="text-ink-soft text-center py-24">No recipes found.</p>
{{- end -}}
<!-- More in this taxonomy -->
{{- if gt (len $siblings) 0 -}}
<div class="mt-16 pt-[34px] border-t border-warm/10">
<h4 class="font-mono text-[11px] tracking-[0.2em] uppercase text-gold mb-[18px] pb-3 border-b border-warm/10">More {{ .Type }}</h4>
<div class="flex flex-wrap gap-2.5 mt-3">
{{- range first 12 $siblings -}}
<a href="{{ .Page.RelPermalink }}" class="chip">
<span class="dot"></span>
{{ .Page.Title }}
<span class="font-mono opacity-60 ml-1">{{ .Count }}</span>
</a>
{{- end -}}
</div>
</div>
{{- end -}}
</div>
{{ end }}
+29
View File
@@ -0,0 +1,29 @@
{{ define "main" }}
<div class="bg-bg-deep border-b border-warm/10">
<div class="max-w-[1280px] mx-auto px-8 max-[860px]:px-5 py-16">
<div class="eyebrow mb-3">{{ .Type | title }}</div>
<h1 class="display text-[clamp(36px,6vw,72px)] mb-4">{{ .Title }}</h1>
<p class="text-ink-soft text-lg">{{ len .Pages }} {{ .Type | singularize }} types across {{ len .Site.RegularPages }} recipes.</p>
</div>
</div>
<div class="max-w-[1280px] mx-auto px-8 max-[860px]:px-5 py-16">
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{{- range .Pages.ByTitle -}}
<a
href="{{ .RelPermalink }}"
class="group flex items-center justify-between p-4 rounded-xl border border-warm/10 bg-surface hover:border-gold/40 hover:bg-surface-2 transition-all duration-200"
>
<div>
<div class="font-serif font-medium text-xl group-hover:text-gold transition-colors">{{ .Title }}</div>
{{- $cnt := len .Pages -}}
<div class="font-mono text-[11px] text-ink-mute mt-1">{{ $cnt }} {{ if eq $cnt 1 }}recipe{{ else }}recipes{{ end }}</div>
</div>
<div class="text-ink-faint group-hover:text-gold transition-colors">
{{- partial "icon.html" "arrow-right" -}}
</div>
</a>
{{- end -}}
</div>
</div>
{{ end }}