Learning jam scaffolding
This commit is contained in:
parent
d896298117
commit
b5d4fe9ba2
|
@ -62,6 +62,17 @@ var WRJ2023 = Jam{
|
||||||
UrlSlug: "2023",
|
UrlSlug: "2023",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var LJ2024 = Jam{
|
||||||
|
Event: Event{
|
||||||
|
StartTime: time.Date(2024, 3, 15, 17, 0, 0, 0, time.UTC),
|
||||||
|
EndTime: time.Date(2024, 3, 24, 20, 0, 0, 0, time.UTC),
|
||||||
|
},
|
||||||
|
Name: "Learning Jam 2024",
|
||||||
|
Slug: "LJ2024",
|
||||||
|
UrlSlug: "learning-2024",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conferences
|
||||||
var HMS2022 = Event{
|
var HMS2022 = Event{
|
||||||
StartTime: time.Date(2022, 11, 16, 0, 0, 0, 0, utils.Must1(time.LoadLocation("America/Los_Angeles"))),
|
StartTime: time.Date(2022, 11, 16, 0, 0, 0, 0, utils.Must1(time.LoadLocation("America/Los_Angeles"))),
|
||||||
EndTime: time.Date(2022, 11, 18, 0, 0, 0, 0, utils.Must1(time.LoadLocation("America/Los_Angeles"))),
|
EndTime: time.Date(2022, 11, 18, 0, 0, 0, 0, utils.Must1(time.LoadLocation("America/Los_Angeles"))),
|
||||||
|
@ -77,7 +88,7 @@ var HMBoston2023 = Event{
|
||||||
EndTime: time.Date(2023, 8, 4, 0, 0, 0, 0, utils.Must1(time.LoadLocation("America/Los_Angeles"))),
|
EndTime: time.Date(2023, 8, 4, 0, 0, 0, 0, utils.Must1(time.LoadLocation("America/Los_Angeles"))),
|
||||||
}
|
}
|
||||||
|
|
||||||
var AllJams = []Jam{WRJ2021, WRJ2022, VJ2023, WRJ2023}
|
var AllJams = []Jam{WRJ2021, WRJ2022, VJ2023, WRJ2023, LJ2024}
|
||||||
|
|
||||||
func CurrentJam() *Jam {
|
func CurrentJam() *Jam {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
|
@ -143,7 +143,6 @@ func TestFeed(t *testing.T) {
|
||||||
|
|
||||||
func TestProjectIndex(t *testing.T) {
|
func TestProjectIndex(t *testing.T) {
|
||||||
AssertRegexMatch(t, BuildProjectIndex(1, ""), RegexProjectIndex, nil)
|
AssertRegexMatch(t, BuildProjectIndex(1, ""), RegexProjectIndex, nil)
|
||||||
AssertRegexMatch(t, BuildProjectIndex(2, ""), RegexProjectIndex, map[string]string{"page": "2"})
|
|
||||||
AssertRegexMatch(t, BuildProjectIndex(1, "test"), RegexProjectIndex, map[string]string{"category": "test"})
|
AssertRegexMatch(t, BuildProjectIndex(1, "test"), RegexProjectIndex, map[string]string{"category": "test"})
|
||||||
AssertRegexMatch(t, BuildProjectIndex(2, "test"), RegexProjectIndex, map[string]string{"page": "2", "category": "test"})
|
AssertRegexMatch(t, BuildProjectIndex(2, "test"), RegexProjectIndex, map[string]string{"page": "2", "category": "test"})
|
||||||
assert.Panics(t, func() { BuildProjectIndex(0, "") })
|
assert.Panics(t, func() { BuildProjectIndex(0, "") })
|
||||||
|
@ -427,6 +426,16 @@ func TestJamFeed2023(t *testing.T) {
|
||||||
AssertSubdomain(t, BuildJamFeed2023(), "")
|
AssertSubdomain(t, BuildJamFeed2023(), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJamIndex2024_Learning(t *testing.T) {
|
||||||
|
AssertRegexMatch(t, BuildJamIndex2024_Learning(), RegexJamIndex2024_Learning, nil)
|
||||||
|
AssertSubdomain(t, BuildJamIndex2024_Learning(), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJamFeed2024_Learning(t *testing.T) {
|
||||||
|
AssertRegexMatch(t, BuildJamFeed2024_Learning(), RegexJamFeed2024_Learning, nil)
|
||||||
|
AssertSubdomain(t, BuildJamFeed2024_Learning(), "")
|
||||||
|
}
|
||||||
|
|
||||||
func TestTimeMachine(t *testing.T) {
|
func TestTimeMachine(t *testing.T) {
|
||||||
AssertRegexMatch(t, BuildTimeMachine(), RegexTimeMachine, nil)
|
AssertRegexMatch(t, BuildTimeMachine(), RegexTimeMachine, nil)
|
||||||
AssertSubdomain(t, BuildTimeMachine(), "")
|
AssertSubdomain(t, BuildTimeMachine(), "")
|
||||||
|
|
|
@ -126,6 +126,20 @@ func BuildJamRecap2023_Visibility() string {
|
||||||
return Url("/jam/visibility-2023/recap", nil)
|
return Url("/jam/visibility-2023/recap", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var RegexJamIndex2024_Learning = regexp.MustCompile("^/jam/learning-2024$")
|
||||||
|
|
||||||
|
func BuildJamIndex2024_Learning() string {
|
||||||
|
defer CatchPanic()
|
||||||
|
return Url("/jam/learning-2024", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var RegexJamFeed2024_Learning = regexp.MustCompile("^/jam/learning-2024/feed$")
|
||||||
|
|
||||||
|
func BuildJamFeed2024_Learning() string {
|
||||||
|
defer CatchPanic()
|
||||||
|
return Url("/jam/learning-2024/feed", nil)
|
||||||
|
}
|
||||||
|
|
||||||
func BuildJamIndexAny(slug string) string {
|
func BuildJamIndexAny(slug string) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
return Url(fmt.Sprintf("/jam/%s", slug), nil)
|
return Url(fmt.Sprintf("/jam/%s", slug), nil)
|
||||||
|
|
|
@ -91,7 +91,7 @@
|
||||||
<a href="{{ .Header.FishbowlUrl }}">Fishbowls</a>
|
<a href="{{ .Header.FishbowlUrl }}">Fishbowls</a>
|
||||||
<a href="{{ .Header.PodcastUrl }}">Podcast</a>
|
<a href="{{ .Header.PodcastUrl }}">Podcast</a>
|
||||||
<a href="https://guide.handmade-seattle.com/s" target="_blank">Handmade Dev Show</a>
|
<a href="https://guide.handmade-seattle.com/s" target="_blank">Handmade Dev Show</a>
|
||||||
<a href="{{ .Header.CalendarUrl }}">Calendar</a>
|
{{/*<a href="{{ .Header.CalendarUrl }}">Calendar</a>*/}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="root-item">
|
<div class="root-item">
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
{{ template "jam_2024_learning_base.html" . }}
|
||||||
|
{{ define "content-top" }}
|
||||||
|
<div class="flex flex-column items-center pa3 g3">
|
||||||
|
<img class="mw5" src="{{ static "visjam2023/logo.svg" }}">
|
||||||
|
<div class="f1 fw7">The Learning Jam</div>
|
||||||
|
<div class="flex flex-row g5 lh-solid">
|
||||||
|
<div>
|
||||||
|
<div class="fw7 f3">Learn</div>
|
||||||
|
<div class="fw3 f4">March 15-17, 2024</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="fw7 f3">Teach</div>
|
||||||
|
<div class="fw3 f4">March 22-24, 2024</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt3">
|
||||||
|
<a href="{{ .DiscordInviteUrl }}" class="db ph2 pv1 button-simple">Join the Discord</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "content" }}
|
||||||
|
<div class="flex flex-column g3 items-center pa3">
|
||||||
|
<div class="w6">
|
||||||
|
<h2 class="c--theme-gradient-light">Recent activity</h2>
|
||||||
|
<div class="flex flex-column g3">
|
||||||
|
{{ if .TimelineItems }}
|
||||||
|
{{ range .TimelineItems }}
|
||||||
|
<div class="flex flex-column g2 bg--rich-gray pa2">
|
||||||
|
<div class="flex flex-row g2">
|
||||||
|
{{ if .OwnerAvatarUrl }}
|
||||||
|
<a class="flex flex-shrink-0 br-100 square items-center justify-center overflow-hidden bg--gray" href="{{ .OwnerUrl }}">
|
||||||
|
<img class="w2" src="{{ .OwnerAvatarUrl }}" />
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
<div class="flex flex-column">
|
||||||
|
<div class="fw6">{{ .OwnerName }}</div>
|
||||||
|
<div class="f7">{{ timehtml (relativedate .Date) .Date }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ if .Description }}
|
||||||
|
<div>{{ trim .Description }}</div>
|
||||||
|
{{ end }}
|
||||||
|
{{ range .EmbedMedia }}
|
||||||
|
<div class="flex flex-column {{ if eq .Type mediaembed }}wide-screen{{ end }} justify-stretch iframe-fill">
|
||||||
|
{{ if eq .Type mediaimage }}
|
||||||
|
<img src="{{ .AssetUrl }}">
|
||||||
|
{{ else if eq .Type mediavideo }}
|
||||||
|
{{ if .ThumbnailUrl }}
|
||||||
|
<video src="{{ .AssetUrl }}" poster="{{ .ThumbnailUrl }}" preload="none" controls>
|
||||||
|
{{ else }}
|
||||||
|
<video src="{{ .AssetUrl }}" preload="metadata" controls>
|
||||||
|
{{ end }}
|
||||||
|
{{ else if eq .Type mediaaudio }}
|
||||||
|
<audio src="{{ .AssetUrl }}" controls>
|
||||||
|
{{ else if eq .Type mediaembed }}
|
||||||
|
{{ .EmbedHTML }}
|
||||||
|
{{ else }}
|
||||||
|
<div class="">
|
||||||
|
<a href="{{ .AssetUrl }}" target="_blank">{{ .Filename }} ({{ filesize .FileSize }})</a>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
{{ else }}
|
||||||
|
Be the first!
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
{{ template "jam_2024_learning_base.html" . }}
|
||||||
|
{{ define "content-top" }}
|
||||||
|
<div class="flex flex-column items-center pa3 g3">
|
||||||
|
<img class="mw5" src="{{ static "visjam2023/logo.svg" }}">
|
||||||
|
<div class="f1 fw7">The Learning Jam</div>
|
||||||
|
<div class="flex flex-row g5 lh-solid">
|
||||||
|
<div>
|
||||||
|
<div class="fw7 f3">Learn</div>
|
||||||
|
<div class="fw3 f4">March 15-17, 2024</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="fw7 f3">Teach</div>
|
||||||
|
<div class="fw3 f4">March 22-24, 2024</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ if lt .DaysUntilStart 0 }}
|
||||||
|
<div class="flex flex-row g3 mt2">
|
||||||
|
{{ if .SubmittedProjectUrl }}
|
||||||
|
<a class="db ph3 pv2 f4 button-simple" href="{{ .SubmittedProjectUrl }}">Share your progress</a>
|
||||||
|
{{ else }}
|
||||||
|
<a class="db ph3 pv2 f4 button-simple" href="{{ .ProjectSubmissionUrl }}">Create your project</a>
|
||||||
|
{{ end }}
|
||||||
|
<a class="db ph3 pv2 f4 button-simple" href="{{ .JamFeedUrl }}">Recent activity</a>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
<div class="mt2">
|
||||||
|
<a href="{{ .DiscordInviteUrl }}" class="db ph2 pv1 button-simple">Join the Discord</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "content" }}
|
||||||
|
<style>
|
||||||
|
.participate-icon {
|
||||||
|
--mask-url: url("{{ static "visjam2023/logo.svg" }}");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="flex flex-column g3 items-center pa3">
|
||||||
|
<div class="w6">
|
||||||
|
<h2 class="c--theme-gradient-light">How to participate</h2>
|
||||||
|
<div class="flex flex-column g2 pa3">
|
||||||
|
<div class="flex flex-row g3 items-center bg--rich-gray pa2">
|
||||||
|
<div class="svg-mask participate-icon bg--theme-gradient-light">
|
||||||
|
<img class="w4 invisible" src="{{ static "visjam2023/logo.svg" }}" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-column g2">
|
||||||
|
<div class="f4 fw7">Pick a project and form a team</div>
|
||||||
|
<div>Find a project idea that excites you etc...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row g3 items-center bg--rich-gray pa2">
|
||||||
|
<div class="svg-mask participate-icon bg--theme-gradient-light">
|
||||||
|
<img class="w4 invisible" src="{{ static "visjam2023/logo.svg" }}" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-column g2">
|
||||||
|
<div class="f4 fw7">Pick a project and form a team</div>
|
||||||
|
<div>Find a project idea that excites you etc...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row g3 items-center bg--rich-gray pa2">
|
||||||
|
<div class="svg-mask participate-icon bg--theme-gradient-light">
|
||||||
|
<img class="w4 invisible" src="{{ static "visjam2023/logo.svg" }}" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-column g2">
|
||||||
|
<div class="f4 fw7">Pick a project and form a team</div>
|
||||||
|
<div>Find a project idea that excites you etc...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w7 center bb b--rich-gray"></div>
|
||||||
|
<div class="w6">
|
||||||
|
<h2 class="c--theme-gradient-light">March 15 - 17, 2024</h2>
|
||||||
|
<div>
|
||||||
|
Do things
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w7 center bb b--rich-gray"></div>
|
||||||
|
<div class="w6">
|
||||||
|
<h2 class="c--theme-gradient-light">March 22 - 24, 2024</h2>
|
||||||
|
<div>
|
||||||
|
Do more things
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w7 center bb b--rich-gray"></div>
|
||||||
|
<div class="w6">
|
||||||
|
<h2 class="c--theme-gradient-light">Rules</h2>
|
||||||
|
<div>
|
||||||
|
Do more things
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
|
@ -16,6 +16,11 @@
|
||||||
<p>Since 2020, we have been running programming jams to encourage community members to explore new ideas and start projects. You can view all the past submissions and results here.</p>
|
<p>Since 2020, we have been running programming jams to encourage community members to explore new ideas and start projects. You can view all the past submissions and results here.</p>
|
||||||
|
|
||||||
<div class="jam-grid g3">
|
<div class="jam-grid g3">
|
||||||
|
<a href="{{ .LJ2024Url }}">
|
||||||
|
<div class="br2 overflow-hidden flex">
|
||||||
|
<img src="{{ static "learningjam2024/TwitterCard.png" }}">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
<a href="{{ .WRJ2023Url }}">
|
<a href="{{ .WRJ2023Url }}">
|
||||||
<div class="br2 overflow-hidden flex">
|
<div class="br2 overflow-hidden flex">
|
||||||
<img src="{{ static "wheeljam2023/TwitterCard.png" }}">
|
<img src="{{ static "wheeljam2023/TwitterCard.png" }}">
|
||||||
|
|
|
@ -111,6 +111,74 @@
|
||||||
</div>
|
</div>
|
||||||
*/}}
|
*/}}
|
||||||
|
|
||||||
|
<div class="mb3 ph3 ph0-ns">
|
||||||
|
<style>
|
||||||
|
#jam-banner {
|
||||||
|
background: linear-gradient(to bottom right, #003c83, #019AD2);
|
||||||
|
color: white !important;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#jam-banner h3 {
|
||||||
|
font-family: 'MohaveHMN', sans-serif;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 2.2rem;
|
||||||
|
line-height: 0.8;
|
||||||
|
margin: 0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
#jam-details {
|
||||||
|
font-family: 'MohaveHMN', sans-serif;
|
||||||
|
font-variant: small-caps;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 0.8;
|
||||||
|
margin-top: 0.6rem;
|
||||||
|
letter-spacing: 0.02rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#jam-learn-more {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 30rem) {
|
||||||
|
#jam-banner {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#jam-title-container {
|
||||||
|
padding-top: 0.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<a id="jam-banner" class="pv3 ph3 ph4-l br3 flex flex-column flex-row-ns items-center" href="{{ .JamUrl }}">
|
||||||
|
<img class="h3" src="{{ static "wheeljam2023/logo.svg" }}">
|
||||||
|
<div id="jam-title-container" class="flex flex-column pl3-m pl4-l pv3 pv0-ns">
|
||||||
|
<h3 id="jam-title">The Learning Jam</h3>
|
||||||
|
<div id="jam-details">
|
||||||
|
March 15 - March 24.
|
||||||
|
{{ if gt .JamDaysUntilEnd 0 }}
|
||||||
|
{{ if eq .JamDaysUntilStart 0 }}
|
||||||
|
<b>Happening now.</b>
|
||||||
|
{{ else if eq .JamDaysUntilStart 1 }}
|
||||||
|
<b>Starting tomorrow.</b>
|
||||||
|
{{ else }}
|
||||||
|
<b>In {{ .JamDaysUntilStart }} days.</b>
|
||||||
|
{{ end }}
|
||||||
|
{{ else }}
|
||||||
|
<b>See the results.</b>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1"></div>
|
||||||
|
<div id="jam-learn-more">
|
||||||
|
Learn more
|
||||||
|
<div class="dib svgicon">{{ svg "chevron-right" }}</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{/*
|
||||||
<div class="mb3 ph3 ph0-ns">
|
<div class="mb3 ph3 ph0-ns">
|
||||||
<style>
|
<style>
|
||||||
#jam-banner {
|
#jam-banner {
|
||||||
|
@ -177,6 +245,7 @@
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
*/}}
|
||||||
|
|
||||||
{{/*
|
{{/*
|
||||||
<div class="mb3 ph3 ph0-ns">
|
<div class="mb3 ph3 ph0-ns">
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
{{/*
|
||||||
|
This is a copy-paste from base.html because we want to preserve the unique
|
||||||
|
style of this page no matter what future changes we make to the base.
|
||||||
|
*/}}
|
||||||
|
<!DOCTYPE html{{ if .OpenGraphItems }} prefix="og: http://ogp.me/ns#"{{ end }}>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="{{ static "learningjam2024/favicon-16x16.png" }}">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="{{ static "learningjam2024/favicon-32x32.png" }}">
|
||||||
|
|
||||||
|
{{ if .CanonicalLink }}<link rel="canonical" href="{{ .CanonicalLink }}">{{ end }}
|
||||||
|
{{ range .OpenGraphItems }}
|
||||||
|
{{ if .Property }}
|
||||||
|
<meta property="{{ .Property }}" content="{{ .Value }}" />
|
||||||
|
{{ else }}
|
||||||
|
<meta name="{{ .Name }}" content="{{ .Value }}" />
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
{{ if .Title }}
|
||||||
|
<title>{{ .Title }} | Handmade Network</title>
|
||||||
|
{{ else }}
|
||||||
|
<title>Handmade Network</title>
|
||||||
|
{{ end }}
|
||||||
|
<meta name="theme-color" content="#003C83">
|
||||||
|
|
||||||
|
<script src="{{ static "js/templates.js" }}"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="{{ static "fonts/mohave/stylesheet.css" }}">
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Fira+Sans:300,400,500,600' rel='stylesheet' type='text/css'>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Fira+Mono:300,400,500,700' rel='stylesheet' type='text/css'>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ static "style.css" }}">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--theme-gradient-dark: linear-gradient(to bottom right, #003c83, #019AD2);
|
||||||
|
--theme-gradient-light: linear-gradient(to bottom right, #8BD5FF, #2F69FF);
|
||||||
|
--white: #fff;
|
||||||
|
--bg-button: #082F5766;
|
||||||
|
--bg-button-hover: #082F5733;
|
||||||
|
--charcoal: #2F2F2F;
|
||||||
|
--gray: #CBCBCB;
|
||||||
|
--rich-gray: #494949;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Inter", "Fira Sans", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg--theme-gradient-dark {
|
||||||
|
background: var(--theme-gradient-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg--theme-gradient-light {
|
||||||
|
background: var(--theme-gradient-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg--charcoal {
|
||||||
|
background: var(--charcoal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg--rich-gray {
|
||||||
|
background: var(--rich-gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg--gray {
|
||||||
|
background: var(--gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
.b--rich-gray {
|
||||||
|
border-color: var(--rich-gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
.c--theme-gradient-dark {
|
||||||
|
background: var(--theme-gradient-dark);
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c--theme-gradient-light {
|
||||||
|
background: var(--theme-gradient-light);
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-simple {
|
||||||
|
background: var(--bg-button);
|
||||||
|
border: 1px solid var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-simple:hover {
|
||||||
|
background: var(--bg-button-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-white {
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.invisible {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-mask {
|
||||||
|
mask: var(--mask-url);
|
||||||
|
}
|
||||||
|
|
||||||
|
.square {
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wide-screen {
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iframe-fill iframe {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="flex flex-column">
|
||||||
|
<div class="c-white bg--theme-gradient-dark">
|
||||||
|
<div class="bb b--white pa1 mb3 flex flex-row g2 items-center">
|
||||||
|
<a href="{{ .Header.HMNHomepageUrl }}" class="f3">HANDMADE</a>
|
||||||
|
<div class="flex-grow-1 flex-shrink-1"></div>
|
||||||
|
</div>
|
||||||
|
{{ block "content-top" . }}{{ end }}
|
||||||
|
</div>
|
||||||
|
<div class="bg--charcoal c-white flex-grow-1">
|
||||||
|
{{ block "content" . }}{{ end }}
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const dtf = new Intl.DateTimeFormat([], {
|
||||||
|
dateStyle: "full",
|
||||||
|
timeStyle: "short",
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const time of document.querySelectorAll('time')) {
|
||||||
|
const d = new Date(Date.parse(time.dateTime));
|
||||||
|
if (time.getAttribute("data-type") == "content") {
|
||||||
|
time.textContent = dtf.format(d);
|
||||||
|
} else {
|
||||||
|
time.title = dtf.format(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -20,6 +20,7 @@ type BaseData struct {
|
||||||
CurrentProjectUrl string
|
CurrentProjectUrl string
|
||||||
LoginPageUrl string
|
LoginPageUrl string
|
||||||
ProjectCSSUrl string
|
ProjectCSSUrl string
|
||||||
|
DiscordInviteUrl string
|
||||||
|
|
||||||
Project Project
|
Project Project
|
||||||
User *User
|
User *User
|
||||||
|
|
|
@ -51,6 +51,7 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc
|
||||||
CurrentProjectUrl: c.UrlContext.BuildHomepage(),
|
CurrentProjectUrl: c.UrlContext.BuildHomepage(),
|
||||||
LoginPageUrl: hmnurl.BuildLoginPage(c.FullUrl()),
|
LoginPageUrl: hmnurl.BuildLoginPage(c.FullUrl()),
|
||||||
ProjectCSSUrl: hmnurl.BuildProjectCSS(project.Color1),
|
ProjectCSSUrl: hmnurl.BuildProjectCSS(project.Color1),
|
||||||
|
DiscordInviteUrl: "https://discord.gg/hmn",
|
||||||
|
|
||||||
Project: templates.ProjectToTemplate(&project, c.UrlContext.BuildHomepage()),
|
Project: templates.ProjectToTemplate(&project, c.UrlContext.BuildHomepage()),
|
||||||
User: templateUser,
|
User: templateUser,
|
||||||
|
|
|
@ -27,6 +27,7 @@ func JamsIndex(c *RequestContext) ResponseData {
|
||||||
WRJ2022Url string
|
WRJ2022Url string
|
||||||
VJ2023Url string
|
VJ2023Url string
|
||||||
WRJ2023Url string
|
WRJ2023Url string
|
||||||
|
LJ2024Url string
|
||||||
}
|
}
|
||||||
|
|
||||||
res.MustWriteTemplate("jams_index.html", TemplateData{
|
res.MustWriteTemplate("jams_index.html", TemplateData{
|
||||||
|
@ -37,6 +38,140 @@ func JamsIndex(c *RequestContext) ResponseData {
|
||||||
WRJ2022Url: hmnurl.BuildJamIndex2022(),
|
WRJ2022Url: hmnurl.BuildJamIndex2022(),
|
||||||
VJ2023Url: hmnurl.BuildJamIndex2023_Visibility(),
|
VJ2023Url: hmnurl.BuildJamIndex2023_Visibility(),
|
||||||
WRJ2023Url: hmnurl.BuildJamIndex2023(),
|
WRJ2023Url: hmnurl.BuildJamIndex2023(),
|
||||||
|
LJ2024Url: hmnurl.BuildJamIndex2024_Learning(),
|
||||||
|
}, c.Perf)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func JamIndex2024_Learning(c *RequestContext) ResponseData {
|
||||||
|
var res ResponseData
|
||||||
|
|
||||||
|
daysUntilStart := daysUntil(hmndata.LJ2024.StartTime)
|
||||||
|
daysUntilEnd := daysUntil(hmndata.LJ2024.EndTime)
|
||||||
|
|
||||||
|
baseData := getBaseDataAutocrumb(c, hmndata.LJ2024.Name)
|
||||||
|
baseData.OpenGraphItems = []templates.OpenGraphItem{
|
||||||
|
{Property: "og:site_name", Value: "Handmade Network"},
|
||||||
|
{Property: "og:type", Value: "website"},
|
||||||
|
{Property: "og:image", Value: hmnurl.BuildPublic("learningjam2024/opengraph.png", true)},
|
||||||
|
{Property: "og:description", Value: "Need desc"},
|
||||||
|
{Property: "og:url", Value: hmnurl.BuildJamIndex2024_Learning()},
|
||||||
|
}
|
||||||
|
|
||||||
|
type JamPageData struct {
|
||||||
|
templates.BaseData
|
||||||
|
DaysUntilStart, DaysUntilEnd int
|
||||||
|
TwitchEmbedUrl string
|
||||||
|
ProjectSubmissionUrl string
|
||||||
|
SubmittedProjectUrl string
|
||||||
|
JamFeedUrl string
|
||||||
|
}
|
||||||
|
|
||||||
|
twitchEmbedUrl := ""
|
||||||
|
twitchStatus, err := db.QueryOne[models.TwitchLatestStatus](c, c.Conn,
|
||||||
|
`
|
||||||
|
SELECT $columns
|
||||||
|
FROM twitch_latest_status
|
||||||
|
WHERE twitch_login = $1
|
||||||
|
`,
|
||||||
|
"handmadenetwork",
|
||||||
|
)
|
||||||
|
if err == nil {
|
||||||
|
if twitchStatus.Live {
|
||||||
|
hmnUrl, err := url.Parse(config.Config.BaseUrl)
|
||||||
|
if err == nil {
|
||||||
|
twitchEmbedUrl = fmt.Sprintf("https://player.twitch.tv/?channel=%s&parent=%s", twitchStatus.TwitchLogin, hmnUrl.Hostname())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
submittedProjectUrl := ""
|
||||||
|
|
||||||
|
if c.CurrentUser != nil {
|
||||||
|
projects, err := hmndata.FetchProjects(c, c.Conn, c.CurrentUser, hmndata.ProjectsQuery{
|
||||||
|
OwnerIDs: []int{c.CurrentUser.ID},
|
||||||
|
JamSlugs: []string{hmndata.WRJ2023.Slug},
|
||||||
|
Limit: 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch jam projects for current user"))
|
||||||
|
}
|
||||||
|
if len(projects) > 0 {
|
||||||
|
urlContext := hmndata.UrlContextForProject(&projects[0].Project)
|
||||||
|
submittedProjectUrl = urlContext.BuildHomepage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.MustWriteTemplate("jam_2024_lj_index.html", JamPageData{
|
||||||
|
BaseData: baseData,
|
||||||
|
DaysUntilStart: daysUntilStart,
|
||||||
|
DaysUntilEnd: daysUntilEnd,
|
||||||
|
ProjectSubmissionUrl: hmnurl.BuildProjectNewJam(),
|
||||||
|
SubmittedProjectUrl: submittedProjectUrl,
|
||||||
|
JamFeedUrl: hmnurl.BuildJamFeed2024_Learning(),
|
||||||
|
TwitchEmbedUrl: twitchEmbedUrl,
|
||||||
|
}, c.Perf)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func JamFeed2024_Learning(c *RequestContext) ResponseData {
|
||||||
|
jamProjects, err := hmndata.FetchProjects(c, c.Conn, c.CurrentUser, hmndata.ProjectsQuery{
|
||||||
|
JamSlugs: []string{hmndata.LJ2024.Slug},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch jam projects for current user"))
|
||||||
|
}
|
||||||
|
|
||||||
|
projectIds := make([]int, 0, len(jamProjects))
|
||||||
|
for _, jp := range jamProjects {
|
||||||
|
projectIds = append(projectIds, jp.Project.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
var timelineItems []templates.TimelineItem
|
||||||
|
if len(projectIds) > 0 {
|
||||||
|
snippets, err := hmndata.FetchSnippets(c, c.Conn, c.CurrentUser, hmndata.SnippetQuery{
|
||||||
|
ProjectIDs: projectIds,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets for jam showcase"))
|
||||||
|
}
|
||||||
|
|
||||||
|
timelineItems = make([]templates.TimelineItem, 0, len(snippets))
|
||||||
|
for _, s := range snippets {
|
||||||
|
timelineItem := SnippetToTimelineItem(&s.Snippet, s.Asset, s.DiscordMessage, s.Projects, s.Owner, c.Theme, false)
|
||||||
|
timelineItem.SmallInfo = true
|
||||||
|
timelineItems = append(timelineItems, timelineItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type JamFeedData struct {
|
||||||
|
templates.BaseData
|
||||||
|
DaysUntilStart, DaysUntilEnd int
|
||||||
|
|
||||||
|
TimelineItems []templates.TimelineItem
|
||||||
|
}
|
||||||
|
|
||||||
|
daysUntilStart := daysUntil(hmndata.LJ2024.StartTime)
|
||||||
|
daysUntilEnd := daysUntil(hmndata.LJ2024.EndTime)
|
||||||
|
|
||||||
|
baseData := getBaseDataAutocrumb(c, hmndata.LJ2024.Name)
|
||||||
|
baseData.OpenGraphItems = []templates.OpenGraphItem{
|
||||||
|
{Property: "og:site_name", Value: "Handmade Network"},
|
||||||
|
{Property: "og:type", Value: "website"},
|
||||||
|
{Property: "og:image", Value: hmnurl.BuildPublic("learningjam2024/opengraph.png", true)},
|
||||||
|
{Property: "og:description", Value: "Need desc"},
|
||||||
|
{Property: "og:url", Value: hmnurl.BuildJamFeed2024_Learning()},
|
||||||
|
}
|
||||||
|
|
||||||
|
var res ResponseData
|
||||||
|
res.MustWriteTemplate("jam_2024_lj_feed.html", JamFeedData{
|
||||||
|
BaseData: baseData,
|
||||||
|
DaysUntilStart: daysUntilStart,
|
||||||
|
DaysUntilEnd: daysUntilEnd,
|
||||||
|
TimelineItems: timelineItems,
|
||||||
|
// ProjectSubmissionUrl: hmnurl.BuildProjectNewJam(),
|
||||||
|
// SubmittedProjectUrl: submittedProjectUrl,
|
||||||
|
// JamProjects: pageProjects,
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,9 +156,9 @@ func Index(c *RequestContext) ResponseData {
|
||||||
AtomFeedUrl: hmnurl.BuildAtomFeed(),
|
AtomFeedUrl: hmnurl.BuildAtomFeed(),
|
||||||
MarkAllReadUrl: hmnurl.HMNProjectContext.BuildForumMarkRead(0),
|
MarkAllReadUrl: hmnurl.HMNProjectContext.BuildForumMarkRead(0),
|
||||||
|
|
||||||
JamUrl: hmnurl.BuildJamIndex2023(),
|
JamUrl: hmnurl.BuildJamIndex2024_Learning(),
|
||||||
JamDaysUntilStart: daysUntil(hmndata.WRJ2023.StartTime),
|
JamDaysUntilStart: daysUntil(hmndata.LJ2024.StartTime),
|
||||||
JamDaysUntilEnd: daysUntil(hmndata.WRJ2023.EndTime),
|
JamDaysUntilEnd: daysUntil(hmndata.LJ2024.EndTime),
|
||||||
|
|
||||||
HMSDaysUntilStart: daysUntil(hmndata.HMS2023.StartTime),
|
HMSDaysUntilStart: daysUntil(hmndata.HMS2023.StartTime),
|
||||||
HMSDaysUntilEnd: daysUntil(hmndata.HMS2023.EndTime),
|
HMSDaysUntilEnd: daysUntil(hmndata.HMS2023.EndTime),
|
||||||
|
|
|
@ -71,6 +71,8 @@ func NewWebsiteRoutes(conn *pgxpool.Pool) http.Handler {
|
||||||
hmnOnly.GET(hmnurl.RegexJamRecap2023_Visibility, JamRecap2023_Visibility)
|
hmnOnly.GET(hmnurl.RegexJamRecap2023_Visibility, JamRecap2023_Visibility)
|
||||||
hmnOnly.GET(hmnurl.RegexJamIndex2023, JamIndex2023)
|
hmnOnly.GET(hmnurl.RegexJamIndex2023, JamIndex2023)
|
||||||
hmnOnly.GET(hmnurl.RegexJamFeed2023, JamFeed2023)
|
hmnOnly.GET(hmnurl.RegexJamFeed2023, JamFeed2023)
|
||||||
|
hmnOnly.GET(hmnurl.RegexJamIndex2024_Learning, JamIndex2024_Learning)
|
||||||
|
hmnOnly.GET(hmnurl.RegexJamFeed2024_Learning, JamFeed2024_Learning)
|
||||||
|
|
||||||
hmnOnly.GET(hmnurl.RegexTimeMachine, TimeMachine)
|
hmnOnly.GET(hmnurl.RegexTimeMachine, TimeMachine)
|
||||||
hmnOnly.GET(hmnurl.RegexTimeMachineSubmissions, TimeMachineSubmissions)
|
hmnOnly.GET(hmnurl.RegexTimeMachineSubmissions, TimeMachineSubmissions)
|
||||||
|
|
Loading…
Reference in New Issue