Merge remote-tracking branch 'origin/feature/2023_frontend_updates'

This commit is contained in:
Ben Visness 2023-03-07 11:40:26 -06:00
commit bb38d0b759
17 changed files with 1146 additions and 95 deletions

6
.gitignore vendored
View File

@ -16,3 +16,9 @@ local/backups
/tmp
*.exe
.DS_Store
# vim session saves
Session.vim
# tags files
tags

View File

@ -540,7 +540,7 @@ input[type="url"],
height: 100%;
z-index: 100; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.aspect-ratio-ns {
height: 0;
position: relative; }
@ -576,7 +576,7 @@ input[type="url"],
height: 100%;
z-index: 100; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.aspect-ratio-m {
height: 0;
position: relative; }
@ -679,13 +679,13 @@ img, video {
.contain {
background-size: contain !important; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.cover-ns {
background-size: cover !important; }
.contain-ns {
background-size: contain !important; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.cover-m {
background-size: cover !important; }
.contain-m {
@ -737,7 +737,7 @@ img, video {
background-repeat: no-repeat;
background-position: center left; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.bg-center-ns {
background-repeat: no-repeat;
background-position: center center; }
@ -754,7 +754,7 @@ img, video {
background-repeat: no-repeat;
background-position: center left; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.bg-center-m {
background-repeat: no-repeat;
background-position: center center; }
@ -807,7 +807,7 @@ img, video {
.outline-0 {
outline: 0; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.outline-ns {
outline: 1px solid; }
.outline-transparent-ns {
@ -815,7 +815,7 @@ img, video {
.outline-0-ns {
outline: 0; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.outline-m {
outline: 1px solid; }
.outline-transparent-m {
@ -877,7 +877,7 @@ img, video {
border-style: none;
border-width: 0; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.ba-ns {
border-style: solid;
border-width: 1px; }
@ -897,7 +897,7 @@ img, video {
border-style: none;
border-width: 0; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.ba-m {
border-style: solid;
border-width: 1px; }
@ -1204,7 +1204,7 @@ img, video {
border-top-right-radius: 0;
border-bottom-right-radius: 0; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.br0-ns {
border-radius: 0; }
.br1-ns {
@ -1232,7 +1232,7 @@ img, video {
border-top-right-radius: 0;
border-bottom-right-radius: 0; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.br0-m {
border-radius: 0; }
.br1-m {
@ -1322,7 +1322,7 @@ img, video {
.b--none {
border-style: none; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.b--dotted-ns {
border-style: dotted; }
.b--dashed-ns {
@ -1332,7 +1332,7 @@ img, video {
.b--none-ns {
border-style: none; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.b--dotted-m {
border-style: dotted; }
.b--dashed-m {
@ -1405,7 +1405,7 @@ img, video {
.bl-0 {
border-left-width: 0; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.bw0-ns {
border-width: 0; }
.bw1-ns {
@ -1427,7 +1427,7 @@ img, video {
.bl-0-ns {
border-left-width: 0; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.bw0-m {
border-width: 0; }
.bw1-m {
@ -1497,7 +1497,7 @@ img, video {
.shadow-5 {
box-shadow: 4px 4px 8px 0px rgba(0, 0, 0, 0.2); }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.shadow-1-ns {
box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.2); }
.shadow-2-ns {
@ -1509,7 +1509,7 @@ img, video {
.shadow-5-ns {
box-shadow: 4px 4px 8px 0px rgba(0, 0, 0, 0.2); } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.shadow-1-m {
box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.2); }
.shadow-2-m {
@ -1635,7 +1635,7 @@ img, video {
bottom: 0;
left: 0; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.top-0-ns {
top: 0; }
.left-0-ns {
@ -1682,7 +1682,7 @@ img, video {
bottom: 0;
left: 0; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.top-0-m {
top: 0; }
.left-0-m {
@ -1807,7 +1807,7 @@ img, video {
.cn {
clear: none; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.cl-ns {
clear: left; }
.cr-ns {
@ -1817,7 +1817,7 @@ img, video {
.cn-ns {
clear: none; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.cl-m {
clear: left; }
.cr-m {
@ -1903,7 +1903,7 @@ img, video {
table-layout: fixed;
width: 100%; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.dn-ns {
display: none; }
.di-ns {
@ -1930,7 +1930,7 @@ img, video {
table-layout: fixed;
width: 100%; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.dn-m {
display: none; }
.di-m {
@ -2138,7 +2138,7 @@ img, video {
.flex-shrink-1 {
flex-shrink: 1; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.flex-ns {
display: flex; }
.inline-flex-ns {
@ -2236,7 +2236,7 @@ img, video {
.flex-shrink-1-ns {
flex-shrink: 1; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.flex-m {
display: flex; }
.inline-flex-m {
@ -2468,7 +2468,7 @@ img, video {
.fn {
float: none; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.fl-ns {
float: left;
_display: inline; }
@ -2478,7 +2478,7 @@ img, video {
.fn-ns {
float: none; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.fl-m {
float: left;
_display: inline; }
@ -2570,13 +2570,13 @@ code, .code {
.fs-normal {
font-style: normal; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.i-ns {
font-style: italic; }
.fs-normal-ns {
font-style: normal; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.i-m {
font-style: italic; }
.fs-normal-m {
@ -2646,7 +2646,7 @@ code, .code {
.fw9 {
font-weight: 900; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.normal-ns {
font-weight: normal; }
.b-ns {
@ -2670,7 +2670,7 @@ code, .code {
.fw9-ns {
font-weight: 900; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.normal-m {
font-weight: normal; }
.b-m {
@ -2819,7 +2819,7 @@ code, .code {
.h-inherit {
height: inherit; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.h1-ns {
height: 1rem; }
.h2-ns {
@ -2855,7 +2855,7 @@ code, .code {
.h-inherit-ns {
height: inherit; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.h1-m {
height: 1rem; }
.h2-m {
@ -2947,7 +2947,7 @@ code, .code {
.tracked-mega {
letter-spacing: 0.25em; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.tracked-ns {
letter-spacing: 0.1em; }
.tracked-tight-ns {
@ -2955,7 +2955,7 @@ code, .code {
.tracked-mega-ns {
letter-spacing: 0.25em; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.tracked-m {
letter-spacing: 0.1em; }
.tracked-tight-m {
@ -2991,7 +2991,7 @@ code, .code {
.lh-copy {
line-height: 1.5; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.lh-solid-ns {
line-height: 1; }
.lh-title-ns {
@ -2999,7 +2999,7 @@ code, .code {
.lh-copy-ns {
line-height: 1.5; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.lh-solid-m {
line-height: 1; }
.lh-title-m {
@ -3114,7 +3114,7 @@ code, .code {
.mw-none {
max-width: none; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.mw-100-ns {
max-width: 100%; }
.mw1-ns {
@ -3138,7 +3138,7 @@ code, .code {
.mw-none-ns {
max-width: none; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.mw-100-m {
max-width: 100%; }
.mw1-m {
@ -3303,7 +3303,7 @@ code, .code {
.w-auto {
width: auto; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.w1-ns {
width: 1rem; }
.w2-ns {
@ -3355,7 +3355,7 @@ code, .code {
.w-auto-ns {
width: auto; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.w1-m {
width: 1rem; }
.w2-m {
@ -3505,7 +3505,7 @@ code, .code {
.overflow-y-auto {
overflow-y: auto; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.overflow-visible-ns {
overflow: visible; }
.overflow-hidden-ns {
@ -3531,7 +3531,7 @@ code, .code {
.overflow-y-auto-ns {
overflow-y: auto; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.overflow-visible-m {
overflow: visible; }
.overflow-hidden-m {
@ -3606,7 +3606,7 @@ code, .code {
.fixed {
position: fixed; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.static-ns {
position: static; }
.relative-ns {
@ -3616,7 +3616,7 @@ code, .code {
.fixed-ns {
position: fixed; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.static-m {
position: static; }
.relative-m {
@ -3707,7 +3707,7 @@ code, .code {
.rotate-315 {
transform: rotate(315deg); }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.rotate-45-ns {
transform: rotate(45deg); }
.rotate-90-ns {
@ -3723,7 +3723,7 @@ code, .code {
.rotate-315-ns {
transform: rotate(315deg); } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.rotate-45-m {
transform: rotate(45deg); }
.rotate-90-m {
@ -4985,7 +4985,7 @@ input[type=submit]:not(.button-small), .notice {
margin-left: 16rem;
margin-right: 16rem; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.pa0-ns {
padding: 0; }
.pa1-ns {
@ -5247,7 +5247,7 @@ input[type=submit]:not(.button-small), .notice {
margin-left: 16rem;
margin-right: 16rem; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.pa0-m {
padding: 0; }
.pa1-m {
@ -5895,7 +5895,7 @@ input[type=submit]:not(.button-small), .notice {
.nt7 {
margin-top: -16rem; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.na1-ns {
margin: -0.25rem; }
.na2-ns {
@ -5967,7 +5967,7 @@ input[type=submit]:not(.button-small), .notice {
.nt7-ns {
margin-top: -16rem; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.na1-m {
margin: -0.25rem; }
.na2-m {
@ -6160,7 +6160,7 @@ input[type=submit]:not(.button-small), .notice {
.no-underline {
text-decoration: none; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.strike-ns {
text-decoration: line-through; }
.underline-ns {
@ -6168,7 +6168,7 @@ input[type=submit]:not(.button-small), .notice {
.no-underline-ns {
text-decoration: none; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.strike-m {
text-decoration: line-through; }
.underline-m {
@ -6216,7 +6216,7 @@ input[type=submit]:not(.button-small), .notice {
.tj {
text-align: justify; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.tl-ns {
text-align: left; }
.tr-ns, .edit-form .edit-form-row > :first-child {
@ -6226,7 +6226,7 @@ input[type=submit]:not(.button-small), .notice {
.tj-ns {
text-align: justify; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.tl-m {
text-align: left; }
.tr-m {
@ -6278,7 +6278,7 @@ input[type=submit]:not(.button-small), .notice {
.ttn {
text-transform: none; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.ttc-ns {
text-transform: capitalize; }
.ttl-ns {
@ -6288,7 +6288,7 @@ input[type=submit]:not(.button-small), .notice {
.ttn-ns {
text-transform: none; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.ttc-m {
text-transform: capitalize; }
.ttl-m {
@ -6365,7 +6365,7 @@ input[type=submit]:not(.button-small), .notice {
.f7 {
font-size: 0.75rem; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.f-6-ns,
.f-headline-ns {
font-size: 6rem; }
@ -6387,7 +6387,7 @@ input[type=submit]:not(.button-small), .notice {
.f7-ns {
font-size: 0.75rem; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.f-6-m,
.f-headline-m {
font-size: 6rem; }
@ -6469,7 +6469,7 @@ input[type=submit]:not(.button-small), .notice {
overflow: hidden;
text-overflow: ellipsis; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.measure-ns {
max-width: 30em; }
.measure-wide-ns {
@ -6487,7 +6487,7 @@ input[type=submit]:not(.button-small), .notice {
overflow: hidden;
text-overflow: ellipsis; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.measure-m {
max-width: 30em; }
.measure-wide-m {
@ -6547,7 +6547,7 @@ input[type=submit]:not(.button-small), .notice {
.ml-auto {
margin-left: auto; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.center-ns {
margin-right: auto;
margin-left: auto; }
@ -6556,7 +6556,7 @@ input[type=submit]:not(.button-small), .notice {
.ml-auto-ns {
margin-left: auto; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.center-m {
margin-right: auto;
margin-left: auto; }
@ -6595,7 +6595,7 @@ input[type=submit]:not(.button-small), .notice {
/* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px); }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.clip-ns {
position: fixed !important;
_position: absolute !important;
@ -6603,7 +6603,7 @@ input[type=submit]:not(.button-small), .notice {
/* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px); } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.clip-m {
position: fixed !important;
_position: absolute !important;
@ -6638,7 +6638,7 @@ input[type=submit]:not(.button-small), .notice {
.pre {
white-space: pre; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.ws-normal-ns {
white-space: normal; }
.nowrap-ns {
@ -6646,7 +6646,7 @@ input[type=submit]:not(.button-small), .notice {
.pre-ns {
white-space: pre; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.ws-normal-m {
white-space: normal; }
.nowrap-m {
@ -6684,7 +6684,7 @@ input[type=submit]:not(.button-small), .notice {
.v-btm {
vertical-align: bottom; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.v-base-ns {
vertical-align: baseline; }
.v-mid-ns {
@ -6694,7 +6694,7 @@ input[type=submit]:not(.button-small), .notice {
.v-btm-ns {
vertical-align: bottom; } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.v-base-m {
vertical-align: baseline; }
.v-mid-m {
@ -7357,7 +7357,7 @@ article code {
flex-grow: 1;
flex-shrink: 1; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.flex-fair-ns {
flex-basis: 1px;
flex-grow: 1;
@ -7556,7 +7556,7 @@ article code {
.hide-if-empty:empty {
display: none !important; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.bi-avoid-ns {
break-inside: avoid; }
.cc-auto-ns {
@ -7583,7 +7583,7 @@ article code {
background-color: #f0f0f0;
background-color: var(--dim-background); } }
@media screen and (min-width: 30em) and (max-width: 60em) {
@media screen and (min-width: 35em) and (max-width: 60em) {
.bi-avoid-m {
break-inside: avoid; }
.cc-auto-m {
@ -7658,7 +7658,7 @@ article code {
margin-right: auto;
margin-left: auto; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
footer .list li:not(:last-child)::after {
content: ' / '; } }
@ -7741,7 +7741,7 @@ article code {
border-width: 0px;
border-bottom-width: 1px;
padding-bottom: 0.5rem; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.optionbar {
flex-direction: row;
text-align: left;
@ -7751,7 +7751,7 @@ article code {
border-top-width: 1px;
padding-bottom: 0;
padding-top: 0.5rem; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.optionbar.bottom {
padding-top: 0; } }
.optionbar.center {
@ -7759,7 +7759,7 @@ article code {
.optionbar .options {
display: flex;
flex-direction: column; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.optionbar .options {
flex-direction: row; } }
@ -7869,6 +7869,28 @@ article code {
--fade-color: #f8f8f8;
--fade-color: var(--background-even-background); }
.sr-only, .sr-focusable {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
transition: 0.2s all; }
.sr-focusable:focus {
padding: 15px 10px;
height: auto;
width: auto;
background: var(--content-background);
clip: initial;
clip-path: initial;
z-index: 99999; }
.userlist {
text-align: center;
width: 100%;
@ -8075,7 +8097,7 @@ figure {
color: var(--dimmer-color);
font-style: italic; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
#preview-container {
max-height: calc(100vh - 20rem);
overflow: auto; } }
@ -8083,7 +8105,7 @@ figure {
.edit-form .edit-form-row > :first-child {
font-weight: 500; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.edit-form .edit-form-row .pt-input-ns {
padding-top: 0.3rem; } }
@ -8827,10 +8849,10 @@ header .hmn-logo {
align-items: center;
justify-content: center;
color: white !important; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
header .hmn-logo.big {
width: 11.25rem; } }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
header .hmn-logo.small {
width: 3.75rem;
padding: 0.8rem;
@ -8845,7 +8867,7 @@ header .hmn-logo {
header .items {
position: relative; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
header .root-item {
position: relative;
height: 3.75rem; } }
@ -8882,7 +8904,7 @@ header .submenu {
min-width: 10rem;
border-top-style: solid;
border-bottom-style: solid; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
header .submenu {
border-top-style: none;
border-left-style: solid;
@ -8895,7 +8917,7 @@ header .submenu {
z-index: 1;
font-weight: bold;
text-align: center; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
header .submenu > a {
text-align: left; } }
@ -8903,6 +8925,9 @@ header .menu-bar {
width: 100%;
z-index: 10; }
header #login-link {
cursor: pointer; }
header #login-popup {
background-color: #fbfbfb;
background-color: var(--login-popup-background);
@ -9452,7 +9477,7 @@ span.icon-rss::before {
.timeline-item .avatar-icon.big {
width: 3rem;
height: 3rem; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.timeline-item .avatar-icon.big {
width: 3.875rem;
height: 3.875rem; } }
@ -9467,7 +9492,7 @@ span.icon-rss::before {
.timeline-modal .container {
max-height: 100vh;
max-width: 100%; }
@media screen and (min-width: 30em) {
@media screen and (min-width: 35em) {
.timeline-modal .container {
width: auto;
max-width: calc(100% - 2rem);

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

View File

@ -14,6 +14,7 @@ var Config = HMNConfig{
BaseUrl: "http://handmade.local:9001",
LogLevel: zerolog.TraceLevel, // InfoLevel is recommended for production
Postgres: PostgresConfig{
// the "db seed" command depends on this user existing in Postgres, so you'll want to make sure it exists when running locally.
User: "hmn",
Password: "password",
Hostname: "localhost",

View File

@ -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"))),

View File

@ -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 {

View File

@ -769,3 +769,31 @@ footer {
@include usevar(background-color, background-even-background);
@include usevar(--fade-color, background-even-background);
}
.sr-only {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
transition: 0.2s all;
}
.sr-focusable {
@extend .sr-only;
&:focus {
padding: 15px 10px;
height: auto;
width: auto;
background: var(--content-background);
clip: initial;
clip-path: initial;
z-index: 99999;
}
}

View File

@ -122,6 +122,10 @@ header {
z-index: 10;
}
#login-link{
cursor: pointer;
}
#login-popup {
@include usevar(background-color, login-popup-background);
@include usevar(color, fg-font-color);

View File

@ -136,8 +136,8 @@ $washed-red: #ffdfdf !default;
// Custom Media Query Variables
$breakpoint-not-small: 'screen and (min-width: 30em)' !default;
$breakpoint-medium: 'screen and (min-width: 30em) and (max-width: 60em)' !default;
$breakpoint-not-small: 'screen and (min-width: 35em)' !default;
$breakpoint-medium: 'screen and (min-width: 35em) and (max-width: 60em)' !default;
$breakpoint-large: 'screen and (min-width: 60em)' !default;
/*

View File

@ -1,4 +1,5 @@
<header id="site-header" class="mb3 bb bw1 b--theme-dark">
<a href="#content-start" class="sr-focusable" id="content-jump">Jump to Content</a>
<div class="user-options flex justify-center justify-end-ns relative">
{{ if .User }}
{{ if .User.IsStaff }}
@ -70,8 +71,10 @@
<a href="{{ .Header.ProjectIndexUrl }}">Projects</a>
</div>
<div class="root-item">
<a>Media <div class="dib svgicon ml1">{{ svg "chevron-down-thick" }}</div></a>
<div class="submenu b--theme-dark">
<a aria-expanded="false" aria-controls="media-submenu" class="menu-dropdown-js" href="#">
Media <div class="dib svgicon ml1">{{ svg "chevron-down-thick" }}</div>
</a>
<div class="submenu b--theme-dark" id="media-submenu">
<a href="{{ .Header.ConferencesUrl }}">Conferences</a>
<a href="{{ .Header.PodcastUrl }}">Podcast</a>
<a href="{{ .Header.FishbowlUrl }}">Fishbowls</a>
@ -82,8 +85,10 @@
<a href="{{ .Header.ForumsUrl }}">Forums</a>
</div>
<div class="root-item">
<a>Resources <div class="dib svgicon ml1">{{ svg "chevron-down-thick" }}</div></a>
<div class="submenu b--theme-dark">
<a aria-expanded="false" aria-controls="resource-submenu" class="menu-dropdown-js" href="#">
Resources <div class="dib svgicon ml1">{{ svg "chevron-down-thick" }}</div>
</a>
<div class="submenu b--theme-dark" id="resource-submenu">
<a href="{{ .Header.EducationUrl }}">Education</a>
</div>
</div>
@ -96,7 +101,7 @@
</div>
</div>
</header>
<div id="content-start"></div>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
const header = document.querySelector('#site-header');
@ -132,15 +137,37 @@
}
}
// dropdown accessiblity
{
const dropdowns = document.querySelectorAll('.menu-dropdown-js');
for(let i = 0; i < dropdowns.length; i++) {
let dropdown = dropdowns[i];
dropdown.addEventListener('click', e => {
e.preventDefault();
for(let j = 0; j < dropdowns.length; j++){
let each = dropdowns[j];
if(each != dropdown){
each.setAttribute("aria-expanded", false);
}
}
// getAttribute returns a string so we have to do it this way
var toSetTo = dropdown.getAttribute("aria-expanded") == "false" ? "true" : "false";
dropdown.setAttribute("aria-expanded", toSetTo);
console.log(dropdown);
});
}
}
// set up login form
{
const loginPopup = document.getElementById("login-popup");
const loginLink = document.getElementById("login-link");
if (loginPopup !== null) {
loginLink.removeAttribute("href");
loginLink.onclick = () => {
loginLink.onclick = (e) => {
e.preventDefault();
loginPopup.classList.toggle("open");
}
}

View File

@ -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 "visualjam2023/favicon-16x16.png" }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ static "visualjam2023/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>

View File

@ -0,0 +1,447 @@
{{ 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 jam to see things in a new way. {{ 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 its some weird data structure you
want to debug. Maybe its a map of your codebase. Maybe its 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
<a href="{{ $discordInviteURL }}" target="_blank">Discord</a>, 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 }}

View File

@ -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)

View File

@ -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("visualjam2023/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))
// }