Ugly jam feed. Needs CSS work.
This commit is contained in:
parent
64f94bddbb
commit
316aba12b6
|
@ -29,6 +29,7 @@ type ProjectsQuery struct {
|
|||
ProjectIDs []int // if empty, all projects
|
||||
Slugs []string // if empty, all projects
|
||||
OwnerIDs []int // if empty, all projects
|
||||
JamSlugs []string // if empty, all projects
|
||||
|
||||
// Ignored when using CountProjects
|
||||
Limit, Offset int // if empty, no pagination
|
||||
|
@ -101,6 +102,14 @@ func FetchProjects(
|
|||
)
|
||||
}
|
||||
|
||||
if len(q.JamSlugs) > 0 {
|
||||
qb.Add(
|
||||
`
|
||||
JOIN jam_project ON jam_project.project_id = project.id
|
||||
`,
|
||||
)
|
||||
}
|
||||
|
||||
// Filters (permissions are checked after the query, in Go)
|
||||
qb.Add(`
|
||||
WHERE
|
||||
|
@ -130,6 +139,9 @@ func FetchProjects(
|
|||
if len(q.Slugs) > 0 {
|
||||
qb.Add(`AND (project.slug != '' AND project.slug = ANY ($?))`, q.Slugs)
|
||||
}
|
||||
if len(q.JamSlugs) > 0 {
|
||||
qb.Add(`AND (jam_project.jam_slug = ANY ($?) AND jam_project.participating = TRUE)`, q.JamSlugs)
|
||||
}
|
||||
|
||||
// Output
|
||||
if q.Limit > 0 {
|
||||
|
|
|
@ -320,6 +320,12 @@ func BuildProjectNew() string {
|
|||
return Url("/p/new", nil)
|
||||
}
|
||||
|
||||
func BuildProjectNewJam() string {
|
||||
defer CatchPanic()
|
||||
|
||||
return Url("/p/new", []Q{Q{Name: "jam", Value: "1"}})
|
||||
}
|
||||
|
||||
var RegexPersonalProject = regexp.MustCompile("^/p/(?P<projectid>[0-9]+)(/(?P<projectslug>[a-zA-Z0-9-]+))?")
|
||||
|
||||
func BuildPersonalProject(id int, slug string) string {
|
||||
|
|
|
@ -0,0 +1,280 @@
|
|||
{{/*
|
||||
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">
|
||||
|
||||
<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" }}">
|
||||
<link rel="stylesheet" href="{{ statictheme .Theme "theme.css" }}" />
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--content-background: #f8f8f8;
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(#346ba6, #814cb7)
|
||||
}
|
||||
|
||||
.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: #346ba6;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 30em) {
|
||||
/* not small styles */
|
||||
|
||||
#top-container {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
#logo {
|
||||
width: 31rem;
|
||||
}
|
||||
|
||||
#title {
|
||||
font-size: 5.2rem;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="left white">
|
||||
<div class="mt4-ns mw8 margin-center ph3-m ph4-l">
|
||||
{{ template "header.html" . }}
|
||||
</div>
|
||||
|
||||
<div id="top-container" class="flex flex-column items-center ph3">
|
||||
<h1 id="title">Wheel Reinvention Jam</h1>
|
||||
<h2 id="dates">August 15 - 21, 2O22</h2>
|
||||
<div id="tagline" class="center">
|
||||
A one-week jam to change the status quo.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="bg-black-20 pt4 pb3 pb4-ns">
|
||||
<div class="section mw8 margin-center ph3 ph4-l mv4">
|
||||
<h2>Projects</h2>
|
||||
<div class="projects">
|
||||
{{ range .JamProjects }}
|
||||
<div class="mv3">
|
||||
{{ template "project_card.html" projectcarddata . "" }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section mw8 margin-center ph3 ph4-l">
|
||||
<h2>Recent activity</h2>
|
||||
<div class="timeline">
|
||||
{{ range .TimelineItems }}
|
||||
{{ template "timeline_item.html" . }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mw8 margin-center ph3-m ph4-l">
|
||||
{{ template "footer.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -26,6 +26,9 @@
|
|||
{{ end }}
|
||||
<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'>
|
||||
<link href='https://fonts.googleapis.com/css?family=Fira+Mono:300,400,500,700' rel='stylesheet' type='text/css'>
|
||||
|
@ -105,12 +108,12 @@
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#actions {
|
||||
.actions {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
#actions a {
|
||||
text-decoration: none;
|
||||
.actions a {
|
||||
text-decoration: none !important;
|
||||
line-height: 1.4;
|
||||
font-weight: 500;
|
||||
|
||||
|
@ -118,11 +121,11 @@
|
|||
background-color:rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
#actions a:hover {
|
||||
.actions a:hover {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
#actions a:active {
|
||||
.actions a:active {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
|
@ -183,6 +186,11 @@
|
|||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.showcase-item {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 30em) {
|
||||
/* not small styles */
|
||||
|
||||
|
@ -208,11 +216,11 @@
|
|||
margin-top: 1.2rem;
|
||||
}
|
||||
|
||||
#actions {
|
||||
.actions {
|
||||
margin-top: 2.2rem;
|
||||
}
|
||||
|
||||
#actions a {
|
||||
.actions a {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
|
@ -241,11 +249,18 @@
|
|||
<div id="tagline" class="center">
|
||||
A one-week jam to change the status quo.
|
||||
</div>
|
||||
<div id="actions" class="flex justify-center">
|
||||
<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">Choose a project</a>
|
||||
{{ else }}
|
||||
<!-- TODO: A reasonable call to action! -->
|
||||
{{ 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" target="_blank" href="https://github.com/HandmadeNetwork/wishlist/discussions">Choose a project</a>
|
||||
<a class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3" target="_blank" href="{{ .ProjectSubmissionUrl }}">Create a jam project</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<a class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3" target="_blank" href="https://discord.gg/hmn">Join the Discord</a>
|
||||
</div>
|
||||
|
@ -266,6 +281,28 @@
|
|||
</p>
|
||||
</div>
|
||||
|
||||
{{ if .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 activity</h2>
|
||||
<p>
|
||||
These screenshots and videos were shared in #jam-showcase on our <a href="https://discord.gg/hmn" target="_blank">Discord</a>. Join us!
|
||||
</p>
|
||||
{{ else }}
|
||||
<h2>Showcase</h2>
|
||||
<p>
|
||||
Post-jam text
|
||||
</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 more</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="bg-black-20 pt4 pb3 pb4-ns">
|
||||
<div class="section mw8 margin-center ph3 ph4-l">
|
||||
<h2>Details / Rules</h2>
|
||||
|
@ -340,6 +377,109 @@
|
|||
{{ template "footer.html" . }}
|
||||
</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>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -32,22 +32,132 @@ func JamIndex2022(c *RequestContext) ResponseData {
|
|||
type JamPageData struct {
|
||||
templates.BaseData
|
||||
DaysUntilStart, DaysUntilEnd int
|
||||
SubmittedProjectUrl string
|
||||
ProjectSubmissionUrl string
|
||||
ShowcaseFeedUrl string
|
||||
ShowcaseJson string
|
||||
}
|
||||
|
||||
var showcaseItems []templates.TimelineItem
|
||||
submittedProjectUrl := ""
|
||||
if daysUntilStart <= 0 && daysUntilEnd > 0 {
|
||||
if c.CurrentUser != nil {
|
||||
projects, err := hmndata.FetchProjects(c.Context(), 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.Context(), 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"))
|
||||
}
|
||||
|
||||
jamProjectTags := make([]int, 0, len(jamProjects))
|
||||
for _, jp := range jamProjects {
|
||||
if jp.Tag != nil {
|
||||
jamProjectTags = append(jamProjectTags, jp.Tag.ID)
|
||||
}
|
||||
}
|
||||
|
||||
snippets, err := hmndata.FetchSnippets(c.Context(), c.Conn, c.CurrentUser, hmndata.SnippetQuery{
|
||||
Tags: jamProjectTags,
|
||||
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.Tags, s.Owner, c.Theme)
|
||||
if timelineItem.CanShowcase {
|
||||
showcaseItems = append(showcaseItems, timelineItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
showcaseJson := templates.TimelineItemsToJSON(showcaseItems)
|
||||
|
||||
res.MustWriteTemplate("wheeljam_2022_index.html", JamPageData{
|
||||
BaseData: baseData,
|
||||
DaysUntilStart: daysUntilStart,
|
||||
DaysUntilEnd: daysUntilEnd,
|
||||
BaseData: baseData,
|
||||
DaysUntilStart: daysUntilStart,
|
||||
DaysUntilEnd: daysUntilEnd,
|
||||
ProjectSubmissionUrl: hmnurl.BuildProjectNewJam(),
|
||||
SubmittedProjectUrl: submittedProjectUrl,
|
||||
ShowcaseFeedUrl: hmnurl.BuildJamFeed2022(),
|
||||
ShowcaseJson: showcaseJson,
|
||||
}, c.Perf)
|
||||
return res
|
||||
}
|
||||
|
||||
func JamFeed2022(c *RequestContext) ResponseData {
|
||||
// List newly-created jam projects
|
||||
// list snippets from jam projects
|
||||
// list forum posts from jam project threads
|
||||
// timeline everything
|
||||
return FourOhFour(c)
|
||||
jamProjects, err := hmndata.FetchProjects(c.Context(), 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"))
|
||||
}
|
||||
|
||||
jamProjectTags := make([]int, 0, len(jamProjects))
|
||||
for _, jp := range jamProjects {
|
||||
if jp.Tag != nil {
|
||||
jamProjectTags = append(jamProjectTags, jp.Tag.ID)
|
||||
}
|
||||
}
|
||||
|
||||
snippets, err := hmndata.FetchSnippets(c.Context(), c.Conn, c.CurrentUser, hmndata.SnippetQuery{
|
||||
Tags: jamProjectTags,
|
||||
})
|
||||
if err != nil {
|
||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets for jam showcase"))
|
||||
}
|
||||
|
||||
timelineItems := make([]templates.TimelineItem, 0, len(snippets))
|
||||
|
||||
for _, s := range snippets {
|
||||
timelineItem := SnippetToTimelineItem(&s.Snippet, s.Asset, s.DiscordMessage, s.Tags, s.Owner, c.Theme)
|
||||
timelineItems = append(timelineItems, timelineItem)
|
||||
}
|
||||
|
||||
// TODO(asaf): add forum posts from jam project threads to timeline
|
||||
// TODO(asaf): Sort timeline items
|
||||
|
||||
pageProjects := make([]templates.Project, 0, len(jamProjects))
|
||||
for _, p := range jamProjects {
|
||||
pageProjects = append(pageProjects, templates.ProjectAndStuffToTemplate(&p, hmndata.UrlContextForProject(&p.Project).BuildHomepage(), c.Theme))
|
||||
}
|
||||
|
||||
type JamFeedData struct {
|
||||
templates.BaseData
|
||||
JamProjects []templates.Project
|
||||
TimelineItems []templates.TimelineItem
|
||||
}
|
||||
|
||||
baseData := getBaseDataAutocrumb(c, hmndata.WRJ2022.Name)
|
||||
baseData.OpenGraphItems = []templates.OpenGraphItem{
|
||||
{Property: "og:site_name", Value: "Handmade.Network"},
|
||||
{Property: "og:type", Value: "website"},
|
||||
{Property: "og:image", Value: hmnurl.BuildPublic("wheeljam2022/opengraph.png", true)},
|
||||
{Property: "og:description", Value: "A one-week jam to change the status quo. August 15 - 21 on Handmade Network."},
|
||||
{Property: "og:url", Value: hmnurl.BuildJamIndex()},
|
||||
}
|
||||
|
||||
var res ResponseData
|
||||
res.MustWriteTemplate("wheeljam_2022_feed.html", JamFeedData{
|
||||
BaseData: baseData,
|
||||
JamProjects: pageProjects,
|
||||
TimelineItems: timelineItems,
|
||||
}, c.Perf)
|
||||
return res
|
||||
}
|
||||
|
||||
func JamIndex2021(c *RequestContext) ResponseData {
|
||||
|
|
Loading…
Reference in New Issue