Visualization Jam 2023 template
This commit is contained in:
parent
1825e93b04
commit
526a588a19
|
@ -0,0 +1,22 @@
|
|||
<svg width="461" height="280" viewBox="0 0 461 280" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M22 0C9.84974 0 0 9.84974 0 22V258C0 270.15 9.84973 280 22 280H439C451.15 280 461 270.15 461 258V22C461 9.84974 451.15 0 439 0H22ZM36 14C23.8497 14 14 23.8497 14 36V236H447V36C447 23.8497 437.15 14 425 14H36Z" fill="white"/>
|
||||
<circle cx="56.5" cy="200.5" r="22.5" fill="white"/>
|
||||
<circle cx="101.5" cy="147.5" r="22.5" fill="white"/>
|
||||
<circle cx="183.5" cy="188.5" r="22.5" fill="white"/>
|
||||
<circle cx="183.5" cy="97.5" r="22.5" fill="white"/>
|
||||
<circle cx="83.5" cy="52.5" r="22.5" fill="white"/>
|
||||
<line x1="83.9476" y1="51.4415" x2="101.948" y2="146.442" stroke="white" stroke-width="6"/>
|
||||
<line x1="53.7131" y1="198.058" x2="98.7131" y2="145.058" stroke="white" stroke-width="6"/>
|
||||
<line x1="183.59" y1="99.544" x2="103.59" y2="149.544" stroke="white" stroke-width="6"/>
|
||||
<line x1="181.645" y1="190.677" x2="100.645" y2="149.677" stroke="white" stroke-width="6"/>
|
||||
<rect x="421" y="36" width="21" height="54" rx="5" transform="rotate(90 421 36)" fill="white"/>
|
||||
<rect x="361" y="65" width="21" height="54" rx="5" transform="rotate(90 361 65)" fill="white"/>
|
||||
<rect x="421" y="65" width="21" height="99" rx="5" transform="rotate(90 421 65)" fill="white"/>
|
||||
<rect x="361" y="94" width="21" height="99" rx="5" transform="rotate(90 361 94)" fill="white"/>
|
||||
<rect x="421" y="94" width="21" height="69" rx="5" transform="rotate(90 421 94)" fill="white"/>
|
||||
<rect x="361" y="123" width="21" height="69" rx="5" transform="rotate(90 361 123)" fill="white"/>
|
||||
<rect x="421" y="123" width="21" height="120" rx="5" transform="rotate(90 421 123)" fill="white"/>
|
||||
<rect x="361" y="152" width="21" height="120" rx="5" transform="rotate(90 361 152)" fill="white"/>
|
||||
<rect x="421" y="152" width="21" height="40" rx="5" transform="rotate(90 421 152)" fill="white"/>
|
||||
<rect x="361" y="181" width="21" height="40" rx="5" transform="rotate(90 361 181)" fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -39,6 +39,15 @@ var WRJ2022 = Jam{
|
|||
Slug: "WRJ2022",
|
||||
}
|
||||
|
||||
var VJ2023 = Jam{
|
||||
Event: Event{
|
||||
StartTime: time.Date(2023, 4, 14, 0, 0, 0, 0, utils.Must1(time.LoadLocation("America/Los_Angeles"))),
|
||||
EndTime: time.Date(2023, 4, 16, 8, 0, 0, 0, utils.Must1(time.LoadLocation("America/Los_Angeles"))),
|
||||
},
|
||||
Name: "Visualization Jam 2023",
|
||||
Slug: "VJ2023",
|
||||
}
|
||||
|
||||
var HMS2022 = Event{
|
||||
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"))),
|
||||
|
|
|
@ -70,6 +70,13 @@ func BuildJamIndex2022() string {
|
|||
return Url("/jam/2022", nil)
|
||||
}
|
||||
|
||||
var RegexVisualizationJamIndex2023 = regexp.MustCompile("^/visualization-jam/2023$")
|
||||
|
||||
func BuildVisualizationJamIndex2023() string {
|
||||
defer CatchPanic()
|
||||
return Url("/visualization-jam/2023", nil)
|
||||
}
|
||||
|
||||
var RegexJamFeed2022 = regexp.MustCompile("^/jam/2022/feed$")
|
||||
|
||||
func BuildJamFeed2022() string {
|
||||
|
|
|
@ -0,0 +1,356 @@
|
|||
{{/*
|
||||
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 "wheeljam2022/favicon-16x16.png" }}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ static "wheeljam2022/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="#346ba6">
|
||||
|
||||
<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 rel="stylesheet" type="text/css" href="{{ static "style.css" }}">
|
||||
|
||||
<style>
|
||||
/* Copy-paste from project.css yay */
|
||||
{{ $c := hex2color "D10074" }}
|
||||
|
||||
{{ $themeDim := eq .Theme "dark" | ternary (lightness 0.35 $c) (lightness 0.75 $c) | color2css }}
|
||||
{{ $themeDimmer := eq .Theme "dark" | ternary (lightness 0.3 $c) (lightness 0.8 $c) | color2css }}
|
||||
{{ $themeDimmest := eq .Theme "dark" | ternary (lightness 0.2 $c) (lightness 0.85 $c) | color2css }}
|
||||
|
||||
{{ $themeDark := eq .Theme "dark" | ternary (lightness 0.30 $c) (lightness 0.35 $c) | color2css }}
|
||||
|
||||
{{ $linkColor := eq .Theme "dark" | ternary (lightness 0.55 $c) (lightness 0.35 $c) | color2css }}
|
||||
{{ $linkHoverColor := eq .Theme "dark" | ternary (lightness 0.65 $c) (lightness 0.45 $c) | color2css }}
|
||||
|
||||
:root {
|
||||
--content-background: #f8f8f8;
|
||||
--card-background: rgba(255, 255, 255, 0.1);
|
||||
--card-background-hover: rgba(255, 255, 255, 0.16);
|
||||
|
||||
--theme-color: {{ $c | color2css }};
|
||||
--theme-color-dim: {{ $themeDim }};
|
||||
--theme-color-dimmer: {{ $themeDimmer }};
|
||||
--theme-color-dimmest: {{ $themeDimmest }};
|
||||
|
||||
--timeline-content-background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient( #D10074, #6E2C6B );
|
||||
// background: linear-gradient( #34e89e, #0f3443);
|
||||
}
|
||||
|
||||
.user-options,
|
||||
header form,
|
||||
header .menu-bar .wiki,
|
||||
header .menu-bar .library
|
||||
{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
header {
|
||||
border-bottom-color: white;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.hmn-logo {
|
||||
background-color: rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
header a, footer a {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
header .submenu {
|
||||
background-color: #D10074;
|
||||
}
|
||||
|
||||
#top-container {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
#logo {
|
||||
width: 16rem;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
font-family: 'MohaveHMN', sans-serif;
|
||||
margin-bottom: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#title {
|
||||
color: white;
|
||||
font-size: 2.4rem;
|
||||
line-height: 0.8;
|
||||
margin-top: 2rem;
|
||||
letter-spacing: -0.06rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#dates {
|
||||
font-variant: small-caps;
|
||||
font-size: 1.6rem;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
#tagline {
|
||||
font-size: 1rem;
|
||||
margin-top: 1rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
#top-container a {
|
||||
color: white !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.actions a {
|
||||
text-decoration: none !important;
|
||||
line-height: 1.4;
|
||||
font-weight: 500;
|
||||
|
||||
transition: background-color 50ms ease-in-out;
|
||||
background-color:rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.actions a:hover {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.actions a:active {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
.section {
|
||||
font-size: 1rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
font-variant: small-caps;
|
||||
font-size: 2.2rem;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.section h3 {
|
||||
font-variant: small-caps;
|
||||
font-size: 2rem;
|
||||
line-height: 0.8;
|
||||
margin-top: 1.4rem;
|
||||
}
|
||||
|
||||
.section p {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.section a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.emphasized {
|
||||
padding-left: 1rem;
|
||||
border-left: 0.3rem solid white;
|
||||
}
|
||||
|
||||
.flex-fair {
|
||||
flex-basis: 1px;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-top: 0.6rem;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.section li p {
|
||||
margin-top: 0.6rem;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
footer {
|
||||
border-top: 2px solid white;
|
||||
margin-top: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
footer h2 {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.showcase-item {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.carousel-thinger {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 6rem;
|
||||
height: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.1); /* bg-white-10 */
|
||||
border-radius: 0.5rem; /* br3 */
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.carousel-thinger.prev {
|
||||
left: -7rem;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
background: linear-gradient(to left, rgba(255, 255, 255, 0.1), transparent);
|
||||
}
|
||||
|
||||
.carousel-thinger.next {
|
||||
right: -7rem;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
background: linear-gradient(to right, rgba(255, 255, 255, 0.1), transparent);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 30em) {
|
||||
/* not small styles */
|
||||
|
||||
#top-container {
|
||||
margin: 5.4rem 0;
|
||||
}
|
||||
|
||||
#logo {
|
||||
width: 31rem;
|
||||
}
|
||||
|
||||
#title {
|
||||
font-size: 5.2rem;
|
||||
margin-top: 4rem;
|
||||
}
|
||||
|
||||
#dates {
|
||||
font-size: 2.8rem;
|
||||
}
|
||||
|
||||
#tagline {
|
||||
font-size: 1.2rem;
|
||||
margin-top: 1.2rem;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: 2.2rem;
|
||||
}
|
||||
|
||||
.actions a {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
font-size: 3.4rem;
|
||||
}
|
||||
|
||||
.section h3 {
|
||||
font-size: 2.4rem;
|
||||
margin-top: 1.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3.mt0 {
|
||||
margin-top: 0; /* ugh seriously */
|
||||
}
|
||||
|
||||
.back-to-normal * {
|
||||
font-family: "Fira Sans", sans-serif;
|
||||
}
|
||||
|
||||
.back-to-normal h1,
|
||||
.back-to-normal h2,
|
||||
.back-to-normal h3,
|
||||
.back-to-normal h4,
|
||||
.back-to-normal h5
|
||||
{
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.25em;
|
||||
}
|
||||
|
||||
.back-to-normal a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.snippet-project {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
/* More copy-paste from project.css */
|
||||
.bg-theme {
|
||||
background-color: {{ $c | color2css }};
|
||||
background-color: var(--theme-color);
|
||||
}
|
||||
|
||||
.bg-theme-dim {
|
||||
background-color: {{ $themeDim }};
|
||||
background-color: var(--theme-color-dim);
|
||||
}
|
||||
|
||||
.bg-theme-dimmer {
|
||||
background-color: {{ $themeDimmer }};
|
||||
background-color: var(--theme-color-dimmer);
|
||||
}
|
||||
|
||||
.bg-theme-dimmest {
|
||||
background-color: {{ $themeDimmest }};
|
||||
background-color: var(--theme-color-dimmest);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="{{ static "js/carousel.js" }}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="left white">
|
||||
<div class="mt4-ns mw8 margin-center ph3-m ph4-l">
|
||||
{{ template "header.html" . }}
|
||||
</div>
|
||||
|
||||
{{ block "content" . }}{{ end }}
|
||||
|
||||
<div class="mw8 margin-center ph3-m ph4-l">
|
||||
{{ template "footer.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,446 @@
|
|||
{{ template "visualization_jam_2023_base.html" . }} {{ define "content" }} {{
|
||||
$discordInviteURL := "https://discord.gg/hmn" }}
|
||||
|
||||
<style>
|
||||
.projects {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 30em) {
|
||||
/* not small styles */
|
||||
|
||||
.projects {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="top-container" class="flex flex-column items-center ph3">
|
||||
<img id="logo" src="{{ static "visualjam2023/logo.svg" }}">
|
||||
<h1 id="title">Visualization Jam</h1>
|
||||
<h2 id="dates">April 14 - 16, 2O23</h2>
|
||||
<div id="tagline" class="center">
|
||||
A one-week jam to change the status quo. {{ if gt .DaysUntilEnd 0 }} {{ if
|
||||
eq .DaysUntilStart 0 }}
|
||||
<b>Happening now.</b>
|
||||
{{ else if eq .DaysUntilStart 1 }}
|
||||
<b>Starting tomorrow.</b>
|
||||
{{ else }}
|
||||
<b>In {{ .DaysUntilStart }} days.</b>
|
||||
{{ end }} {{ end }}
|
||||
</div>
|
||||
<div class="actions flex justify-center">
|
||||
{{ if gt .DaysUntilStart 0 }}
|
||||
<a
|
||||
class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns"
|
||||
target="_blank"
|
||||
href="https://github.com/HandmadeNetwork/wishlist/discussions"
|
||||
>Find a project</a
|
||||
>
|
||||
{{ else if gt .DaysUntilEnd 0 }} {{ if .SubmittedProjectUrl }}
|
||||
<a
|
||||
class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns"
|
||||
target="_blank"
|
||||
href="{{ .SubmittedProjectUrl }}"
|
||||
>Share your progress</a
|
||||
>
|
||||
{{ else }}
|
||||
<a
|
||||
class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3"
|
||||
target="_blank"
|
||||
href="{{ .ProjectSubmissionUrl }}"
|
||||
>Create your project</a
|
||||
>
|
||||
{{ end }} {{ else }}
|
||||
<a
|
||||
class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3"
|
||||
href="{{ .ShowcaseFeedUrl }}"
|
||||
>See the results</a
|
||||
>
|
||||
{{ end }}
|
||||
<a
|
||||
class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3"
|
||||
target="_blank"
|
||||
href="{{ $discordInviteURL }}"
|
||||
>Join the Discord</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section mw8 margin-center ph3 ph4-l mv4">
|
||||
<h1>
|
||||
TODO: Needs copy -- guessing we'll use some of the images that Ben has
|
||||
marked as TODO TODO TODO in the copy doc.
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{{ if eq .DaysUntilEnd 0 }}
|
||||
<div class="section bg-black-20 pv4 overflow-hidden">
|
||||
<div class="mw8 margin-center ph3 ph4-l">
|
||||
<h2>Submitted projects</h2>
|
||||
<div class="mt3 projects g3 back-to-normal">
|
||||
{{ range .JamProjects }} {{ template "project_card.html" projectcarddata .
|
||||
"" }} {{ end }}
|
||||
</div>
|
||||
<div class="actions flex justify-center">
|
||||
<a
|
||||
class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3"
|
||||
href="{{ .ShowcaseFeedUrl }}"
|
||||
>See all updates</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ else if and (eq .DaysUntilStart 0) (not (eq .ShowcaseJson "[]")) }}
|
||||
<div id="showcase-outer-container" class="bg-black-20 pt4 pb3 pb4-ns">
|
||||
<div class="section mw8 margin-center ph3 ph4-l">
|
||||
{{ if gt .DaysUntilEnd 0 }}
|
||||
<h2>Recent updates</h2>
|
||||
<p>
|
||||
These screenshots and videos were shared by jam participants in
|
||||
<b>#project-showcase</b> on our
|
||||
<a href="{{ $discordInviteURL }}" target="_blank">Discord</a>. Join us and
|
||||
share what you're working on!
|
||||
<a class="b" href="{{ .ShowcaseFeedUrl }}">See all ➜</a>
|
||||
</p>
|
||||
{{ else }}
|
||||
<h2>Community showcase</h2>
|
||||
<p>
|
||||
These screenshots and videos were shared by jam participants in
|
||||
<b>#project-showcase</b> on our
|
||||
<a href="https://discord.gg/hmn" target="_blank">Discord</a> during the
|
||||
jam. Join us and chat about your favorites!
|
||||
</p>
|
||||
{{ end }}
|
||||
<div id="showcase-container" class="mw8 center-layout mh2 mh0-ns"></div>
|
||||
<div class="actions flex justify-center">
|
||||
<a
|
||||
class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3"
|
||||
target="_blank"
|
||||
href="{{ .ShowcaseFeedUrl }}"
|
||||
>See all</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ template "showcase_templates.html" }}
|
||||
<!-- Copy-pasted and mangled from showcase.html -->
|
||||
<script>
|
||||
const ROW_HEIGHT = 300;
|
||||
const ITEM_SPACING = 4;
|
||||
|
||||
const showcaseItems = JSON.parse("{{ .ShowcaseJson }}");
|
||||
const addThumbnailFuncs = new Array(showcaseItems.length);
|
||||
|
||||
const showcaseOuterContainer = document.querySelector(
|
||||
"#showcase-outer-container"
|
||||
);
|
||||
let showcaseContainer = document.querySelector("#showcase-container");
|
||||
|
||||
// showcaseOuterContainer.classList.toggle('dn', showcaseItems.length === 0);
|
||||
|
||||
const itemElements = []; // array of arrays
|
||||
for (let i = 0; i < showcaseItems.length; i++) {
|
||||
const item = showcaseItems[i];
|
||||
|
||||
const [itemEl, addThumbnail] = makeShowcaseItem(item);
|
||||
itemEl.container.setAttribute("data-index", i);
|
||||
itemEl.container.setAttribute("data-date", item.date);
|
||||
|
||||
addThumbnailFuncs[i] = addThumbnail;
|
||||
|
||||
itemElements.push(itemEl.container);
|
||||
}
|
||||
|
||||
function layout() {
|
||||
const width = showcaseContainer.getBoundingClientRect().width;
|
||||
showcaseContainer = emptyElement(showcaseContainer);
|
||||
|
||||
function addRow(itemEls, rowWidth, container) {
|
||||
const totalSpacing = ITEM_SPACING * (itemEls.length - 1);
|
||||
const scaleFactor = width / Math.max(rowWidth, width);
|
||||
|
||||
const row = document.createElement("div");
|
||||
row.classList.add("flex");
|
||||
row.classList.toggle("justify-between", rowWidth >= width);
|
||||
row.style.marginBottom = `${ITEM_SPACING}px`;
|
||||
|
||||
for (const itemEl of itemEls) {
|
||||
const index = parseInt(itemEl.getAttribute("data-index"), 10);
|
||||
const item = showcaseItems[index];
|
||||
|
||||
const aspect = item.width / item.height;
|
||||
const baseWidth = aspect * ROW_HEIGHT * scaleFactor;
|
||||
const actualWidth = baseWidth - totalSpacing / itemEls.length;
|
||||
|
||||
itemEl.style.width = `${actualWidth}px`;
|
||||
itemEl.style.height = `${scaleFactor * ROW_HEIGHT}px`;
|
||||
itemEl.style.marginRight = `${ITEM_SPACING}px`;
|
||||
|
||||
row.appendChild(itemEl);
|
||||
}
|
||||
|
||||
container.appendChild(row);
|
||||
}
|
||||
|
||||
let rowItemEls = [];
|
||||
let rowWidth = 0;
|
||||
let numRows = 0;
|
||||
|
||||
for (const itemEl of itemElements) {
|
||||
const index = parseInt(itemEl.getAttribute("data-index"), 10);
|
||||
const item = showcaseItems[index];
|
||||
|
||||
const aspect = item.width / item.height;
|
||||
rowWidth += aspect * ROW_HEIGHT;
|
||||
|
||||
rowItemEls.push(itemEl);
|
||||
|
||||
if (rowWidth > width) {
|
||||
addRow(rowItemEls, rowWidth, showcaseContainer);
|
||||
numRows += 1;
|
||||
if (numRows == 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
rowItemEls = [];
|
||||
rowWidth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
addRow(rowItemEls, rowWidth, showcaseContainer);
|
||||
}
|
||||
|
||||
function loadImages() {
|
||||
const items = showcaseContainer.querySelectorAll(".showcase-item");
|
||||
for (const item of items) {
|
||||
const i = parseInt(item.getAttribute("data-index"), 10);
|
||||
addThumbnailFuncs[i]();
|
||||
}
|
||||
}
|
||||
|
||||
layout();
|
||||
layout(); // scrollbars are fun!!
|
||||
|
||||
loadImages();
|
||||
|
||||
window.addEventListener("resize", () => {
|
||||
layout();
|
||||
});
|
||||
</script>
|
||||
{{ end }}
|
||||
|
||||
<div class="pt4 pb3 pb4-ns">
|
||||
<div class="section mw8 margin-center ph3 ph4-l">
|
||||
<h2>How to participate</h2>
|
||||
<p>
|
||||
The jam takes place from Friday, April 14 through Sunday, April 16. Here's
|
||||
how you can participate:
|
||||
</p>
|
||||
|
||||
<div class="{{ if gt .DaysUntilStart 0 }}emphasized{{ end }}">
|
||||
<h3>Pick a project and form a team.</h3>
|
||||
<p>
|
||||
Pick something to visualize! Maybe it’s some weird data structure you
|
||||
want to debug. Maybe it’s a map of your codebase. Maybe it’s your sleep
|
||||
schedule. Whatever it is, make a Handmade Network project for it
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="{{ if and (eq .DaysUntilStart 0) (gt .DaysUntilEnd 1) }}emphasized{{ end }}"
|
||||
>
|
||||
<h3>Jam.</h3>
|
||||
<p>
|
||||
{{ if and (eq .DaysUntilStart 0) (not .SubmittedProjectUrl) }}
|
||||
<a href="{{ .ProjectSubmissionUrl }}" target="_blank"
|
||||
><b>Create a Handmade Network project</b></a
|
||||
>
|
||||
{{ else }} After the jam starts, create a Handmade Network project {{
|
||||
end }} to track your work. Then, build your program! Share your work in
|
||||
progress in #project-showcase on Discord, or directly from your project
|
||||
page. Chat with other jammers in #jam too.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="{{ if eq .DaysUntilEnd 1 }}emphasized{{ end }}">
|
||||
<h3>Submit your work!</h3>
|
||||
<p>
|
||||
<b>Your Handmade Network project is your submission.</b> Fill out the
|
||||
project description, making sure to explain the goals of the project and
|
||||
how it improves on what came before. Also consider posting an update
|
||||
with video of your program in action!
|
||||
</p>
|
||||
{{ if and (eq .DaysUntilStart 0) (gt .DaysUntilEnd 0) }}
|
||||
<p>
|
||||
Submissions close
|
||||
<b><span class="countdown" data-deadline="{{ .EndTimeUnix }}"></span></b
|
||||
>.
|
||||
</p>
|
||||
{{ else if eq .DaysUntilEnd 0 }}
|
||||
<p>
|
||||
<b>Submissions are now closed.</b>
|
||||
</p>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-black-20 pt4 pb3 pb4-ns">
|
||||
<div class="section mw8 margin-center ph3 ph4-l">
|
||||
<h2>Rules</h2>
|
||||
<ul>
|
||||
<li>
|
||||
Any tech is allowed, but we encourage you to use only use what you
|
||||
really need. If you want some lightweight templates to get you started,
|
||||
check out our
|
||||
<a
|
||||
href="https://github.com/HandmadeNetwork/jam_templates"
|
||||
target="_blank"
|
||||
>app templates</a
|
||||
>.
|
||||
</li>
|
||||
<li>
|
||||
You may work solo or in a team. (But we encourage you to work with a
|
||||
team!)
|
||||
</li>
|
||||
<li>Submit your work by the end of the day on April 16.</li>
|
||||
</ul>
|
||||
<p>
|
||||
There are no explicit winners, but we will be selecting a few of our
|
||||
favorite projects to highlight in a recap stream following the jam.
|
||||
</p>
|
||||
|
||||
<h3>Submission rules</h3>
|
||||
<p>
|
||||
<b
|
||||
>{{ with .SubmittedProjectUrl }}
|
||||
<a href="{{ . }}" target="_blank">Your Handmade Network project</a>
|
||||
{{ else }} Your Handmade Network project {{ end }} is your
|
||||
submission.</b
|
||||
>
|
||||
We will be looking at the project's description and any extra updates you
|
||||
share toward the end of the jam.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Explain the project's goals and how it improves on what came before.
|
||||
Also share some closing thoughts - did it turn out how you hoped? What
|
||||
did you learn? If you continue the project, what will you do
|
||||
differently?
|
||||
</li>
|
||||
<li>
|
||||
<b
|
||||
>Your description must contain multiple screenshots of your software
|
||||
in action.</b
|
||||
>
|
||||
You should ideally also share a project update with a demo video. We
|
||||
recommend Mārtiņš Možeiko's
|
||||
<a href="https://wcap.handmade.network/" target="_blank">wcap</a> for
|
||||
recording desktop video on Windows. On Mac, just press ⌘-Option-5 and
|
||||
record a video, or use QuickTime.
|
||||
</li>
|
||||
<li>
|
||||
If at all possible, please provide a way for people to either build or
|
||||
download your program.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pt4">
|
||||
<div class="flex-ns flex-row-ns mw8 margin-center ph3 ph4-l">
|
||||
<div class="section flex-fair mb4 mb0-ns">
|
||||
<h2>Make it by hand.</h2>
|
||||
<p>
|
||||
The Handmade ethos and Handmade community are software development
|
||||
superpowers. Don't be afraid to question your foundations and rebuild
|
||||
what needs rebuilding. The community is here to help you take on those
|
||||
challenges and do what others might consider impossible.
|
||||
</p>
|
||||
<p>
|
||||
Of course, this is a jam, so focus on what matters to your project.
|
||||
There are many excellent libraries in the community that can save you
|
||||
time and help you focus on your core ideas. Don't be afraid to use them.
|
||||
But don't be afraid to do your own thing if they're holding you back.
|
||||
</p>
|
||||
</div>
|
||||
<div class="section flex-fair ml4-m ml5-l">
|
||||
<h2>Don't just rebuild. Reinvent.</h2>
|
||||
<p>
|
||||
This is a chance to build something <em>truly new</em>. Learn from
|
||||
previous work, but don't settle for “the same, but better”. It would be
|
||||
a huge shame to spend a week building nothing more than a clone of the
|
||||
same broken software we use today.
|
||||
</p>
|
||||
<p>
|
||||
This is where working with a team can really help. Bounce ideas off each
|
||||
other, do some research, and brainstorm before the jam starts. The
|
||||
software you end up building might be pretty different from your
|
||||
original ideas.
|
||||
</p>
|
||||
<p>In the end, this is a jam. Get weird and try something different.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const carouselContainer = document.querySelector(".carousel-container");
|
||||
if (carouselContainer) {
|
||||
const { next, prev } = initCarousel(carouselContainer, {
|
||||
onChange() {
|
||||
if (carouselContainer.getBoundingClientRect().top < 0) {
|
||||
carouselContainer.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
document
|
||||
.querySelector(".carousel-thinger.next")
|
||||
.addEventListener("click", () => {
|
||||
next();
|
||||
});
|
||||
document
|
||||
.querySelector(".carousel-thinger.prev")
|
||||
.addEventListener("click", () => {
|
||||
prev();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
for (const countdown of document.querySelectorAll(".countdown")) {
|
||||
const deadline = countdown.getAttribute("data-deadline");
|
||||
const deadlineDate = new Date(parseInt(deadline, 10) * 1000);
|
||||
|
||||
function updateCountdown() {
|
||||
const remainingMs = deadlineDate.getTime() - new Date().getTime();
|
||||
const remainingMinutes = remainingMs / 1000 / 60;
|
||||
const remainingHours = remainingMinutes / 60;
|
||||
const remainingDays = remainingHours / 24; // no daylight savings transitions during the jam mmkay
|
||||
|
||||
let str = "imminently";
|
||||
if (remainingMinutes < 60) {
|
||||
str = `in ${Math.ceil(remainingMinutes)} ${
|
||||
remainingMinutes === 1 ? "minute" : "minutes"
|
||||
}`;
|
||||
} else if (remainingHours < 24) {
|
||||
str = `in ${Math.ceil(remainingHours)} ${
|
||||
remainingHours === 1 ? "hour" : "hours"
|
||||
}`;
|
||||
} else {
|
||||
str = `in ${Math.ceil(remainingDays)} ${
|
||||
remainingDays === 1 ? "day" : "days"
|
||||
}`;
|
||||
}
|
||||
|
||||
countdown.innerText = str;
|
||||
}
|
||||
|
||||
updateCountdown();
|
||||
setInterval(updateCountdown, 1000 * 60);
|
||||
}
|
||||
</script>
|
||||
{{ end }}
|
|
@ -59,6 +59,7 @@ func NewWebsiteRoutes(conn *pgxpool.Pool) http.Handler {
|
|||
hmnOnly.GET(hmnurl.RegexJamIndex2021, JamIndex2021)
|
||||
hmnOnly.GET(hmnurl.RegexJamIndex2022, JamIndex2022)
|
||||
hmnOnly.GET(hmnurl.RegexJamFeed2022, JamFeed2022)
|
||||
hmnOnly.GET(hmnurl.RegexVisualizationJamIndex2023, VisualizationIndex2023)
|
||||
|
||||
hmnOnly.GET(hmnurl.RegexStaffRolesIndex, StaffRolesIndex)
|
||||
hmnOnly.GET(hmnurl.RegexStaffRole, StaffRole)
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
package website
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
// "time"
|
||||
|
||||
"git.handmade.network/hmn/hmn/src/hmndata"
|
||||
"git.handmade.network/hmn/hmn/src/hmnurl"
|
||||
"git.handmade.network/hmn/hmn/src/oops"
|
||||
"git.handmade.network/hmn/hmn/src/templates"
|
||||
// "git.handmade.network/hmn/hmn/src/utils"
|
||||
)
|
||||
|
||||
func VisualizationIndex2023(c *RequestContext) ResponseData {
|
||||
var res ResponseData
|
||||
|
||||
daysUntilStart := daysUntil(hmndata.VJ2023.StartTime)
|
||||
daysUntilEnd := daysUntil(hmndata.VJ2023.EndTime)
|
||||
|
||||
baseData := getBaseDataAutocrumb(c, hmndata.VJ2023.Name)
|
||||
baseData.OpenGraphItems = []templates.OpenGraphItem{
|
||||
{Property: "og:site_name", Value: "Handmade.Network"},
|
||||
{Property: "og:type", Value: "website"},
|
||||
// TODO:
|
||||
{Property: "og:image", Value: hmnurl.BuildPublic("wheeljam2022/opengraph.png", true)},
|
||||
{Property: "og:description", Value: "See things in a new way. April 14 - 16."},
|
||||
{Property: "og:url", Value: hmnurl.BuildJamIndex()},
|
||||
}
|
||||
|
||||
type JamPageData struct {
|
||||
templates.BaseData
|
||||
DaysUntilStart, DaysUntilEnd int
|
||||
StartTimeUnix, EndTimeUnix int64
|
||||
|
||||
SubmittedProjectUrl string
|
||||
ProjectSubmissionUrl string
|
||||
ShowcaseFeedUrl string
|
||||
ShowcaseJson string
|
||||
|
||||
JamProjects []templates.Project
|
||||
}
|
||||
|
||||
var showcaseItems []templates.TimelineItem
|
||||
submittedProjectUrl := ""
|
||||
|
||||
if c.CurrentUser != nil {
|
||||
projects, err := hmndata.FetchProjects(c, c.Conn, c.CurrentUser, hmndata.ProjectsQuery{
|
||||
OwnerIDs: []int{c.CurrentUser.ID},
|
||||
JamSlugs: []string{hmndata.VJ2023.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()
|
||||
}
|
||||
}
|
||||
|
||||
jamProjects, err := hmndata.FetchProjects(c, c.Conn, c.CurrentUser, hmndata.ProjectsQuery{
|
||||
JamSlugs: []string{hmndata.VJ2023.Slug},
|
||||
})
|
||||
if err != nil {
|
||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch jam projects for current user"))
|
||||
}
|
||||
|
||||
pageProjects := make([]templates.Project, 0, len(jamProjects))
|
||||
for _, p := range jamProjects {
|
||||
pageProjects = append(pageProjects, templates.ProjectAndStuffToTemplate(&p, hmndata.UrlContextForProject(&p.Project).BuildHomepage(), c.Theme))
|
||||
}
|
||||
|
||||
projectIds := make([]int, 0, len(jamProjects))
|
||||
for _, jp := range jamProjects {
|
||||
projectIds = append(projectIds, jp.Project.ID)
|
||||
}
|
||||
|
||||
if len(projectIds) > 0 {
|
||||
snippets, err := hmndata.FetchSnippets(c, c.Conn, c.CurrentUser, hmndata.SnippetQuery{
|
||||
ProjectIDs: projectIds,
|
||||
Limit: 12,
|
||||
})
|
||||
if err != nil {
|
||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets for jam showcase"))
|
||||
}
|
||||
showcaseItems = 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)
|
||||
if timelineItem.CanShowcase {
|
||||
showcaseItems = append(showcaseItems, timelineItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showcaseJson := templates.TimelineItemsToJSON(showcaseItems)
|
||||
|
||||
res.MustWriteTemplate("visualization_jam_2023.html", JamPageData{
|
||||
BaseData: baseData,
|
||||
DaysUntilStart: daysUntilStart,
|
||||
DaysUntilEnd: daysUntilEnd,
|
||||
StartTimeUnix: hmndata.VJ2023.StartTime.Unix(),
|
||||
EndTimeUnix: hmndata.VJ2023.EndTime.Unix(),
|
||||
ProjectSubmissionUrl: hmnurl.BuildProjectNewJam(),
|
||||
SubmittedProjectUrl: submittedProjectUrl,
|
||||
ShowcaseFeedUrl: hmnurl.BuildJamFeed2022(),
|
||||
ShowcaseJson: showcaseJson,
|
||||
JamProjects: pageProjects,
|
||||
}, c.Perf)
|
||||
return res
|
||||
}
|
||||
|
||||
// func daysUntil(t time.Time) int {
|
||||
// d := t.Sub(time.Now())
|
||||
// if d < 0 {
|
||||
// d = 0
|
||||
// }
|
||||
// return int(utils.DurationRoundUp(d, 24*time.Hour) / (24 * time.Hour))
|
||||
// }
|
Loading…
Reference in New Issue