Skip to content

Commit 375c503

Browse files
sumnerevansclaude
andcommitted
templates: add templ components for static pages and teacher login
Bring in templ component equivalents of the HTML templates for: home, info, authors, rules, register, faq, archive, navbar partial, footer partial, base layout, and teacher login page. Update internal/archive.go to remove duplicate type definitions (Link, WinningTeam, CompetitionResult, YearInfo now live in the templates package). Add archiveInfo package variable and update GetArchiveTemplate to convert to the struct types expected by the html/template renderer. Add internal/contextkeys/keys.go with context key constants shared by both the HTTP handlers and the templ components. The runtime application.go is unchanged and continues to use html/template; the templ components are not yet wired up. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 6e109e5 commit 375c503

25 files changed

Lines changed: 2566 additions & 216 deletions

internal/archive.go

Lines changed: 241 additions & 216 deletions
Large diffs are not rendered by default.

internal/contextkeys/keys.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package contextkeys
2+
3+
type contextKey int
4+
5+
const (
6+
ContextKeyLoggedInTeacher contextKey = iota
7+
ContextKeyPageName
8+
ContextKeyRegistrationEnabled
9+
ContextKeyHostedByHTML
10+
)

internal/templates/archive.templ

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package templates
2+
3+
import "strconv"
4+
5+
type Link struct {
6+
URL templ.SafeURL
7+
Title string
8+
}
9+
10+
type WinningTeam struct {
11+
Place string
12+
Name string
13+
School string
14+
Location string
15+
}
16+
17+
type CompetitionResult struct {
18+
Name string
19+
Shortname string
20+
Teams []WinningTeam
21+
}
22+
23+
type YearInfo struct {
24+
Year int
25+
RecapParagraphs []string
26+
Links []Link
27+
Results []CompetitionResult
28+
}
29+
30+
func accordionHeadingID(year int, shortname string) string {
31+
return "heading" + strconv.Itoa(year) + shortname
32+
}
33+
34+
func accordionCollapseCSSID(year int, shortname string) string {
35+
return "#" + accordionCollapseID(year, shortname)
36+
}
37+
38+
func accordionCollapseID(year int, shortname string) string {
39+
return "winners" + strconv.Itoa(year) + shortname
40+
}
41+
42+
func trophyColor(place int) string {
43+
switch place + 1 {
44+
case 1:
45+
return "#FFD700"
46+
case 2:
47+
return "#C0C0C0"
48+
default:
49+
return "#CD7F32"
50+
}
51+
}
52+
53+
templ Archive(years []YearInfo) {
54+
<div class="container">
55+
<div class="row page-header">
56+
<div class="col">
57+
<h1>Archive</h1>
58+
<p class="header-paragraph">
59+
Since 2018, the CS@Mines High School Programming
60+
Competition has provided high school students an opportunity to
61+
demonstrate their programming and problem solving skills in a
62+
competitive environment. For more information on all of our competitions
63+
and past problems, view
64+
<a href="https://sumnerevans.com/tags/high-school-programming-competition/" target="_blank">
65+
competition summaries
66+
</a>.
67+
</p>
68+
</div>
69+
</div>
70+
</div>
71+
<div class="container page-content archive pb-5">
72+
for _, y := range years {
73+
@year(y)
74+
@yearLinks(y)
75+
}
76+
</div>
77+
}
78+
79+
templ year(y YearInfo) {
80+
<div class="row mb-4">
81+
<div class="col-lg-5 mt-4 mx-4">
82+
<h2>{ strconv.Itoa(y.Year) }</h2>
83+
for _, p := range y.RecapParagraphs {
84+
<p>{ p }</p>
85+
}
86+
</div>
87+
<div class="col mt-5">
88+
<div class="accordion">
89+
for _, r := range y.Results {
90+
<div class="accordion-item">
91+
<h2 class="accordion-header" id={ accordionHeadingID(y.Year, r.Shortname) }>
92+
<button
93+
class="accordion-button collapsed"
94+
type="button"
95+
data-bs-toggle="collapse"
96+
data-bs-target={ accordionCollapseCSSID(y.Year, r.Shortname) }
97+
aria-expanded="true"
98+
aria-controls={ accordionCollapseID(y.Year, r.Shortname) }
99+
>
100+
<strong>{ r.Name } Competition Winners</strong>
101+
</button>
102+
</h2>
103+
<div
104+
id={ accordionCollapseID(y.Year, r.Shortname) }
105+
class="accordion-collapse collapse"
106+
aria-labelledby={ accordionHeadingID(y.Year, r.Shortname) }
107+
>
108+
<div class="accordion-body">
109+
for i, t := range r.Teams {
110+
@winningTeam(i, t)
111+
}
112+
</div>
113+
</div>
114+
</div>
115+
}
116+
</div>
117+
</div>
118+
</div>
119+
}
120+
121+
templ yearLinks(y YearInfo) {
122+
<div class="row">
123+
<div class="col mx-4">
124+
for i, link := range y.Links {
125+
if i > 0 {
126+
&nbsp;&bull;
127+
}
128+
<a href={ link.URL } target="_blank">{ link.Title }</a>
129+
}
130+
</div>
131+
</div>
132+
}
133+
134+
templ winningTeam(i int, team WinningTeam) {
135+
<li class="list-group-item">
136+
<span class="badge bg-primary rounded-pill">
137+
<i class="fa fa-trophy" { templ.Attributes{"style": "color: " + trophyColor(i) + ";"}... } role="img" aria-label="Trophy"></i>
138+
{ team.Place }
139+
</span>
140+
<strong>{ team.Name }</strong>
141+
<p class="mb-1 text-secondary">
142+
{ team.School } &bull; { team.Location }
143+
</p>
144+
</li>
145+
}

0 commit comments

Comments
 (0)