Some tweaks

This commit is contained in:
Ben Visness 2022-08-06 20:21:12 -05:00
parent 97ed892ce3
commit 48490d83a9
8 changed files with 244 additions and 200 deletions

View File

@ -28,7 +28,7 @@ var WRJ2021 = Jam{
var WRJ2022 = Jam{
Name: "Wheel Reinvention Jam 2022",
Slug: "WRJ2022",
StartTime: time.Date(2022, 8, 3, 8, 0, 0, 0, utils.Must1(time.LoadLocation("America/Los_Angeles"))),
StartTime: time.Date(2022, 8, 15, 8, 0, 0, 0, utils.Must1(time.LoadLocation("America/Los_Angeles"))),
EndTime: time.Date(2022, 8, 22, 8, 0, 0, 0, utils.Must1(time.LoadLocation("America/Los_Angeles"))),
}

View File

@ -146,7 +146,20 @@
<img class="h3" src="{{ static "wheeljam2022/logo.svg" }}">
<div id="jam-title-container" class="flex flex-column pl3-m pl4-l pv3 pv0-ns">
<h3 id="jam-title">Wheel Reinvention Jam</h3>
<div id="jam-details">August 15 - 21. Change the status quo.</div>
<div id="jam-details">
August 15 - 21.
{{ if gt .JamDaysUntilEnd 0 }}
{{ if eq .JamDaysUntilStart 0 }}
<b>Happening now.</b>
{{ else if eq .JamDaysUntilStart 1 }}
<b>Starting tomorrow.</b>
{{ else }}
<b>In {{ .JamDaysUntilStart }} days.</b>
{{ end }}
{{ else }}
<b>See the results.</b>
{{ end }}
</div>
</div>
<div class="flex-grow-1"></div>
<div id="jam-learn-more">

View File

@ -27,7 +27,6 @@
<meta name="theme-color" content="#346ba6">
<script src="{{ static "js/templates.js" }}"></script>
<script src="{{ static "js/showcase.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'>
@ -264,6 +263,31 @@
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;
}
</style>
<script src="{{ static "js/carousel.js" }}"></script>

View File

@ -90,16 +90,15 @@
{{ if .ProjectSettings.JamParticipation }}
<div class="edit-form-row">
<div class="pt-input-ns">Jam Participation</div>
</div>
{{ range .ProjectSettings.JamParticipation }}
<div class="edit-form-row">
<div>{{ .JamName }}:</div>
<div>
<input id="jam_{{ .JamSlug }}" type="checkbox" name="jam_participation" value="{{ .JamSlug }}" {{ if .Participating }}checked{{ end }} />
<label for="jam_{{ .JamSlug }}">Participating</label>
</div>
<div class="pt-input-ns">
{{ range .ProjectSettings.JamParticipation }}
<div class="pb1">
<input id="jam_{{ .JamSlug }}" type="checkbox" name="jam_participation" value="{{ .JamSlug }}" {{ if .Participating }}checked{{ end }} />
<label for="jam_{{ .JamSlug }}">{{ .JamName }}</label>
</div>
{{ end }}
</div>
{{ end }}
</div>
{{ end }}
{{ if and .Editing .User.IsStaff }}
<div class="edit-form-row">

View File

@ -5,39 +5,6 @@
#title {
margin-top: 0;
}
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;
}
@media screen and (min-width: 30em) {
/* not small styles */
}
@media screen and (min-width: 30em) {
/* large styles */
}
</style>
<div id="top-container" class="flex flex-column items-center ph3">
@ -50,7 +17,7 @@
<div class="section bg-black-20 pt4 pb3 pb4-ns">
<div class="mw8 margin-center ph3 ph4-l flex flex-column flex-row-ns g3">
<div>
<div class="flex-grow-1">
{{ if eq .DaysUntilEnd 0 }}
<h3 class="mt0 mb3">Project updates</h3>
{{ else }}

View File

