diff --git a/features/about/pages/about_templ.go b/features/about/pages/about_templ.go
index 1d95bcf..08cd774 100644
--- a/features/about/pages/about_templ.go
+++ b/features/about/pages/about_templ.go
@@ -66,7 +66,7 @@ func AboutATProto() templ.Component {
}
return nil
})
- templ_7745c5c3_Err = layouts.Base("What's ATProto? — atmo.quest", "ATProto is an open social protocol — your records live in your repo, not ours.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = layouts.Base("What's ATProto?", "ATProto is an open social protocol — your records live in your repo, not ours.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/features/admin/handlers.go b/features/admin/handlers.go
index d3dc44e..ec22fc1 100644
--- a/features/admin/handlers.go
+++ b/features/admin/handlers.go
@@ -5,6 +5,7 @@
package admin
import (
+ "context"
"database/sql"
"encoding/json"
"errors"
@@ -23,6 +24,8 @@ import (
"atmoquest/features/auth"
"atmoquest/internal/admincrypto"
"atmoquest/internal/badge"
+ "atmoquest/internal/checkin"
+ "atmoquest/internal/connection"
"atmoquest/internal/event"
"atmoquest/internal/users"
)
@@ -266,20 +269,28 @@ func (h *Handlers) AdminEventBadge(w http.ResponseWriter, r *http.Request) {
QRPublicURL: strings.TrimRight(config.Global.PublicURL, "/") + "/e/" + token,
}
+ // Which badge type are we editing?
+ badgeType := r.URL.Query().Get("type")
+ if badgeType == "" {
+ badgeType = "event-attendee"
+ }
+ view.SelectedBadgeType = badgeType
+
if h.Signer != nil {
- if d, err := badge.Get(r.Context(), h.DB, h.Signer, ev.URI); err == nil {
+ if d, err := badge.Get(r.Context(), h.DB, h.Signer, ev.URI, badgeType); err == nil {
view.Design = pages.AdminBadgeDesign{
- Shape: d.Shape,
- PrimaryColor: d.PrimaryColor,
- AccentColor: d.AccentColor,
- RibbonColor: d.RibbonColor,
- Label: d.Label,
- Signature: d.Signature,
- SigningKeyID: d.SigningKeyID,
+ Shape: d.Shape,
+ PrimaryColor: d.PrimaryColor,
+ AccentColor: d.AccentColor,
+ RibbonColor: d.RibbonColor,
+ Label: d.Label,
+ MessageTemplate: d.MessageTemplate,
+ Signature: d.Signature,
+ SigningKeyID: d.SigningKeyID,
}
view.SVGPreview = badge.RenderSVG(d, 200)
} else if !errors.Is(err, badge.ErrNotFound) {
- slog.Warn("admin badge: get", "event_uri", ev.URI, "err", err)
+ slog.Warn("admin badge: get", "event_uri", ev.URI, "type", badgeType, "err", err)
}
}
@@ -295,12 +306,67 @@ func (h *Handlers) AdminEventBadge(w http.ResponseWriter, r *http.Request) {
}, 200)
}
+ // Build event badge overview — show which badge types have designs.
+ eventBadgeTypes := []struct {
+ slug, name, desc string
+ }{
+ {"event-attendee", "Event check-in", "Awarded when someone checks into this event"},
+ {"event-leaderboard-1st", "Leaderboard 1st place", "Awarded to the top connector at event end"},
+ {"event-leaderboard-2nd", "Leaderboard 2nd place", "Awarded to the runner-up at event end"},
+ {"event-leaderboard-3rd", "Leaderboard 3rd place", "Awarded to third place at event end"},
+ {"event-exceeded", "Beyond expectations", "Awarded when check-ins exceed expected attendees"},
+ }
+ designMap, _ := badge.ListForEvent(r.Context(), h.DB, ev.URI)
+ for _, bt := range eventBadgeTypes {
+ eb := pages.EventBadgeOverview{
+ Slug: bt.slug,
+ Name: bt.name,
+ Description: bt.desc,
+ }
+ if d, ok := designMap[bt.slug]; ok {
+ eb.Designed = true
+ eb.Label = d.Label
+ }
+ view.EventBadges = append(view.EventBadges, eb)
+ }
+
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := pages.AdminEventBadge(view).Render(r.Context(), w); err != nil {
slog.Error("render admin badge", "err", err)
}
}
+// BadgePreviewSVG renders a badge SVG from query parameters for the live
+// designer preview. No signing or persistence — purely visual.
+func (h *Handlers) BadgePreviewSVG(w http.ResponseWriter, r *http.Request) {
+ d := badge.Design{
+ Shape: r.URL.Query().Get("shape"),
+ PrimaryColor: r.URL.Query().Get("primary_color"),
+ AccentColor: r.URL.Query().Get("accent_color"),
+ RibbonColor: r.URL.Query().Get("ribbon_color"),
+ Label: r.URL.Query().Get("label"),
+ }
+ if d.Shape == "" {
+ d.Shape = "shield"
+ }
+ if d.PrimaryColor == "" {
+ d.PrimaryColor = "#fab387"
+ }
+ if d.AccentColor == "" {
+ d.AccentColor = "#1e1e2e"
+ }
+ if d.RibbonColor == "" {
+ d.RibbonColor = "#f38ba8"
+ }
+ if d.Label == "" {
+ d.Label = "preview"
+ }
+ svg := badge.RenderSVG(d, 200)
+ w.Header().Set("Content-Type", "image/svg+xml")
+ w.Header().Set("Cache-Control", "no-cache")
+ _, _ = w.Write([]byte(svg))
+}
+
// AdminEventBadgeSave handles POST /admin/events/{token}/badge.
func (h *Handlers) AdminEventBadgeSave(w http.ResponseWriter, r *http.Request) {
if h.Signer == nil {
@@ -314,20 +380,27 @@ func (h *Handlers) AdminEventBadgeSave(w http.ResponseWriter, r *http.Request) {
return
}
+ badgeType := r.FormValue("badge_type")
+ if badgeType == "" {
+ badgeType = "event-attendee"
+ }
+
d := badge.Design{
- EventURI: ev.URI,
- Shape: r.FormValue("shape"),
- PrimaryColor: r.FormValue("primary_color"),
- AccentColor: r.FormValue("accent_color"),
- RibbonColor: r.FormValue("ribbon_color"),
- Label: strings.TrimSpace(r.FormValue("label")),
+ EventURI: ev.URI,
+ BadgeType: badgeType,
+ Shape: r.FormValue("shape"),
+ PrimaryColor: r.FormValue("primary_color"),
+ AccentColor: r.FormValue("accent_color"),
+ RibbonColor: r.FormValue("ribbon_color"),
+ Label: strings.TrimSpace(r.FormValue("label")),
+ MessageTemplate: strings.TrimSpace(r.FormValue("message_template")),
}
if _, err := badge.Save(r.Context(), h.DB, h.Signer, d); err != nil {
slog.Warn("admin badge save", "err", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
- http.Redirect(w, r, "/admin/events/"+token+"/badge?saved=1", http.StatusSeeOther)
+ http.Redirect(w, r, "/admin/events/"+token+"/badge?type="+badgeType+"&saved=1", http.StatusSeeOther)
}
// parseEventForm pulls form values into a CreateInput, returning a
@@ -371,6 +444,320 @@ func parseEventForm(r *http.Request) (event.CreateInput, pages.AdminEventFormVie
return in, view, ""
}
+// AdminEventDelete handles POST /admin/events/{token}/delete — removes the
+// event, its PDS record, and all associated local data (checkins, badges, etc.).
+func (h *Handlers) AdminEventDelete(w http.ResponseWriter, r *http.Request) {
+ _, sess, ok := h.Auth.RequireSession(w, r)
+ if !ok {
+ return
+ }
+
+ token := chi.URLParam(r, "token")
+ ev, err := event.LookupByQRToken(r.Context(), h.DB, token)
+ if err != nil {
+ http.NotFound(w, r)
+ return
+ }
+
+ if err := event.Delete(r.Context(), sess, h.DB, ev.URI); err != nil {
+ slog.Error("admin event delete", "uri", ev.URI, "err", err)
+ http.Error(w, "failed to delete event", http.StatusInternalServerError)
+ return
+ }
+
+ slog.Info("admin event deleted", "uri", ev.URI, "name", ev.Name)
+ http.Redirect(w, r, "/admin/events", http.StatusSeeOther)
+}
+
+// AdminEventFinalize awards end-of-event badges: leaderboard top 3 and
+// "exceeded expectations" if check-ins surpassed expected attendees.
+// This is a manual admin action triggered after the event ends.
+func (h *Handlers) AdminEventFinalize(w http.ResponseWriter, r *http.Request) {
+ _, _, ok := h.Auth.RequireSession(w, r)
+ if !ok {
+ return
+ }
+
+ token := chi.URLParam(r, "token")
+ ev, err := event.LookupByQRToken(r.Context(), h.DB, token)
+ if err != nil {
+ http.NotFound(w, r)
+ return
+ }
+
+ ctx := r.Context()
+
+ // Get all checked-in attendees.
+ attendeeDIDs, _ := checkin.ListAttendeesForEvent(ctx, h.DB, ev.URI)
+
+ // Build leaderboard (connection counts per attendee at this event).
+ type connCount struct {
+ did string
+ count int
+ }
+ var leaderboard []connCount
+ for _, didStr := range attendeeDIDs {
+ did, err := syntax.ParseDID(didStr)
+ if err != nil {
+ continue
+ }
+ // Skip users who opted out of leaderboard.
+ if users.IsHiddenFromLeaderboard(ctx, h.DB, didStr) {
+ continue
+ }
+ pds := lookupPDSForDIDAdmin(ctx, h.DB, did)
+ conns, _ := connection.List(ctx, pds, did)
+ eventConns := 0
+ for _, c := range conns {
+ if c.EventURI == ev.URI {
+ eventConns++
+ }
+ }
+ if eventConns > 0 {
+ leaderboard = append(leaderboard, connCount{did: didStr, count: eventConns})
+ }
+ }
+
+ // Sort by count desc.
+ for i := 0; i < len(leaderboard); i++ {
+ for j := i + 1; j < len(leaderboard); j++ {
+ if leaderboard[j].count > leaderboard[i].count {
+ leaderboard[i], leaderboard[j] = leaderboard[j], leaderboard[i]
+ }
+ }
+ }
+
+ // Load custom message templates for this event's badges.
+ msgTemplates := make(map[string]string)
+ if designs, err := badge.ListForEvent(ctx, h.DB, ev.URI); err == nil {
+ for badgeType, d := range designs {
+ msgTemplates[badgeType] = d.MessageTemplate
+ }
+ }
+
+ // Award leaderboard badges (1st, 2nd, 3rd) using competition ranking.
+ placeSlugs := []string{"event-leaderboard-1st", "event-leaderboard-2nd", "event-leaderboard-3rd"}
+ placeIdx := 0
+ prevCount := -1
+ for i, entry := range leaderboard {
+ if placeIdx >= len(placeSlugs) {
+ break
+ }
+ if entry.count != prevCount {
+ placeIdx = i
+ prevCount = entry.count
+ }
+ if placeIdx < len(placeSlugs) {
+ def, err := badge.GetDefinitionBySlug(ctx, h.DB, placeSlugs[placeIdx])
+ if err == nil && !badge.HasEarned(ctx, h.DB, entry.did, def.ID) {
+ msg := badgeMessage(msgTemplates, placeSlugs[placeIdx], ev.Name)
+ _ = badge.RecordEarned(ctx, h.DB, entry.did, def.ID, "", msg)
+ slog.Info("finalize: awarded leaderboard badge",
+ "did", entry.did, "place", placeIdx+1, "connections", entry.count)
+ }
+ }
+ }
+
+ // Award "exceeded expectations" badge if check-ins > expected attendees.
+ if ev.ExpectedAttendees > 0 && len(attendeeDIDs) > ev.ExpectedAttendees {
+ def, err := badge.GetDefinitionBySlug(ctx, h.DB, "event-exceeded")
+ if err == nil {
+ msg := badgeMessage(msgTemplates, "event-exceeded", ev.Name)
+ for _, didStr := range attendeeDIDs {
+ if !badge.HasEarned(ctx, h.DB, didStr, def.ID) {
+ _ = badge.RecordEarned(ctx, h.DB, didStr, def.ID, "", msg)
+ }
+ }
+ slog.Info("finalize: awarded exceeded badge",
+ "event", ev.Name, "checkins", len(attendeeDIDs), "expected", ev.ExpectedAttendees)
+ }
+ }
+
+ // Award "event-host" badge if the event was successful (>1 check-in + >=1 connection).
+ totalConns := 0
+ for _, cc := range leaderboard {
+ totalConns += cc.count
+ }
+ if len(attendeeDIDs) > 1 && totalConns > 0 && ev.OrganizerDID.String() != "" {
+ def, err := badge.GetDefinitionBySlug(ctx, h.DB, "event-host")
+ if err == nil && !badge.HasEarned(ctx, h.DB, ev.OrganizerDID.String(), def.ID) {
+ msg := badgeMessage(msgTemplates, "event-host", ev.Name)
+ if msg == "" {
+ msg = "Successfully hosted " + ev.Name
+ }
+ _ = badge.RecordEarned(ctx, h.DB, ev.OrganizerDID.String(), def.ID, "", msg)
+ slog.Info("finalize: awarded event-host badge",
+ "did", ev.OrganizerDID.String(), "event", ev.Name)
+ }
+ }
+
+ slog.Info("admin event finalized", "uri", ev.URI, "name", ev.Name,
+ "attendees", len(attendeeDIDs), "leaderboard_entries", len(leaderboard))
+ http.Redirect(w, r, "/admin/events", http.StatusSeeOther)
+}
+
+// badgeMessage looks up a custom message template for a badge type,
+// falling back to a default message with the event name.
+func badgeMessage(templates map[string]string, badgeType, eventName string) string {
+ if msg, ok := templates[badgeType]; ok && msg != "" {
+ return msg
+ }
+ return "Earned at " + eventName
+}
+
+// AdminBadges lists all app-wide badge definitions.
+func (h *Handlers) AdminBadges(w http.ResponseWriter, r *http.Request) {
+ defs, err := badge.ListDefinitions(r.Context(), h.DB)
+ if err != nil {
+ slog.Error("admin badges: list", "err", err)
+ http.Error(w, "internal error", http.StatusInternalServerError)
+ return
+ }
+
+ var view pages.AdminBadgesView
+ for _, d := range defs {
+ svg := badge.RenderSVG(badge.Design{
+ Shape: d.Shape,
+ PrimaryColor: d.PrimaryColor,
+ AccentColor: d.AccentColor,
+ RibbonColor: d.RibbonColor,
+ Label: d.Label,
+ }, 80)
+ view.Badges = append(view.Badges, pages.AdminBadgeRow{
+ ID: d.ID,
+ Slug: d.Slug,
+ Name: d.Name,
+ Description: d.Description,
+ Shape: d.Shape,
+ PrimaryColor: d.PrimaryColor,
+ AccentColor: d.AccentColor,
+ RibbonColor: d.RibbonColor,
+ Label: d.Label,
+ Trigger: d.Trigger,
+ SVGPreview: svg,
+ })
+ }
+
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ if err := pages.AdminBadges(view).Render(r.Context(), w); err != nil {
+ slog.Error("render admin badges", "err", err)
+ }
+}
+
+// AdminBadgeEditPage renders the badge edit form for a specific definition.
+func (h *Handlers) AdminBadgeEditPage(w http.ResponseWriter, r *http.Request) {
+ idStr := chi.URLParam(r, "id")
+ id, err := strconv.Atoi(idStr)
+ if err != nil {
+ http.NotFound(w, r)
+ return
+ }
+
+ defs, _ := badge.ListDefinitions(r.Context(), h.DB)
+ var def *badge.Definition
+ for i := range defs {
+ if defs[i].ID == id {
+ def = &defs[i]
+ break
+ }
+ }
+ if def == nil {
+ http.NotFound(w, r)
+ return
+ }
+
+ svg := badge.RenderSVG(badge.Design{
+ Shape: def.Shape,
+ PrimaryColor: def.PrimaryColor,
+ AccentColor: def.AccentColor,
+ RibbonColor: def.RibbonColor,
+ Label: def.Label,
+ }, 200)
+
+ view := pages.AdminBadgeEditView{
+ Badge: pages.AdminBadgeRow{
+ ID: def.ID,
+ Slug: def.Slug,
+ Name: def.Name,
+ Description: def.Description,
+ Shape: def.Shape,
+ PrimaryColor: def.PrimaryColor,
+ AccentColor: def.AccentColor,
+ RibbonColor: def.RibbonColor,
+ Label: def.Label,
+ Trigger: def.Trigger,
+ SVGPreview: svg,
+ },
+ Shapes: badge.DefaultShapes,
+ Primary: badge.DefaultPrimaryColors,
+ Accent: badge.DefaultAccentColors,
+ Ribbon: badge.DefaultRibbonColors,
+ Saved: r.URL.Query().Get("saved") == "1",
+ }
+
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ if err := pages.AdminBadgeEdit(view).Render(r.Context(), w); err != nil {
+ slog.Error("render admin badge edit", "err", err)
+ }
+}
+
+// AdminBadgeEditSave handles POST /admin/badges/{id}/edit — updates the
+// badge definition's visual design.
+func (h *Handlers) AdminBadgeEditSave(w http.ResponseWriter, r *http.Request) {
+ idStr := chi.URLParam(r, "id")
+ id, err := strconv.Atoi(idStr)
+ if err != nil {
+ http.NotFound(w, r)
+ return
+ }
+
+ if err := r.ParseForm(); err != nil {
+ http.Error(w, "bad request", http.StatusBadRequest)
+ return
+ }
+
+ _, err = h.DB.ExecContext(r.Context(), `
+ UPDATE badge_definitions SET
+ name = ?,
+ description = ?,
+ shape = ?,
+ primary_color = ?,
+ accent_color = ?,
+ ribbon_color = ?,
+ label = ?
+ WHERE id = ?
+ `,
+ strings.TrimSpace(r.FormValue("name")),
+ strings.TrimSpace(r.FormValue("description")),
+ r.FormValue("shape"),
+ r.FormValue("primary_color"),
+ r.FormValue("accent_color"),
+ r.FormValue("ribbon_color"),
+ strings.TrimSpace(r.FormValue("label")),
+ id,
+ )
+ if err != nil {
+ slog.Warn("admin badge edit save", "id", id, "err", err)
+ http.Error(w, "failed to save", http.StatusInternalServerError)
+ return
+ }
+
+ http.Redirect(w, r, fmt.Sprintf("/admin/badges/%d/edit?saved=1", id), http.StatusSeeOther)
+}
+
+// lookupPDSForDIDAdmin is a helper that looks up PDS host from oauth_sessions.
+func lookupPDSForDIDAdmin(ctx context.Context, db *sql.DB, did syntax.DID) string {
+ var host string
+ err := db.QueryRowContext(ctx, `
+ SELECT data ->> 'host_url' FROM oauth_sessions
+ WHERE did = ? ORDER BY updated_at DESC LIMIT 1
+ `, did.String()).Scan(&host)
+ if err == nil && host != "" {
+ return host
+ }
+ return "https://bsky.social"
+}
+
// toAdminEventRows projects []event.AdminEvent into the view type. We
// pre-format times here so the template stays dumb.
func toAdminEventRows(list []event.AdminEvent, publicURL string) []pages.AdminEventRow {
diff --git a/features/admin/pages/badges.templ b/features/admin/pages/badges.templ
new file mode 100644
index 0000000..2b86770
--- /dev/null
+++ b/features/admin/pages/badges.templ
@@ -0,0 +1,138 @@
+package pages
+
+import (
+ "fmt"
+
+ "atmoquest/features/common/layouts"
+)
+
+// AdminBadgesView is the data for /admin/badges.
+type AdminBadgesView struct {
+ Badges []AdminBadgeRow
+}
+
+// AdminBadgeRow is one badge definition in the admin list.
+type AdminBadgeRow struct {
+ ID int
+ Slug string
+ Name string
+ Description string
+ Shape string
+ PrimaryColor string
+ AccentColor string
+ RibbonColor string
+ Label string
+ Trigger string
+ SVGPreview string
+}
+
+// AdminBadgeEditView is the data for /admin/badges/{id}/edit.
+type AdminBadgeEditView struct {
+ Badge AdminBadgeRow
+ Shapes []string
+ Primary []string
+ Accent []string
+ Ribbon []string
+ Saved bool
+ Error string
+}
+
+templ AdminBadges(v AdminBadgesView) {
+ @layouts.Base("admin · badges", "Manage app-wide badge definitions.") {
+ @adminShell("badges", "") {
+
App badges
+
+ These are the app-wide badge definitions. Click a badge to edit its design.
+
+
+ if len(v.Badges) == 0 {
+
no badge definitions found.
+ } else {
+
+ }
+ }
+ }
+}
+
+templ AdminBadgeEdit(v AdminBadgeEditView) {
+ @layouts.Base("admin · edit badge", "Edit a badge definition.") {
+ @adminShell("badges", "") {
+
edit badge — { v.Badge.Name }
+
+ if v.Saved {
+
+ ✓ badge design saved.
+
+ }
+ if v.Error != "" {
+
+ error: { v.Error }
+
+ }
+
+
+
+ @templ.Raw(v.Badge.SVGPreview)
+
{ v.Badge.Slug }
+ if v.Badge.Trigger != "" {
+
trigger: { v.Badge.Trigger }
+ }
+
+
+
+
+
+ }
+ }
+}
+
+func badgeIDStr(id int) string {
+ return fmt.Sprintf("%d", id)
+}
diff --git a/features/admin/pages/badges_templ.go b/features/admin/pages/badges_templ.go
new file mode 100644
index 0000000..25adfe3
--- /dev/null
+++ b/features/admin/pages/badges_templ.go
@@ -0,0 +1,500 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.3.1020
+package pages
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import templruntime "github.com/a-h/templ/runtime"
+
+import (
+ "fmt"
+
+ "atmoquest/features/common/layouts"
+)
+
+// AdminBadgesView is the data for /admin/badges.
+type AdminBadgesView struct {
+ Badges []AdminBadgeRow
+}
+
+// AdminBadgeRow is one badge definition in the admin list.
+type AdminBadgeRow struct {
+ ID int
+ Slug string
+ Name string
+ Description string
+ Shape string
+ PrimaryColor string
+ AccentColor string
+ RibbonColor string
+ Label string
+ Trigger string
+ SVGPreview string
+}
+
+// AdminBadgeEditView is the data for /admin/badges/{id}/edit.
+type AdminBadgeEditView struct {
+ Badge AdminBadgeRow
+ Shapes []string
+ Primary []string
+ Accent []string
+ Ribbon []string
+ Saved bool
+ Error string
+}
+
+func AdminBadges(v AdminBadgesView) templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var3 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
App badges
These are the app-wide badge definitions. Click a badge to edit its design.
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if len(v.Badges) == 0 {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
no badge definitions found.
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ } else {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ for _, b := range v.Badges {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ.Raw(b.SVGPreview).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var5 string
+ templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(b.Name)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/badges.templ`, Line: 58, Col: 51}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var6 string
+ templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(b.Description)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/badges.templ`, Line: 59, Col: 64}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if b.Trigger != "" {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var7 string
+ templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(b.Trigger)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/badges.templ`, Line: 61, Col: 64}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ return nil
+ })
+ templ_7745c5c3_Err = adminShell("badges", "").Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+ templ_7745c5c3_Err = layouts.Base("admin · badges", "Manage app-wide badge definitions.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
+func AdminBadgeEdit(v AdminBadgeEditView) templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var8 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var8 == nil {
+ templ_7745c5c3_Var8 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var9 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var10 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
edit badge — ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var11 string
+ templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(v.Badge.Name)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/badges.templ`, Line: 75, Col: 64}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if v.Saved {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
✓ badge design saved.
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if v.Error != "" {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
error: ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var12 string
+ templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(v.Error)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/badges.templ`, Line: 84, Col: 60}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ.Raw(v.Badge.SVGPreview).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var13 string
+ templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(v.Badge.Slug)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/badges.templ`, Line: 91, Col: 65}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if v.Badge.Trigger != "" {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
trigger: ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var14 string
+ templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(v.Badge.Trigger)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/badges.templ`, Line: 93, Col: 62}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+ templ_7745c5c3_Err = adminShell("badges", "").Render(templ.WithChildren(ctx, templ_7745c5c3_Var10), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+ templ_7745c5c3_Err = layouts.Base("admin · edit badge", "Edit a badge definition.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
+func badgeIDStr(id int) string {
+ return fmt.Sprintf("%d", id)
+}
+
+var _ = templruntime.GeneratedTemplate
diff --git a/features/admin/pages/dashboard.templ b/features/admin/pages/dashboard.templ
index 7d8faf6..4c2d4de 100644
--- a/features/admin/pages/dashboard.templ
+++ b/features/admin/pages/dashboard.templ
@@ -19,7 +19,7 @@ type AdminDashboardView struct {
}
templ AdminDashboard(v AdminDashboardView) {
- @layouts.Base("admin — atmo.quest", "atmo.quest admin console.") {
+ @layouts.Base("admin", "atmo.quest admin console.") {
@adminShell("dashboard", v.CurrentHandle) {
@statTile("users", intStr(v.TotalUsers), "total signed in")
@@ -73,6 +73,7 @@ templ adminShell(active, currentHandle string) {
@adminNavLink("/admin", "dashboard", active == "dashboard")
@adminNavLink("/admin/users", "users", active == "users")
@adminNavLink("/admin/events", "events", active == "events")
+ @adminNavLink("/admin/badges", "badges", active == "badges")
← back to app
diff --git a/features/admin/pages/dashboard_templ.go b/features/admin/pages/dashboard_templ.go
index 58e3d85..ff096b9 100644
--- a/features/admin/pages/dashboard_templ.go
+++ b/features/admin/pages/dashboard_templ.go
@@ -143,7 +143,7 @@ func AdminDashboard(v AdminDashboardView) templ.Component {
}
return nil
})
- templ_7745c5c3_Err = layouts.Base("admin — atmo.quest", "atmo.quest admin console.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = layouts.Base("admin", "atmo.quest admin console.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -285,6 +285,10 @@ func adminShell(active, currentHandle string) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
+ templ_7745c5c3_Err = adminNavLink("/admin/badges", "badges", active == "badges").Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
← back to app")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
@@ -330,7 +334,7 @@ func adminNavLink(href, label string, active bool) templ.Component {
var templ_7745c5c3_Var14 templ.SafeURL
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/dashboard.templ`, Line: 92, Col: 64}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/dashboard.templ`, Line: 93, Col: 64}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
@@ -343,7 +347,7 @@ func adminNavLink(href, label string, active bool) templ.Component {
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(label)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/dashboard.templ`, Line: 92, Col: 78}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/dashboard.templ`, Line: 93, Col: 78}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
@@ -361,7 +365,7 @@ func adminNavLink(href, label string, active bool) templ.Component {
var templ_7745c5c3_Var16 templ.SafeURL
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/dashboard.templ`, Line: 94, Col: 54}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/dashboard.templ`, Line: 95, Col: 54}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
@@ -374,7 +378,7 @@ func adminNavLink(href, label string, active bool) templ.Component {
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(label)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/dashboard.templ`, Line: 94, Col: 64}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/dashboard.templ`, Line: 95, Col: 64}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
diff --git a/features/admin/pages/events.templ b/features/admin/pages/events.templ
index 263392b..1d2dd1e 100644
--- a/features/admin/pages/events.templ
+++ b/features/admin/pages/events.templ
@@ -21,7 +21,7 @@ type AdminEventRow struct {
}
templ AdminEvents(v AdminEventsView) {
- @layouts.Base("admin · events — atmo.quest", "Manage atmo.quest events.") {
+ @layouts.Base("admin · events", "Manage atmo.quest events.") {
@adminShell("events", "") {
▸ new event
@@ -57,7 +57,14 @@ templ AdminEvents(v AdminEventsView) {
{ intStr(ev.ExpectedAttendees) } |
{ ev.QRPublicURL } |
+ QR ↓
badge →
+
+
|
}
@@ -81,7 +88,7 @@ type AdminEventFormView struct {
}
templ AdminEventNew(v AdminEventFormView) {
- @layouts.Base("admin · new event — atmo.quest", "Create a new atmo.quest event.") {
+ @layouts.Base("admin · new event", "Create a new atmo.quest event.") {
@adminShell("events", "") {
create event
@@ -136,29 +143,69 @@ type AdminEventBadgeView struct {
Primary []string
Accent []string
Ribbon []string
- Design AdminBadgeDesign
- SVGPreview string
- QRPublicURL 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
- Signature string
- SigningKeyID string
+ 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 — atmo.quest", "Design an event badge.") {
+ @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
+
+
+ }
+
-
+
@templ.Raw(v.SVGPreview)
{ v.EventURI }
@@ -171,6 +218,7 @@ templ AdminEventBadge(v AdminEventBadgeView) {
+
}
}
}
diff --git a/features/admin/pages/events_templ.go b/features/admin/pages/events_templ.go
index e531846..5992073 100644
--- a/features/admin/pages/events_templ.go
+++ b/features/admin/pages/events_templ.go
@@ -191,20 +191,59 @@ func AdminEvents(v AdminEventsView) templ.Component {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 templ.SafeURL
- templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("/admin/events/" + ev.QRToken + "/badge"))
+ templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("/e/" + ev.QRToken + "/qr.svg"))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 60, Col: 104}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 60, Col: 94}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">badge →")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">QR ↓
badge →")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -217,7 +256,7 @@ func AdminEvents(v AdminEventsView) templ.Component {
}
return nil
})
- templ_7745c5c3_Err = layouts.Base("admin · events — atmo.quest", "Manage atmo.quest events.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = layouts.Base("admin · events", "Manage atmo.quest events.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -252,12 +291,12 @@ func AdminEventNew(v AdminEventFormView) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var12 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var12 == nil {
- templ_7745c5c3_Var12 = templ.NopComponent
+ templ_7745c5c3_Var15 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var15 == nil {
+ templ_7745c5c3_Var15 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Var13 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Var16 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
@@ -269,7 +308,7 @@ func AdminEventNew(v AdminEventFormView) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var14 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Var17 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
@@ -281,107 +320,107 @@ func AdminEventNew(v AdminEventFormView) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
create event
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
create event
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if v.Error != "" {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
heads up: ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "
heads up: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var15 string
- templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(v.Error)
+ var templ_7745c5c3_Var18 string
+ templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(v.Error)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 90, Col: 63}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 97, Col: 63}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
- templ_7745c5c3_Err = adminShell("events", "").Render(templ.WithChildren(ctx, templ_7745c5c3_Var14), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = adminShell("events", "").Render(templ.WithChildren(ctx, templ_7745c5c3_Var17), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
- templ_7745c5c3_Err = layouts.Base("admin · new event — atmo.quest", "Create a new atmo.quest event.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var13), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = layouts.Base("admin · new event", "Create a new atmo.quest event.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var16), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -391,27 +430,39 @@ func AdminEventNew(v AdminEventFormView) templ.Component {
// 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
+ 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
- Signature string
- SigningKeyID string
+ Shape string
+ PrimaryColor string
+ AccentColor string
+ RibbonColor string
+ Label string
+ MessageTemplate string
+ Signature string
+ SigningKeyID string
}
func AdminEventBadge(v AdminEventBadgeView) templ.Component {
@@ -430,12 +481,12 @@ func AdminEventBadge(v AdminEventBadgeView) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var21 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var21 == nil {
- templ_7745c5c3_Var21 = templ.NopComponent
+ templ_7745c5c3_Var24 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var24 == nil {
+ templ_7745c5c3_Var24 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Var22 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Var25 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
@@ -447,7 +498,7 @@ func AdminEventBadge(v AdminEventBadgeView) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var23 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Var26 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
@@ -459,20 +510,140 @@ func AdminEventBadge(v AdminEventBadgeView) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
badge designer — ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "badge designer — ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var24 string
- templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(v.EventName)
+ var templ_7745c5c3_Var27 string
+ templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(v.EventName)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 158, Col: 67}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 177, Col: 67}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
")
+ if len(v.EventBadges) > 0 {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
Event badges — click to design
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ for _, eb := range v.EventBadges {
+ var templ_7745c5c3_Var28 = []any{"settings-row", templ.KV("active-badge-type", eb.Slug == v.SelectedBadgeType)}
+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var28...)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if eb.Designed {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "◆")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ } else {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "◇")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var31 string
+ templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(eb.Name)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 193, Col: 50}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var32 string
+ templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(eb.Description)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 194, Col: 56}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if eb.Designed {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var33 string
+ templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(eb.Label)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 197, Col: 57}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ } else {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "not designed
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -480,125 +651,138 @@ func AdminEventBadge(v AdminEventBadgeView) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var25 string
- templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(v.EventURI)
+ var templ_7745c5c3_Var34 string
+ templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(v.EventURI)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 164, Col: 25}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 211, Col: 25}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if v.Design.Signature != "" {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "
● signed (key ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "
● signed (key ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var26 string
- templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(v.Design.SigningKeyID)
+ var templ_7745c5c3_Var35 string
+ templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(v.Design.SigningKeyID)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 168, Col: 70}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 215, Col: 70}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, ")
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, ")")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
public scan URL: ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var35 string
- templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(v.QRPublicURL)
+ var templ_7745c5c3_Var45 string
+ templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(v.QRPublicURL)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 199, Col: 93}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `features/admin/pages/events.templ`, Line: 252, Col: 93}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "
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.
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "
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.
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
- templ_7745c5c3_Err = adminShell("events", "").Render(templ.WithChildren(ctx, templ_7745c5c3_Var23), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = adminShell("events", "").Render(templ.WithChildren(ctx, templ_7745c5c3_Var26), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
- templ_7745c5c3_Err = layouts.Base("admin · badge designer — atmo.quest", "Design an event badge.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var22), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = layouts.Base("admin · badge designer", "Design an event badge.").Render(templ.WithChildren(ctx, templ_7745c5c3_Var25), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -703,128 +887,128 @@ func colorSwatchField(name, label string, options []string, selected string) tem
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var36 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var36 == nil {
- templ_7745c5c3_Var36 = templ.NopComponent
+ templ_7745c5c3_Var46 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var46 == nil {
+ templ_7745c5c3_Var46 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/features/admin/pages/users.templ b/features/admin/pages/users.templ
index d95bc24..adb356d 100644
--- a/features/admin/pages/users.templ
+++ b/features/admin/pages/users.templ
@@ -25,7 +25,7 @@ type AdminUserRow struct {
}
templ AdminUsers(v AdminUsersView) {
- @layouts.Base("admin · users — atmo.quest", "Manage atmo.quest users.") {
+ @layouts.Base("admin · users", "Manage atmo.quest users.") {
@adminShell("users", "") {