Add RSVP support and Open Graph meta tags
People can now RSVP without claiming a slot. OG tags show event title, date/time/location, and headcount in link previews. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+34
-5
@@ -2,6 +2,15 @@
|
||||
|
||||
{{define "title"}}{{.Event.Title}} — bbq{{end}}
|
||||
|
||||
{{define "meta"}}
|
||||
<meta property="og:title" content="{{.Event.Title}}">
|
||||
<meta property="og:description" content="{{if .Event.Date}}{{.Event.Date}}{{end}}{{if .Event.Time}} at {{.Event.Time}}{{end}}{{if .Event.Location}} — {{.Event.Location}}{{end}} · {{.TotalGoing}} going">
|
||||
<meta property="og:type" content="website">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="{{.Event.Title}}">
|
||||
<meta name="twitter:description" content="{{if .Event.Date}}{{.Event.Date}}{{end}}{{if .Event.Time}} at {{.Event.Time}}{{end}}{{if .Event.Location}} — {{.Event.Location}}{{end}} · {{.TotalGoing}} going">
|
||||
{{end}}
|
||||
|
||||
{{define "admin-bar"}}{{if .IsAdmin}}<div class="admin-bar">ADMIN VIEW — share the guest link: /e/{{.Event.Slug}}</div>{{end}}{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
@@ -15,8 +24,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-label">What's needed</div>
|
||||
|
||||
<div id="slots-container"
|
||||
hx-ext="sse"
|
||||
sse-connect="/e/{{.Event.Slug}}/sse"
|
||||
@@ -25,10 +32,31 @@
|
||||
{{template "slots-inner" .}}
|
||||
</div>
|
||||
|
||||
<div class="section-label">Add your name</div>
|
||||
<div class="section-label" style="margin-top:40px">Sign up</div>
|
||||
|
||||
<div class="claim-form-wrapper">
|
||||
<div class="form-title">I'll bring something →</div>
|
||||
<div class="form-title">I'm coming →</div>
|
||||
<form hx-post="/e/{{.Event.Slug}}/rsvp"
|
||||
hx-target="#slots-container"
|
||||
hx-swap="innerHTML settle:0.1s"
|
||||
hx-on::after-request="if(event.detail.successful) this.reset()">
|
||||
<div class="form-row">
|
||||
<label>Your name</label>
|
||||
<input type="text" name="name" placeholder="e.g. Sam" required>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Note (optional)</label>
|
||||
<input type="text" name="note" placeholder="e.g. +1, arriving late, etc.">
|
||||
</div>
|
||||
<button class="btn-submit" type="submit">Count me in ↗</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{if .Slots}}
|
||||
<div class="section-label" style="margin-top:40px">I'll bring something</div>
|
||||
|
||||
<div class="claim-form-wrapper">
|
||||
<div class="form-title">Claim a slot →</div>
|
||||
<form hx-post="/e/{{.Event.Slug}}/claim"
|
||||
hx-target="#slots-container"
|
||||
hx-swap="innerHTML settle:0.1s"
|
||||
@@ -49,9 +77,10 @@
|
||||
<label>Note (optional)</label>
|
||||
<input type="text" name="note" placeholder="e.g. bringing sparkling water + lemonade">
|
||||
</div>
|
||||
<button class="btn-submit" type="submit">Count me in ↗</button>
|
||||
<button class="btn-submit" type="submit">Claim ↗</button>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .IsAdmin}}
|
||||
<div class="section-label" style="margin-top:40px">Admin: Add slot</div>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{block "title" .}}picnic{{end}}</title>
|
||||
{{block "meta" .}}{{end}}
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,700;12..96,800&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||
<script src="https://unpkg.com/htmx-ext-sse@2.2.2/sse.js"></script>
|
||||
@@ -319,6 +320,12 @@
|
||||
background: var(--yellow);
|
||||
border-color: var(--border);
|
||||
}
|
||||
.rsvp-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.btn-danger {
|
||||
background: none;
|
||||
border: none;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{{define "slots-inner"}}
|
||||
<div class="section-label">What's needed</div>
|
||||
<div class="slots-grid">
|
||||
{{range .Slots}}
|
||||
<div class="slot-card{{if .IsFull}} full{{end}}">
|
||||
<div class="slot-info">
|
||||
@@ -28,6 +30,25 @@
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<div class="section-label">Going ({{len .Rsvps}})</div>
|
||||
<div class="rsvp-list">
|
||||
{{if .Rsvps}}
|
||||
{{range .Rsvps}}
|
||||
<span class="claim-chip">
|
||||
{{.Name}}{{if .Note}} <small style="color:#888">({{.Note}})</small>{{end}}
|
||||
<button hx-delete="/e/{{$.Event.Slug}}/rsvp/{{.ID}}"
|
||||
hx-target="#slots-container"
|
||||
hx-swap="innerHTML settle:0.1s"
|
||||
hx-confirm="Remove {{.Name}}?"
|
||||
title="Remove">×</button>
|
||||
</span>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<span class="nobody">no one yet</span>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "slots.html"}}{{template "slots-inner" .}}{{end}}
|
||||
|
||||
Reference in New Issue
Block a user