@ -3,6 +3,21 @@
{{ define "content" }}
{{ $discordInviteURL := "https://discord.gg/zFt8Rf59?event=1004511448107602031" }}
<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 "wheeljam2022/logo.svg" }}">
<h1 id="title">Wheel Reinvention Jam</h1>
@ -22,14 +37,14 @@
<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 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>
@ -50,13 +65,27 @@
</p>
</div>
{{ if not (eq .ShowcaseJson "[]") }}
{{ 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!
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>
@ -66,10 +95,114 @@
{{ 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 more</a>
<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>
{{ else }}
<div class="section bg-black-20 pv4 overflow-hidden">
<div class="mw8 margin-center ph3 ph4-l">
@ -229,110 +362,6 @@
</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>
<script>
const carouselContainer = document.querySelector('.carousel-container');

View File

@ -30,59 +30,67 @@ func JamIndex2022(c *RequestContext) ResponseData {
templates.BaseData
DaysUntilStart, DaysUntilEnd int
StartTimeUnix, EndTimeUnix int64
SubmittedProjectUrl string
ProjectSubmissionUrl string
ShowcaseFeedUrl string
ShowcaseJson string
SubmittedProjectUrl string
ProjectSubmissionUrl string
ShowcaseFeedUrl string
ShowcaseJson string
JamProjects []templates.Project
}
var showcaseItems []templates.TimelineItem
submittedProjectUrl := ""
if daysUntilStart <= 0 && daysUntilEnd > 0 {
if c.CurrentUser != nil {
projects, err := hmndata.FetchProjects(c, c.Conn, c.CurrentUser, hmndata.ProjectsQuery{
OwnerIDs: []int{c.CurrentUser.ID},
JamSlugs: []string{hmndata.WRJ2022.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{
if c.CurrentUser != nil {
projects, err := hmndata.FetchProjects(c, c.Conn, c.CurrentUser, hmndata.ProjectsQuery{
OwnerIDs: []int{c.CurrentUser.ID},
JamSlugs: []string{hmndata.WRJ2022.Slug},
Limit: 1,
})
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch jam projects for current user"))
}
projectIds := make([]int, 0, len(jamProjects))
for _, jp := range jamProjects {
projectIds = append(projectIds, jp.Project.ID)
if len(projects) > 0 {
urlContext := hmndata.UrlContextForProject(&projects[0].Project)
submittedProjectUrl = urlContext.BuildHomepage()
}
}
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)
}
jamProjects, err := hmndata.FetchProjects(c, c.Conn, c.CurrentUser, hmndata.ProjectsQuery{
JamSlugs: []string{hmndata.WRJ2022.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("wheeljam_2022_index.html", JamPageData{
@ -95,6 +103,7 @@ func JamIndex2022(c *RequestContext) ResponseData {
SubmittedProjectUrl: submittedProjectUrl,
ShowcaseFeedUrl: hmnurl.BuildJamFeed2022(),
ShowcaseJson: showcaseJson,
JamProjects: pageProjects,
}, c.Perf)
return res
}

View File

@ -29,7 +29,8 @@ type LandingTemplateData struct {
AtomFeedUrl string
MarkAllReadUrl string
JamUrl string
JamUrl string
JamDaysUntilStart, JamDaysUntilEnd int
}
func Index(c *RequestContext) ResponseData {
@ -149,7 +150,9 @@ func Index(c *RequestContext) ResponseData {
AtomFeedUrl: hmnurl.BuildAtomFeed(),
MarkAllReadUrl: hmnurl.HMNProjectContext.BuildForumMarkRead(0),
JamUrl: hmnurl.BuildJamIndex(),
JamUrl: hmnurl.BuildJamIndex(),
JamDaysUntilStart: daysUntil(hmndata.WRJ2022.StartTime),
JamDaysUntilEnd: daysUntil(hmndata.WRJ2022.EndTime),
}, c.Perf)
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render landing page template"))