Files
2026-07-13 17:21:01 -04:00

158 lines
7.2 KiB
HTML

{{template "layout" .}}
{{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:image" content="{{.BaseURL}}/e/{{.Event.Slug}}/og.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:type" content="website">
<meta name="twitter:card" content="summary_large_image">
<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">
<meta name="twitter:image" content="{{.BaseURL}}/e/{{.Event.Slug}}/og.png">
{{end}}
{{define "admin-bar"}}{{if .IsAdmin}}<div class="admin-bar">ADMIN VIEW — <button onclick="navigator.clipboard.writeText(window.location.origin+'/e/{{.Event.Slug}}').then(()=>{this.textContent='Copied!';setTimeout(()=>{this.textContent='Copy guest link'},1500)})" style="background:none;border:none;font-family:inherit;font-size:inherit;cursor:pointer;text-decoration:underline;color:inherit;">Copy guest link</button></div>{{end}}{{end}}
{{define "content"}}
<div class="event-header">
<div class="event-tag">Open · {{.TotalGoing}} going{{if .Capped}} · {{if .CapFull}}FULL{{else}}{{.SpotsLeft}} spot{{if ne .SpotsLeft 1}}s{{end}} left{{end}}{{end}}</div>
<h1 class="event-title">{{.Event.Title}}</h1>
<div class="event-meta">
{{if .Event.Date}}<span>&#128197; {{.Event.Date}}</span>{{end}}
{{if .Event.Time}}<span>&#128338; {{.Event.Time}}</span>{{end}}
{{if .Event.Location}}<span>&#128205; {{.Event.Location}}</span>{{end}}
</div>
{{if .DescriptionHTML}}
<div class="event-description">{{.DescriptionHTML}}</div>
{{end}}
</div>
<div id="slots-container"
hx-ext="sse"
sse-connect="/e/{{.Event.Slug}}/sse"
sse-swap="message"
hx-swap="innerHTML settle:0.1s">
{{template "slots-inner" .}}
</div>
<div class="section-label" style="margin-top:40px">Sign up</div>
{{if and .Capped .CapFull}}
<div class="claim-form-wrapper">
<div class="form-title">Event is full</div>
<p style="font-family:'DM Mono',monospace;font-size:0.8rem;color:#555;">
All {{.Event.AttendeeCap}} spots are taken.
</p>
</div>
{{else if and .Capped (not .User)}}
<div class="claim-form-wrapper">
<div class="form-title">Log in to RSVP</div>
<p style="font-family:'DM Mono',monospace;font-size:0.8rem;color:#555;margin-bottom:16px;">
This event has limited spots ({{.SpotsLeft}} left), so RSVPs require an account.
</p>
<a class="btn-submit" style="display:inline-block;text-decoration:none;text-align:center;"
href="/login?next=/e/{{.Event.Slug}}">Log in to RSVP &#8599;</a>
</div>
{{else}}
<div class="claim-form-wrapper">
<div class="form-title">I'm coming &#8594;</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 value="{{if .User}}{{.User.Name}}{{end}}">
</div>
{{if .Slots}}
<div class="form-row">
<label>Bringing something?</label>
<select name="slot_id" onchange="document.getElementById('claim-note').style.display = this.value ? '' : 'none'; document.getElementById('claim-note-input').placeholder = this.value ? 'e.g. bringing sparkling water + lemonade' : 'e.g. +1, arriving late, etc.'">
<option value="">Just myself</option>
{{range .Slots}}{{if not .IsFull}}
<option value="{{.Slot.ID}}">{{.Slot.Emoji}} {{.Slot.Name}} ({{$left := sub .Slot.MaxClaims .ClaimCount}}{{$left}} spot{{if ne $left 1}}s{{end}} left)</option>
{{end}}{{end}}
</select>
</div>
{{end}}
<div class="form-row">
<label>Bringing anyone?</label>
<input type="number" name="plus_one" value="0" min="0" max="{{if .Capped}}{{.PlusOneMax}}{{else}}10{{end}}">
</div>
<div class="form-row" id="claim-note">
<label>Note (optional)</label>
<input type="text" id="claim-note-input" name="note" placeholder="e.g. arriving late, dietary restrictions, etc.">
</div>
<button class="btn-submit" type="submit">Count me in &#8599;</button>
</form>
</div>
{{end}}
{{if .IsAdmin}}
<div class="section-label" style="margin-top:40px">Admin: Date &amp; time</div>
<div class="claim-form-wrapper">
<form method="POST" action="/e/{{.Event.Slug}}/admin/{{.Event.AdminToken}}/datetime">
<div class="form-row">
<label>Date</label>
<input type="text" name="date" value="{{.Event.Date}}" placeholder="e.g. Saturday, June 14">
</div>
<div class="form-row">
<label>Time</label>
<input type="text" name="time" value="{{.Event.Time}}" placeholder="e.g. 2:00 PM">
</div>
<button class="btn-submit" type="submit">Save date &amp; time</button>
</form>
</div>
<div class="section-label" style="margin-top:40px">Admin: Location</div>
<div class="claim-form-wrapper">
<form method="POST" action="/e/{{.Event.Slug}}/admin/{{.Event.AdminToken}}/location">
<div class="form-row">
<label>Location</label>
<input type="text" name="location" value="{{.Event.Location}}" placeholder="e.g. Central Park">
</div>
<button class="btn-submit" type="submit">Save location</button>
</form>
</div>
<div class="section-label" style="margin-top:40px">Admin: Description</div>
<div class="claim-form-wrapper">
<form method="POST" action="/e/{{.Event.Slug}}/admin/{{.Event.AdminToken}}/description">
<div class="form-row">
<label>Event description (markdown supported)</label>
<textarea name="description" rows="5" style="border:var(--border-w) solid var(--border);background:var(--cream);padding:10px 14px;font-family:'Bricolage Grotesque',sans-serif;font-size:0.95rem;resize:vertical;outline:none;">{{.Event.Description}}</textarea>
</div>
<button class="btn-submit" type="submit">Save description</button>
</form>
</div>
<div class="section-label" style="margin-top:40px">Admin: Add slot</div>
<div class="claim-form-wrapper">
<form hx-post="/e/{{.Event.Slug}}/admin/{{.Event.AdminToken}}/slot"
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>Emoji</label>
<div class="emoji-pick" style="width:100%">
<input type="text" name="emoji" placeholder="&#127829;" readonly style="border:var(--border-w) solid var(--border);background:var(--cream);padding:10px 14px;font-size:0.95rem;width:100%;">
</div>
</div>
<div class="form-row">
<label>Slot name</label>
<input type="text" name="name" placeholder="e.g. Dessert" required>
</div>
<div class="form-row">
<label>Max claims</label>
<input type="number" name="max_claims" value="2" min="1">
</div>
<button class="btn-submit" type="submit">Add slot</button>
</form>
</div>
{{end}}
{{end}}