Compare commits

...

6 Commits

Author SHA1 Message Date
Asaf Gartner 2065bad860 Added tooltip to project owners on the LJ page. 2024-03-14 02:31:59 +02:00
Ben Visness 5dd4880d4c heaaaghghghghg jam time yayaya 2024-03-12 23:20:35 -05:00
Ben Visness ee491c7696 Learning jam final design phase 1 2024-03-12 21:13:05 -05:00
Asaf Gartner f085858e9e Merge remote-tracking branch 'origin/beta' 2024-03-11 20:17:44 +02:00
Asaf Gartner 639ea17a88 Timeline and projects for learning jam 2024-03-11 20:15:32 +02:00
Asaf Gartner 2eb3288b2a LJ jam feed basics 2024-03-11 18:27:34 +02:00
16 changed files with 615 additions and 313 deletions

View File

@ -140,6 +140,13 @@ func BuildJamFeed2024_Learning() string {
return Url("/jam/learning-2024/feed", nil)
}
var RegexJamGuidelines2024_Learning = regexp.MustCompile("^/jam/learning-2024/guidelines$")
func BuildJamGuidelines2024_Learning() string {
defer CatchPanic()
return Url("/jam/learning-2024/guidelines", nil)
}
func BuildJamIndexAny(slug string) string {
defer CatchPanic()
return Url(fmt.Sprintf("/jam/%s", slug), nil)

View File

@ -103,6 +103,9 @@ func ProjectToTemplate(
func ProjectAndStuffToTemplate(p *hmndata.ProjectAndStuff, url string, theme string) Project {
res := ProjectToTemplate(&p.Project, url)
res.Logo = ProjectLogoUrl(&p.Project, p.LogoLightAsset, p.LogoDarkAsset, theme)
for _, o := range p.Owners {
res.Owners = append(res.Owners, UserToTemplate(o, theme))
}
return res
}

View File

@ -0,0 +1,23 @@
<div class="mw7 margin-center link--white">
<div class="flex flex-column pv4 tc">
<img class="jam-logo margin-center" src="{{ static "learningjam2024/logo.svg" }}">
<div class="margin-center mt3 mt4-ns">
<a class="jam-title db mb3" href="{{ .JamUrl }}">Learning Jam</a>
<div class="flex flex-column flex-row-ns justify-between lh-solid g3 g0-ns">
<div>
<div class="fw7 f3 mb1">Learn</div>
<div class="fw3 f4">March 15-17, 2024</div>
</div>
<div>
<div class="fw7 f3 mb1">Share</div>
<div class="fw3 f4">March 22-24, 2024</div>
</div>
</div>
</div>
{{ if gt .DaysUntilEnd 0 }}
<div class="flex g3 justify-center mt4">
<a href="{{ .DiscordInviteUrl }}" class="btn--jam">Join the Discord</a>
</div>
{{ end }}
</div>
</div>

View File

@ -0,0 +1,19 @@
<div class="mw7 margin-center link--white">
<div class="flex flex-column flex-row-ns justify-center items-center pv4 g3 tc tl-ns">
<img class="jam-logo-small" src="{{ static "learningjam2024/logo.svg" }}">
<div class="flex flex-column justify-between">
<div>
<a class="jam-title db small" href="{{ .JamUrl }}">Learning Jam</a>
<div class="fw6 f5 mb3">March 15 - 24, 2024</div>
</div>
<div class="flex items-center g2">
{{ if and (not .SubmittedProjectUrl) (gt .DaysUntilEnd 0) }}
<a href="{{ .NewProjectUrl }}" class="btn--jam">Create your project</a>
{{ else }}
<a href="{{ .DiscordInviteUrl }}" class="btn--jam">Join the Discord</a>
{{ end }}
<a href="{{ .GuidelinesUrl }}" class="flex items-baseline pa2">Guidelines <div class="dib svgicon f8 ml1">{{ svg "chevron-right" }}</div></a>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,14 @@
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="dib c--theme-gradient-light">What is a Learning Jam?</h2>
<div class="post-content">
<p>
The <b class="c--theme-gradient-light">Learning Jam</b> is an opportunity for you to learn something new.
</p>
<p>
Unlike traditional game jams, and unlike our previous programming jams, the goal of the <b class="c--theme-gradient-light">Learning Jam</b> is <em>knowledge</em>. It's an opportunity to throw yourself at a topic and learn everything you can about it—and then, to turn around and share that knowledge with others.
</p>
<p>
The jam takes place over <b>two weekends</b>. On the first weekend, you'll learn as much as you can about your topic of choice. On the second, you'll share what you learned in whatever form you like—writeup, video, Minecraft mod, whatever.
</p>
</div>
</div>

View File

@ -0,0 +1,41 @@
{{ range . }}
<div class="flex flex-column g3 bg--rich-gray pa3">
<div class="flex flex-row g3 items-start">
{{ if .OwnerAvatarUrl }}
<a class="flex flex-shrink-0 br-100 square items-center justify-center overflow-hidden" href="{{ .OwnerUrl }}">
<img class="user-avatar w2-5" src="{{ .OwnerAvatarUrl }}" />
</a>
{{ end }}
<div class="flex flex-column">
<div class="">
<a title="{{ (index .Projects 0).Blurb }}" href="{{ (index .Projects 0).Url }}" class="link--white fw6">{{ (index .Projects 0).Name }}</a>
by
<a href="{{ .OwnerUrl }}" class="link--white fw6">{{ .OwnerName }}</a>
<span class="f7 c--gray nowrap">{{ timehtml (relativedate .Date) .Date }}</span>
</div>
<div>{{ trim .Description }}</div>
</div>
</div>
{{ 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 }}

View File

@ -0,0 +1,100 @@
<style>
.lightbulb-icon {
--mask-url: url("{{ static "learningjam2024/lightbulb.svg" }}");
}
.books-icon {
--mask-url: url("{{ static "learningjam2024/books.svg" }}");
}
.presentation-icon {
--mask-url: url("{{ static "learningjam2024/presentation.svg" }}");
}
</style>
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="dib c--theme-gradient-light">What is a Learning Jam?</h2>
<div class="post-content">
<p>
The <b class="c--theme-gradient-light">Learning Jam</b> is an opportunity for you to learn something new.
</p>
<p>
Unlike traditional game jams, and unlike our previous programming jams, the goal of the <b class="c--theme-gradient-light">Learning Jam</b> is <em>knowledge</em>. It's an opportunity to throw yourself at a topic and learn everything you can about it—and then, to turn around and share that knowledge with others.
</p>
<p>
The jam takes place over <b>two weekends</b>. On the first weekend, you'll learn as much as you can about your topic of choice. On the second, you'll share what you learned in whatever form you like—writeup, video, Minecraft mod, whatever.
</p>
</div>
</div>
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="mb3 dib c--theme-gradient-light">How to participate</h2>
<div class="flex flex-column g2">
<div class="pa3 flex flex-column flex-row-ns g3 items-center bg--rich-gray">
<div class="flex-shrink-0 w4 flex justify-center items-center">
<div class="flex svg-mask lightbulb-icon bg--theme-gradient-light" style="width: 5.2rem">
<img class="invisible" src="{{ static "learningjam2024/lightbulb.svg" }}" />
</div>
</div>
<div class="post-content">
<h3 class="f4">Choose a topic.</h3>
<p>
Decide what you'll spend your weekend learning about. Maybe there's an area of programming you've been meaning to dig into, or maybe there's a specialization in your field that you've been curious about. Maybe you just need a reason to read papers for a weekend.
</p>
<p>
You're welcome to work in teams or work solo.
</p>
</div>
</div>
<div class="pa3 flex flex-column flex-row-ns g3 items-center bg--rich-gray">
<div class="flex-shrink-0 w4 flex justify-center items-center">
<div class="flex flex-shrink-0 svg-mask books-icon bg--theme-gradient-light" style="width: 3.6rem">
<img class="invisible" src="{{ static "learningjam2024/books.svg" }}" />
</div>
</div>
<div class="post-content">
<h3 class="f4">Mar 15-17: Learn!</h3>
<p>
{{ if and (eq .DaysUntilStart 0) (not .SubmittedProjectUrl) }}
<a href="{{ .NewProjectUrl }}">Create a Handmade Network project</a>
{{ else }}
Create a Handmade Network project
{{ end }}
to track your progress. Then go down the rabbit hole. Absorb as much information as you can in a weekend.
</p>
<p>
As you learn, we encourage you to share updates on Discord using the <b>!til</b> command. These updates will be published as part of your submission.
</p>
</div>
</div>
<div class="pa3 flex flex-column flex-row-ns g3 items-center bg--rich-gray">
<div class="flex-shrink-0 w4 flex justify-center items-center">
<div class="flex flex-shrink-0 svg-mask presentation-icon bg--theme-gradient-light" style="width: 5rem">
<img class="invisible" src="{{ static "learningjam2024/presentation.svg" }}" />
</div>
</div>
<div class="post-content">
<h3 class="f4">Mar 22-24: Share!</h3>
<p>
Share what you learned with the rest of the community. You can present the information in any form you like—whatever helps you communicate most effectively.
</p>
<p>
Your post doesn't have to be the authoritative resource on a subject. It doesn't even have to do much "teaching" at all. The point is just to share what you learned, what surprised you, what you found interesting, and where you want to go from here.
</p>
<p>
Your Handmade Network project is your final submission. Make sure the description gives adequate context, and either attach or link to your final presentation.
</p>
</div>
</div>
</div>
</div>
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="dib c--theme-gradient-light">Why?</h2>
<div class="post-content">
<p>
The Handmade Network's goal is to change the software industry by building back up from new foundations. But in order to do that, we need to understand those foundations.
</p>
<p>
Our other programming jams are great opportunities to try building new things. But what should those new things be? We want to give the community a chance to focus just on learning and research, to gather information and share it with others, to boost the entire community's knowledge on a topic.
</p>
<p>
We hope that the results of the <b class="c--theme-gradient-light">Learning Jam</b> inspire new ideas for the community to explore in the Visibility and Wheel Reinvention jams later in the year. There is so much bad software out in the world, and this is the first step toward reinventing it.
</p>
</div>
</div>

View File

@ -0,0 +1,35 @@
{{ if .Projects }}
<div class="flex flex-row flex-wrap g2 link--white">
{{ range .Projects }}
<div class="flex-basis-40-ns flex-grow-1 flex-shrink-1 bg--rich-gray pa3 flex flex-column g1">
{{ if gt (len .Owners) 1 }}
<div class="flex g2">
{{ range .Owners }}
<a title="{{ .Name }}" href="{{ .ProfileUrl }}" class="flex">
<img src="{{ .AvatarUrl }}" class="user-avatar w2">
</a>
{{ end }}
</div>
{{ else }}
{{ range .Owners }}
<a href="{{ .ProfileUrl }}" class="fw6 link--white flex g2 items-center">
<img src="{{ .AvatarUrl }}" class="user-avatar w2">
<div>
{{ .Name }}
</div>
</a>
{{ end }}
{{ end }}
<div class="f3 mt2">
<a href="{{ .Url }}" class="fw6 db">{{ .Name }}</a>
</div>
<div class="flex-grow-1">{{ .Blurb }}</div>
</div>
{{ end }}
{{ if isodd (len .Projects) }}
<div class="flex-basis-40-ns flex-grow-1 flex-shrink-1"></div>
{{ end }}
</div>
{{ else }}
No projects have been created yet. <a href="{{ .NewProjectUrl }}">Be the first!</a>
{{ end }}

View File

@ -1,72 +1,29 @@
{{ 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>
{{ template "jam_2024_lj_bannersmall.html" . }}
{{ 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 class="mw7 margin-center flex flex-column">
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="c--theme-gradient-light mb3">Projects</h2>
{{ template "jam_2024_lj_projects.html" .Projects }}
</div>
{{ if .TimelineItems }}
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="c--theme-gradient-light">All updates</h2>
<p>
See what community members are learning about their topics. You can share your own updates via your <a href="{{ or .SubmittedProjectUrl .NewProjectUrl }}">project page</a> or using the <b>!til</b> command on Discord.
</p>
<div class="flex flex-column g2 mt3">
{{ template "jam_2024_lj_feeditems.html" .TimelineItems }}
</div>
</div>
{{ end }}
<div>
<div class="mv5 h3 fill-current link--white">
<a href="{{ .Header.HMNHomepageUrl }}">{{ svg "hmn_circuit" }}</a>
</div>
</div>
</div>

View File

@ -0,0 +1,16 @@
{{ template "jam_2024_learning_base.html" . }}
{{ define "content-top" }}
{{ template "jam_2024_lj_bannersmall.html" . }}
{{ end }}
{{ define "content" }}
<div class="mw7 margin-center flex flex-column">
{{ template "jam_2024_lj_guidelines.html" . }}
<div>
<div class="mv5 h3 fill-current link--white">
<a href="{{ .Header.HMNHomepageUrl }}">{{ svg "hmn_circuit" }}</a>
</div>
</div>
</div>
{{ end }}

View File

@ -1,170 +1,83 @@
{{ template "jam_2024_learning_base.html" . }}
{{ define "extrahead" }}
<style>
.jam-logo {
max-width: 18rem;
}
.jam-title {
/* align with the width of the logo */
font-size: 2.76rem;
font-weight: 700;
/* align with the text's actual bounding box */
line-height: 1.18;
margin-top: -0.18em;
margin-left: -0.03em;
margin-right: -0.03em;
}
/* not small */
@media screen and (min-width: 35em) {
.jam-logo {
max-width: 24rem;
}
.jam-title {
font-size: 3.7rem;
}
}
</style>
{{ end }}
{{ define "content-top" }}
<div class="mw7 margin-center">
<div class="flex flex-column pv4 tc">
<img class="jam-logo margin-center" src="{{ static "learningjam2024/logo.svg" }}">
<div class="margin-center mt3 mt4-ns mb4">
<div class="jam-title mb3">Learning Jam</div>
<div class="flex flex-column flex-row-ns justify-between lh-solid g3 g0-ns">
<div>
<div class="fw7 f3 mb1">Learn</div>
<div class="fw3 f4">March 15-17, 2024</div>
</div>
<div>
<div class="fw7 f3 mb1">Share</div>
<div class="fw3 f4">March 22-24, 2024</div>
</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="flex g3 justify-center">
<a href="{{ .DiscordInviteUrl }}" class="btn--jam">Join the Discord</a>
</div>
</div>
</div>
{{ if or (gt .DaysUntilStart 0) (eq .DaysUntilEnd 0) }}
{{ template "jam_2024_lj_bannerbig.html" . }}
{{ else }}
{{ template "jam_2024_lj_bannersmall.html" . }}
{{ end }}
{{ end }}
{{ define "content" }}
<style>
.lightbulb-icon {
--mask-url: url("{{ static "learningjam2024/lightbulb.svg" }}");
}
.books-icon {
--mask-url: url("{{ static "learningjam2024/books.svg" }}");
}
.presentation-icon {
--mask-url: url("{{ static "learningjam2024/presentation.svg" }}");
}
</style>
<div class="mw7 margin-center flex flex-column">
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="dib c--theme-gradient-light">What is a Learning Jam?</h2>
<div class="post-content">
<p>
The <b class="c--theme-gradient-light">Learning Jam</b> is an opportunity for you to learn something new.
</p>
<p>
Unlike traditional game jams, and unlike our previous programming jams, the goal of the <b class="c--theme-gradient-light">Learning Jam</b> is <em>knowledge</em>. It's an opportunity to throw yourself at a topic and learn everything you can about it—and then, to turn around and share that knowledge with others.
</p>
<p>
The jam takes place over <b>two weekends</b>. On the first weekend, you'll learn as much as you can about your topic of choice. On the second, you'll share what you learned in whatever form you like—writeup, video, Minecraft mod, whatever.
</p>
</div>
</div>
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="mb3 dib c--theme-gradient-light">How to participate</h2>
<div class="flex flex-column g2">
<div class="pa3 flex flex-column flex-row-ns g3 items-center bg--rich-gray">
<div class="flex-shrink-0 w4 flex justify-center items-center">
<div class="flex svg-mask lightbulb-icon bg--theme-gradient-light" style="width: 5.2rem">
<img class="invisible" src="{{ static "learningjam2024/lightbulb.svg" }}" />
</div>
</div>
<div class="post-content">
<h3 class="f4">Choose a topic.</h3>
<p>
Decide what you'll spend your weekend learning about. Maybe there's an area of programming you've been meaning to dig into, or maybe there's a specialization in your field that you've been curious about. Maybe you just need a reason to read papers for a weekend.
</p>
<p>
You're welcome to work in teams or work solo.
</p>
</div>
</div>
<div class="pa3 flex flex-column flex-row-ns g3 items-center bg--rich-gray">
<div class="flex-shrink-0 w4 flex justify-center items-center">
<div class="flex flex-shrink-0 svg-mask books-icon bg--theme-gradient-light" style="width: 3.6rem">
<img class="invisible" src="{{ static "learningjam2024/books.svg" }}" />
</div>
</div>
<div class="post-content">
<h3 class="f4">Mar 15-17: Learn!</h3>
<p>
Create a Handmade Network project to track your progress. Then go down the rabbit hole. Absorb as much information as you can in a weekend.
</p>
<p>
As you learn, we encourage you to share updates on Discord using the <b>!til</b> command. These updates will be published as part of your submission.
</p>
</div>
</div>
<div class="pa3 flex flex-column flex-row-ns g3 items-center bg--rich-gray">
<div class="flex-shrink-0 w4 flex justify-center items-center">
<div class="flex flex-shrink-0 svg-mask presentation-icon bg--theme-gradient-light" style="width: 5rem">
<img class="invisible" src="{{ static "learningjam2024/presentation.svg" }}" />
</div>
</div>
<div class="post-content">
<h3 class="f4">Mar 22-24: Share!</h3>
<p>
Share what you learned with the rest of the community. You can present the information in any form you like—whatever helps you communicate most effectively.
</p>
<p>
Your post doesn't have to be the authoritative resource on a subject. It doesn't even have to do much "teaching" at all. The point is just to share what you learned, what surprised you, what you found interesting, and where you want to go from here.
</p>
<p>
Your Handmade Network project is your final submission. Make sure the description gives adequate context, and either attach or link to your final presentation.
</p>
</div>
</div>
</div>
</div>
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="dib c--theme-gradient-light">Why?</h2>
<div class="post-content">
<p>
The Handmade Network's goal is to change the software industry by building back up from new foundations. But in order to do that, we need to understand those foundations.
</p>
<p>
Our other programming jams are great opportunities to try building new things. But what should those new things be? We want to give the community a chance to focus just on learning and research, to gather information and share it with others, to boost the entire community's knowledge on a topic.
</p>
<p>
We hope that the results of the <b class="c--theme-gradient-light">Learning Jam</b> inspire new ideas for the community to explore in the Visibility and Wheel Reinvention jams later in the year. There is so much bad software out in the world, and this is the first step toward reinventing it.
</p>
</div>
</div>
{{ if gt .DaysUntilStart 0 }}
{{ template "before-jam" . }}
{{ else if gt .DaysUntilEnd 0 }}
{{ template "during-jam" . }}
{{ else }}
{{ template "after-jam" . }}
{{ end }}
<div>
<div class="mv5 h3 fill-current">
<div class="mv5 h3 fill-current link--white">
<a href="{{ .Header.HMNHomepageUrl }}">{{ svg "hmn_circuit" }}</a>
</div>
</div>
</div>
{{ end }}
{{ define "before-jam" }}
{{ template "jam_2024_lj_guidelines.html" . }}
{{ end }}
{{ define "during-jam" }}
{{ if .Projects.Projects }}
{{ template "jam_2024_lj_description.html" . }}
{{ if .TimelineItems }}
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="c--theme-gradient-light">Recent updates</h2>
<p>
See what community members are learning about their topics. You can share your own updates via your <a href="{{ or .SubmittedProjectUrl .NewProjectUrl }}">project page</a> or using the <b>!til</b> command on Discord.
</p>
<div class="flex flex-column g2 mt3">
{{ template "jam_2024_lj_feeditems.html" .TimelineItems }}
<a href="{{ .JamFeedUrl }}" class="link--white tc pa1">
See all updates<div class="dib svgicon f8 ml1">{{ svg "chevron-right" }}</div>
</a>
</div>
</div>
{{ end }}
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="c--theme-gradient-light mb3">Projects</h2>
{{ template "jam_2024_lj_projects.html" .Projects }}
</div>
{{ else }}
{{ template "jam_2024_lj_guidelines.html" . }}
{{ end }}
{{ end }}
{{ define "after-jam" }}
{{ template "jam_2024_lj_description.html" . }}
{{ with .TwitchEmbedUrl }}
<div class="ph3 pv4 bb b--rich-gray">
<h2 class="dib c--theme-gradient-light">Recap show</h2>
<p>
Watch the livestream celebrating all the submissions:
</p>
<div class="mt3" style="aspect-ratio: 16 / 9;">
<iframe src="{{ . }}" allowfullscreen width="100%" height="100%" frameborder="0"></iframe>
</div>
</div>
{{ end }}
<div class="ph3 pv4 bb b--rich-gray">
<div class="flex justify-between items-baseline">
<h2 class="c--theme-gradient-light mb0">Submitted projects</h2>
<a href="{{ .JamFeedUrl }}" class="link--white tc">
See all updates<div class="dib svgicon f8 ml1">{{ svg "chevron-right" }}</div>
</a>
</div>
<div class="mt3">
{{ template "jam_2024_lj_projects.html" .Projects }}
</div>
</div>
{{ end }}

View File

@ -54,6 +54,8 @@
--spacing-6: 8rem;
--spacing-7: 16rem;
--border-radius-2: 0.25rem;
--link-color: transparent;
}
body {
@ -65,6 +67,14 @@
font-weight: 700;
}
.w2-5 {
width: 3rem;
}
.link--white {
--link-color: var(--white);
}
.post-content p {
/* stupid override, should be done by .post-content instead of .content */
margin: 0.6rem 0;
@ -90,6 +100,10 @@
background: var(--gray);
}
.b--charcoal {
border-color: var(--charcoal);
}
.b--rich-gray {
border-color: var(--rich-gray);
}
@ -101,13 +115,20 @@
color: transparent;
}
.c--theme-gradient-light {
a, .c--theme-gradient-light {
background: var(--theme-gradient-light);
background-clip: text;
-webkit-background-clip: text;
}
.c--theme-gradient-light {
color: transparent;
}
.c--gray {
color: var(--gray);
}
.btn--jam {
border: 1px solid var(--white);
border-radius: var(--border-radius-2);
@ -116,6 +137,10 @@
background-color: var(--bg-button);
}
.btn--jam.small {
padding: var(--spacing-1) var(--spacing-2);
}
.btn--jam:hover {
background-color: var(--bg-button-hover);
}
@ -169,15 +194,59 @@
padding-right: 0.6rem;
}
.user-avatar-header {
width: 1.8rem;
.user-avatar {
border-radius: 999px;
background-color: rgba(0, 0, 0, 0.4);
}
.user-avatar.header {
width: 1.8rem;
}
.jam-logo {
max-width: 18rem;
}
.jam-logo-small {
max-width: 8rem;
}
.jam-title {
/* align with the width of the logo */
font-size: 2.76rem;
font-weight: 700;
/* align with the text's actual bounding box */
line-height: 1.18;
margin-top: -0.18em;
margin-left: -0.03em;
margin-right: -0.03em;
}
.jam-title.small {
font-size: 2.25rem;
/* align with the text's actual bounding box */
line-height: 1.18;
margin-top: -0.18em;
margin-left: -0.03em;
margin-right: -0.03em;
}
/* not small */
@media screen and (min-width: 35em) {
.jam-logo {
max-width: 24rem;
}
.jam-title {
font-size: 3.7rem;
}
}
/* not small */
@media screen and (min-width: 35em) {
.flex-basis-40-ns {
flex-basis: 40%;
}
}
</style>
@ -186,7 +255,7 @@
<body class="bg--charcoal flex flex-column">
<div class="c-white bg--theme-gradient-dark">
<div class="bg-black-20 flex flex-row items-center">
<div class="bg-black-20 flex flex-row items-center link--white">
<a href="{{ .Header.HMNHomepageUrl }}" class="hmn-logo flex-shrink-0">
Handmade
</a>
@ -195,7 +264,7 @@
<a href="{{ .Header.ProjectIndexUrl }}">Projects</a>
<a href="{{ .Header.JamsUrl }}">Jams</a>
<a class="db" href="{{ or .Header.UserProfileUrl .LoginPageUrl }}">
<img class="user-avatar-header" src="{{ .UserAvatarUrl }}">
<img class="user-avatar header" src="{{ .UserAvatarUrl }}">
</a>
</div>
</div>

View File

@ -132,6 +132,8 @@
2023 Wheel Reinvention Jam
{{- else if eq . "visibility-2023" -}}
2023 Visibility Jam
{{- else if eq . "learning-2024" -}}
2024 Learning Jam
{{- else -}}
???
{{- end -}}

View File

@ -287,6 +287,12 @@ var HMNTemplateFuncs = template.FuncMap{
"trim": func(str template.HTML) template.HTML {
return template.HTML(strings.TrimSpace(string(str)))
},
"lastidx": func(idx int, l int) bool {
return idx == l-1
},
"isodd": func(num int) bool {
return num%2 == 1
},
// NOTE(asaf): Template specific functions:
"projectcarddata": func(project Project, classes string) ProjectCardData {

View File

@ -46,74 +46,35 @@ func JamsIndex(c *RequestContext) ResponseData {
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:title", Value: "Learning Jam"},
{Property: "og:site_name", Value: "Handmade Network"},
{Property: "og:type", Value: "website"},
{Property: "og:image", Value: hmnurl.BuildPublic("learningjam2024/2024LJOpenGraph.png", true)},
{Property: "og:description", Value: "A two-weekend jam where you dive deep into a topic, then share it with the rest of the community."},
{Property: "og:url", Value: hmnurl.BuildJamIndex2024_Learning()},
{Name: "twitter:card", Value: "summary_large_image"},
{Name: "twitter:image", Value: hmnurl.BuildPublic("learningjam2024/2024LJTwitterCard.png", true)},
baseData.OpenGraphItems = opengraphLJ2024
jamBaseData, err := getLJ2024BaseData(c)
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, err)
}
feedData, err := getLJ2024FeedData(c, 5)
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, err)
}
type JamPageData struct {
templates.BaseData
UserAvatarUrl string
DaysUntilStart, DaysUntilEnd int
TwitchEmbedUrl string
ProjectSubmissionUrl string
SubmittedProjectUrl string
JamFeedUrl string
}
JamBaseDataLJ2024
TwitchEmbedUrl 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())
}
}
Projects JamProjectDataLJ2024
TimelineItems []templates.TimelineItem
}
tmpl := JamPageData{
BaseData: baseData,
UserAvatarUrl: templates.UserAvatarDefaultUrl("dark"),
DaysUntilStart: daysUntilStart,
DaysUntilEnd: daysUntilEnd,
ProjectSubmissionUrl: hmnurl.BuildProjectNewJam(),
SubmittedProjectUrl: "",
JamFeedUrl: hmnurl.BuildJamFeed2024_Learning(),
TwitchEmbedUrl: twitchEmbedUrl,
}
BaseData: baseData,
JamBaseDataLJ2024: jamBaseData,
TwitchEmbedUrl: getTwitchEmbedUrl(c),
if c.CurrentUser != nil {
tmpl.UserAvatarUrl = templates.UserAvatarUrl(c.CurrentUser, "dark")
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)
tmpl.SubmittedProjectUrl = urlContext.BuildHomepage()
}
Projects: feedData.Projects,
TimelineItems: feedData.TimelineItems,
}
res.MustWriteTemplate("jam_2024_lj_index.html", tmpl, c.Perf)
@ -121,11 +82,144 @@ func JamIndex2024_Learning(c *RequestContext) ResponseData {
}
func JamFeed2024_Learning(c *RequestContext) ResponseData {
baseData := getBaseDataAutocrumb(c, hmndata.LJ2024.Name)
baseData.OpenGraphItems = opengraphLJ2024
jamBaseData, err := getLJ2024BaseData(c)
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, err)
}
feedData, err := getLJ2024FeedData(c, 0)
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, err)
}
type JamFeedData struct {
templates.BaseData
JamBaseDataLJ2024
Projects JamProjectDataLJ2024
TimelineItems []templates.TimelineItem
}
tmpl := JamFeedData{
BaseData: baseData,
JamBaseDataLJ2024: jamBaseData,
Projects: feedData.Projects,
TimelineItems: feedData.TimelineItems,
}
var res ResponseData
res.MustWriteTemplate("jam_2024_lj_feed.html", tmpl, c.Perf)
return res
}
func JamGuidelines2024_Learning(c *RequestContext) ResponseData {
baseData := getBaseDataAutocrumb(c, hmndata.LJ2024.Name)
baseData.OpenGraphItems = opengraphLJ2024
jamBaseData, err := getLJ2024BaseData(c)
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, err)
}
type JamGuidelinesData struct {
templates.BaseData
JamBaseDataLJ2024
}
tmpl := JamGuidelinesData{
BaseData: baseData,
JamBaseDataLJ2024: jamBaseData,
}
var res ResponseData
res.MustWriteTemplate("jam_2024_lj_guidelines_index.html", tmpl, c.Perf)
return res
}
var opengraphLJ2024 = []templates.OpenGraphItem{
{Property: "og:title", Value: "Learning Jam"},
{Property: "og:site_name", Value: "Handmade Network"},
{Property: "og:type", Value: "website"},
{Property: "og:image", Value: hmnurl.BuildPublic("learningjam2024/2024LJOpenGraph.png", true)},
{Property: "og:description", Value: "A two-weekend jam where you dive deep into a topic, then share it with the rest of the community."},
{Property: "og:url", Value: hmnurl.BuildJamIndex2024_Learning()},
{Name: "twitter:card", Value: "summary_large_image"},
{Name: "twitter:image", Value: hmnurl.BuildPublic("learningjam2024/2024LJTwitterCard.png", true)},
}
type JamBaseDataLJ2024 struct {
UserAvatarUrl string
DaysUntilStart, DaysUntilEnd int
JamUrl string
JamFeedUrl string
NewProjectUrl string
SubmittedProjectUrl string
GuidelinesUrl string
}
type JamProjectDataLJ2024 struct {
Projects []templates.Project
NewProjectUrl string
}
type JamFeedDataLJ2024 struct {
Projects JamProjectDataLJ2024
TimelineItems []templates.TimelineItem
projects []hmndata.ProjectAndStuff
}
func getLJ2024BaseData(c *RequestContext) (JamBaseDataLJ2024, error) {
daysUntilStart := daysUntil(hmndata.LJ2024.StartTime)
daysUntilEnd := daysUntil(hmndata.LJ2024.EndTime)
tmpl := JamBaseDataLJ2024{
UserAvatarUrl: templates.UserAvatarDefaultUrl("dark"),
DaysUntilStart: daysUntilStart,
DaysUntilEnd: daysUntilEnd,
JamUrl: hmnurl.BuildJamIndex2024_Learning(),
JamFeedUrl: hmnurl.BuildJamFeed2024_Learning(),
NewProjectUrl: hmnurl.BuildProjectNewJam(),
GuidelinesUrl: hmnurl.BuildJamGuidelines2024_Learning(),
}
if c.CurrentUser != nil {
tmpl.UserAvatarUrl = templates.UserAvatarUrl(c.CurrentUser, "dark")
projects, err := hmndata.FetchProjects(c, c.Conn, c.CurrentUser, hmndata.ProjectsQuery{
OwnerIDs: []int{c.CurrentUser.ID},
JamSlugs: []string{hmndata.LJ2024.Slug},
Limit: 1,
})
if err != nil {
return JamBaseDataLJ2024{}, oops.New(err, "failed to fetch jam projects for current user")
}
if len(projects) > 0 {
urlContext := hmndata.UrlContextForProject(&projects[0].Project)
tmpl.SubmittedProjectUrl = urlContext.BuildHomepage()
}
}
return tmpl, nil
}
// 0 for no limit on timeline items.
func getLJ2024FeedData(c *RequestContext, maxTimelineItems int) (JamFeedDataLJ2024, error) {
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"))
return JamFeedDataLJ2024{}, oops.New(err, "failed to fetch jam projects for current user")
}
projects := make([]templates.Project, 0, len(jamProjects))
for _, jp := range jamProjects {
urlContext := hmndata.UrlContextForProject(&jp.Project)
projectUrl := urlContext.BuildHomepage()
projects = append(projects, templates.ProjectAndStuffToTemplate(&jp, projectUrl, c.Theme))
}
projectIds := make([]int, 0, len(jamProjects))
@ -137,9 +231,10 @@ func JamFeed2024_Learning(c *RequestContext) ResponseData {
if len(projectIds) > 0 {
snippets, err := hmndata.FetchSnippets(c, c.Conn, c.CurrentUser, hmndata.SnippetQuery{
ProjectIDs: projectIds,
Limit: maxTimelineItems,
})
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets for jam showcase"))
return JamFeedDataLJ2024{}, oops.New(err, "failed to fetch snippets for jam showcase")
}
timelineItems = make([]templates.TimelineItem, 0, len(snippets))
@ -150,36 +245,37 @@ func JamFeed2024_Learning(c *RequestContext) ResponseData {
}
}
type JamFeedData struct {
templates.BaseData
DaysUntilStart, DaysUntilEnd int
return JamFeedDataLJ2024{
Projects: JamProjectDataLJ2024{
Projects: projects,
NewProjectUrl: hmnurl.BuildProjectNewJam(),
},
TimelineItems: timelineItems,
TimelineItems []templates.TimelineItem
projects: jamProjects,
}, nil
}
func getTwitchEmbedUrl(c *RequestContext) 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 {
c.Logger.Warn().Err(err).Msg("failed to query Twitch status for the HMN account")
} else 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())
}
}
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)
return res
return twitchEmbedUrl
}
func JamIndex2023(c *RequestContext) ResponseData {

View File

@ -73,6 +73,7 @@ func NewWebsiteRoutes(conn *pgxpool.Pool) http.Handler {
hmnOnly.GET(hmnurl.RegexJamFeed2023, JamFeed2023)
hmnOnly.GET(hmnurl.RegexJamIndex2024_Learning, JamIndex2024_Learning)
hmnOnly.GET(hmnurl.RegexJamFeed2024_Learning, JamFeed2024_Learning)
hmnOnly.GET(hmnurl.RegexJamGuidelines2024_Learning, JamGuidelines2024_Learning)
hmnOnly.GET(hmnurl.RegexTimeMachine, TimeMachine)
hmnOnly.GET(hmnurl.RegexTimeMachineSubmissions, TimeMachineSubmissions)