package pages import ( "strconv" "atmoquest/features/common/layouts" ) // AdminEventsView is the data for /admin/events. type AdminEventsView struct { PublicURL string Events []AdminEventRow } // AdminEventRow is a single row in the admin event list. type AdminEventRow struct { URI string Name string Location string StartTime string EndTime string ExpectedAttendees int QRToken string QRPublicURL string } templ AdminEvents(v AdminEventsView) { @layouts.Base("admin · events", "Manage atmo.quest events.") { @adminShell("events", "") {
▸ new event
if len(v.Events) == 0 {

no events yet. create the first one.

} else {
for _, ev := range v.Events { }
name location dates expected actions
{ ev.Name } if ev.Location != "" { { ev.Location } } else { — } { ev.StartTime }
→ { ev.EndTime }
{ intStr(ev.ExpectedAttendees) }
edit QR ↓ badge
} } } } // AdminEventFormView is the data for /admin/events/new (also re-used on // validation-error re-renders). type AdminEventFormView struct { Name string Location string StartTime string // datetime-local "2006-01-02T15:04" EndTime string ExpectedAttendees int Links []EventLink Error string // Edit mode fields (empty for create). QRToken string // non-empty = editing } // EventLink is a {label, url} pair shown in the admin event form's links // editor. Mirrors event.Link for the view layer. type EventLink struct { Label string URL string } templ AdminEventNew(v AdminEventFormView) { @layouts.Base("admin · new event", "Create a new atmo.quest event.") { @adminShell("events", "") {

create event

if v.Error != "" { }
@eventLinksFieldset(v.Links)
cancel

creating an event writes a quest.atmo.event record to your PDS. you'll be taken to the badge designer next.

} } } templ AdminEventEdit(v AdminEventFormView) { @layouts.Base("admin · edit event", "Edit an event.") { @adminShell("events", "") {

edit event

if v.Error != "" { }
@eventLinksFieldset(v.Links)
cancel

changes are written to your quest.atmo.event PDS record and the local cache.

} } } // eventLinksFieldset renders the "links (up to 5)" editor, mirroring the // profile links editor. Always renders MaxEventLinks rows so an organizer can // add new links; populated rows are pre-filled from v.Links. templ eventLinksFieldset(links []EventLink) { } // eventLinkRow renders a single label+URL row of the links editor. templ eventLinkRow(idx int, l EventLink) { } // eventLinkAt returns the link at index i, or a zero EventLink if out of range. func eventLinkAt(links []EventLink, i int) EventLink { if i < len(links) { return links[i] } return EventLink{} } // AdminEventBadgeView feeds the badge designer page. type AdminEventBadgeView struct { EventURI string EventName string Token string Shapes []string Primary []string Accent []string Ribbon []string Design AdminBadgeDesign SVGPreview string QRPublicURL string EventBadges []EventBadgeOverview // all badge types for this event SelectedBadgeType string // which badge type is being edited } // EventBadgeOverview shows the status of a badge type for an event. type EventBadgeOverview struct { Slug string Name string Description string Designed bool // true if a design has been saved Label string // the label on the badge (if designed) } // AdminBadgeDesign is the current state of the badge being designed. type AdminBadgeDesign struct { Shape string PrimaryColor string AccentColor string RibbonColor string Label string MessageTemplate string Signature string SigningKeyID string } templ AdminEventBadge(v AdminEventBadgeView) { @layouts.Base("admin · badge designer", "Design an event badge.") { @adminShell("events", "") {

badge designer — { v.EventName }

if len(v.EventBadges) > 0 {
Event badges — click to design
for _, eb := range v.EventBadges {
if eb.Designed { ◆ } else { ◇ }
{ eb.Name }
{ eb.Description }
if eb.Designed {
{ eb.Label }
} else {
not designed
}
}
}
@templ.Raw(v.SVGPreview)

{ v.EventURI }

if v.Design.Signature != "" {

● signed (key { v.Design.SigningKeyID })

}
@colorSwatchField("primary_color", "primary color", v.Primary, v.Design.PrimaryColor) @colorSwatchField("accent_color", "accent color", v.Accent, v.Design.AccentColor) @colorSwatchField("ribbon_color", "ribbon color", v.Ribbon, v.Design.RibbonColor)
shown when someone views their badge
← all events

public scan URL: { v.QRPublicURL }
saving signs this design with the server's admin key (ed25519). tampering with the row in the database will fail signature verification on next read.

} } } // colorSwatchField is a radio-group with visible color swatches. templ colorSwatchField(name, label string, options []string, selected string) {
for _, c := range options { }
}