From f8d5f9fce543b66f43af70e4a1c207c4a2fa820a Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sun, 24 Oct 2021 15:48:28 -0500 Subject: [PATCH] Rework the home page --- public/js/showcase.js | 107 ++++++- public/style.css | 91 ++---- public/themes/dark/theme.css | 4 +- src/rawdata/scss/_core.scss | 12 + src/rawdata/scss/_landing.scss | 92 +----- src/rawdata/scss/_timeline.scss | 9 +- src/rawdata/scss/themes/dark/_variables.scss | 4 +- src/templates/mapping.go | 1 + src/templates/src/feed.html | 2 +- .../src/include/showcase_templates.html | 22 +- src/templates/src/include/timeline_item.html | 15 +- src/templates/src/landing.html | 246 ++++------------ src/templates/src/showcase.html | 139 ++------- src/templates/types.go | 1 + src/website/feed.go | 19 +- src/website/landing.go | 276 +++++------------- src/website/timeline_helper.go | 4 + src/website/user.go | 6 +- 18 files changed, 363 insertions(+), 687 deletions(-) diff --git a/public/js/showcase.js b/public/js/showcase.js index 30fe9ee6..d2a2e9e9 100644 --- a/public/js/showcase.js +++ b/public/js/showcase.js @@ -39,7 +39,7 @@ function makeShowcaseItem(timelineItem) { addThumbnailFunc = () => { itemEl.thumbnail.style.backgroundImage = `url('${timelineItem.thumbnail_url}')`; }; - + createModalContentFunc = () => { const modalImage = document.createElement('img'); modalImage.src = timelineItem.asset_url; @@ -81,7 +81,7 @@ function makeShowcaseItem(timelineItem) { break; // TODO(ben): Other snippet types? } - + let modalEl = null; itemEl.container.addEventListener('click', function() { if (!modalEl) { @@ -113,3 +113,106 @@ function makeShowcaseItem(timelineItem) { return [itemEl, doOnce(addThumbnailFunc)]; } +function initShowcaseContainer(container, items, rowHeight = 300, itemSpacing = 4) { + const addThumbnailFuncs = new Array(items.length); + + const itemElements = []; // array of arrays + for (let i = 0; i < items.length; i++) { + const item = items[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 = container.getBoundingClientRect().width; + container = emptyElement(container); + + function addRow(itemEls, rowWidth, container) { + const totalSpacing = itemSpacing * (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 = `${itemSpacing}px`; + + for (const itemEl of itemEls) { + const index = parseInt(itemEl.getAttribute('data-index'), 10); + const item = items[index]; + + const aspect = item.width / item.height; + const baseWidth = (aspect * rowHeight) * scaleFactor; + const actualWidth = baseWidth - (totalSpacing / itemEls.length); + + itemEl.style.width = `${actualWidth}px`; + itemEl.style.height = `${scaleFactor * rowHeight}px`; + itemEl.style.marginRight = `${itemSpacing}px`; + + row.appendChild(itemEl); + } + + container.appendChild(row); + } + + let rowItemEls = []; + let rowWidth = 0; + + for (const itemEl of itemElements) { + const index = parseInt(itemEl.getAttribute('data-index'), 10); + const item = items[index]; + + const aspect = item.width / item.height; + rowWidth += aspect * rowHeight; + + rowItemEls.push(itemEl); + + if (rowWidth > width) { + addRow(rowItemEls, rowWidth, container); + + rowItemEls = []; + rowWidth = 0; + } + } + + addRow(rowItemEls, rowWidth, container); + } + + function tryLoadImages() { + const OFFSCREEN_THRESHOLD = 0; + + const rect = container.getBoundingClientRect(); + const offscreen = ( + rect.bottom < -OFFSCREEN_THRESHOLD + || rect.top > window.innerHeight + OFFSCREEN_THRESHOLD + ); + + if (!offscreen) { + const items = container.querySelectorAll('.showcase-item'); + for (const item of items) { + const i = parseInt(item.getAttribute('data-index'), 10); + addThumbnailFuncs[i](); + } + } + } + + window.addEventListener('DOMContentLoaded', () => { + layout(); + layout(); // scrollbars are fun!! + tryLoadImages(); + }) + + window.addEventListener('resize', () => { + layout(); + tryLoadImages(); + }); + + window.addEventListener('scroll', () => { + tryLoadImages(); + }); +} diff --git a/public/style.css b/public/style.css index 5f86b88d..a8d4a9e0 100644 --- a/public/style.css +++ b/public/style.css @@ -7337,6 +7337,12 @@ article code { flex-grow: 1; flex-shrink: 1; } } +@media screen and (min-width: 60em) { + .flex-fair-l { + flex-basis: 1px; + flex-grow: 1; + flex-shrink: 1; } } + .b--theme { border-color: #666; border-color: var(--theme-color); } @@ -7397,6 +7403,10 @@ article code { background-color: #f8f8f8; background-color: var(--content-background); } +.bg--card { + background-color: #e8e8e8; + background-color: var(--card-background); } + .f8 { font-size: 0.65rem; } @@ -9016,66 +9026,21 @@ span.icon-rss::before { .chat #users .user { cursor: pointer; } -.landing .breadcrumb { - padding: 0px 3px; } - .landing .breadcrumb:first-child { - padding-left: 0px; } +.landing-layout { + display: grid; + gap: 1rem; } + .landing-layout > * { + overflow: hidden; } -.landing .more { - display: block; - margin-top: 10px; } - -.landing .contents { - margin-bottom: 20px; } - -.landing .showcase .arrow-container { - width: 60px; - position: absolute; - top: 0; - bottom: 0; - z-index: 2; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; } - .landing .showcase .arrow-container.left { - left: 0; - background-image: linear-gradient(to right, #f8f8f8 , rgba(0, 0, 0, 0)); - background-image: linear-gradient(to right, var(--content-background) , rgba(0, 0, 0, 0)); } - .landing .showcase .arrow-container.left svg { - transform: translateX(-0.05rem); } - .landing .showcase .arrow-container.right { - right: 0; - background-image: linear-gradient(to left, #f8f8f8 , rgba(0, 0, 0, 0)); - background-image: linear-gradient(to left, var(--content-background) , rgba(0, 0, 0, 0)); } - .landing .showcase .arrow-container.right svg { - transform: translateX(0.05rem); } - .landing .showcase .arrow-container.hide { - opacity: 0; - pointer-events: none; } - .landing .showcase .arrow-container .arrow { - background-color: #f8f8f8; - background-color: var(--content-background); - border-radius: 100%; - width: 2.4rem; - height: 2.4rem; - font-size: 1rem; - transition: opacity 40ms ease-in-out; - box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.2); - display: flex; - justify-content: center; - align-items: center; } - -.landing #showcase-items { - transition: transform 200ms ease-in-out; } - -.landing .showcase-item { - width: 7rem; - height: 7rem; } - @media screen and (min-width: 30em) { - .landing .showcase-item { - width: 10rem; - height: 10rem; } } +@media screen and (min-width: 60em) { + .landing-layout { + grid-template-columns: 1fr; + grid-auto-columns: 1fr; } + .landing-layout > * { + grid-column: 1 / 2; } + .landing-layout > *.landing-right { + grid-column: 2 / 3; + grid-row: 1 / 20; } } .star-btn { border-bottom-width: 2px; @@ -9341,8 +9306,12 @@ span.icon-rss::before { border-color: #666; border-color: var(--theme-color); } .timeline-item .avatar-icon.big { - width: 3.875rem; - height: 3.875rem; } + width: 3rem; + height: 3rem; } + @media screen and (min-width: 30em) { + .timeline-item .avatar-icon.big { + width: 3.875rem; + height: 3.875rem; } } .timeline-item .timeline-content-box > * { display: block; max-width: 100%; diff --git a/public/themes/dark/theme.css b/public/themes/dark/theme.css index 5a2b8fa6..40071c00 100644 --- a/public/themes/dark/theme.css +++ b/public/themes/dark/theme.css @@ -285,8 +285,8 @@ pre, code, .codeblock { --forum-diff-delete-border-color: #6b1e1c; --forum-diff-insert-background: #233a18; --forum-diff-insert-border-color: #30591b; - --card-background: #222; - --card-background-hover: #282828; + --card-background: #282828; + --card-background-hover: #333; --irc-border-color: #333; --irc-tab-current-shadow: 0px 0px 5px #000 inset; --irc-tab-close-button-color: #bbb; diff --git a/src/rawdata/scss/_core.scss b/src/rawdata/scss/_core.scss index 246b3e37..e1419e32 100644 --- a/src/rawdata/scss/_core.scss +++ b/src/rawdata/scss/_core.scss @@ -189,6 +189,14 @@ article code { } } +@media #{$breakpoint-large} { + .flex-fair-l { + flex-basis: 1px; + flex-grow: 1; + flex-shrink: 1; + } +} + .b--theme { @include usevar(border-color, theme-color); } @@ -249,6 +257,10 @@ article code { @include usevar(background-color, content-background); } +.bg--card { + @include usevar(background-color, card-background); +} + .f8 { font-size: 0.65rem; } diff --git a/src/rawdata/scss/_landing.scss b/src/rawdata/scss/_landing.scss index 7fd06a05..84ad89e1 100644 --- a/src/rawdata/scss/_landing.scss +++ b/src/rawdata/scss/_landing.scss @@ -1,86 +1,24 @@ -.landing { - .breadcrumb { - padding: 0px 3px; +.landing-layout { + display: grid; + gap: $spacing-medium; - &:first-child { - padding-left: 0px; - } + > * { + overflow: hidden; } +} - .more { - display: block; - margin-top: 10px; - } +@media #{$breakpoint-large} { + .landing-layout { + grid-template-columns: 1fr; + grid-auto-columns: 1fr; - .contents { - margin-bottom: 20px; - } + > * { + grid-column: 1 / 2; - .showcase { - .arrow-container { - width: 60px; - position: absolute; - top: 0; - bottom: 0; - z-index: 2; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - $svg-scoot: 0.05rem; - - &.left { - left: 0; - @include usevar(background-image, 'linear-gradient(to right, ' content-background ', rgba(0, 0, 0, 0))'); - - svg { - transform: translateX(-$svg-scoot); - } + &.landing-right { + grid-column: 2 / 3; + grid-row: 1 / 20; // increase this number if somehow you ever add that much garbage to the home page :) } - - &.right { - right: 0; - @include usevar(background-image, 'linear-gradient(to left, ' content-background ', rgba(0, 0, 0, 0))'); - - svg { - transform: translateX($svg-scoot); - } - } - - &.hide { - opacity: 0; - pointer-events: none; - } - - .arrow { - @include usevar(background-color, content-background); - border-radius: 100%; - width: 2.4rem; - height: 2.4rem; - font-size: 1rem; - transition: opacity 40ms ease-in-out; - box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.20); - - display: flex; - justify-content: center; - align-items: center; - } - } - } - - #showcase-items { - transition: transform 200ms ease-in-out; - } - - .showcase-item { - width: 7rem; - height: 7rem; - - @media #{$breakpoint-not-small} { - width: 10rem; - height: 10rem; } } } diff --git a/src/rawdata/scss/_timeline.scss b/src/rawdata/scss/_timeline.scss index 21ca4616..deb97b4e 100644 --- a/src/rawdata/scss/_timeline.scss +++ b/src/rawdata/scss/_timeline.scss @@ -8,8 +8,13 @@ @include usevar(border-color, theme-color); &.big { - width: px2rem(62px); - height: px2rem(62px); + width: 3rem; + height: 3rem; + + @media #{$breakpoint-not-small} { + width: px2rem(62px); + height: px2rem(62px); + } } } diff --git a/src/rawdata/scss/themes/dark/_variables.scss b/src/rawdata/scss/themes/dark/_variables.scss index da909697..3cb644ff 100644 --- a/src/rawdata/scss/themes/dark/_variables.scss +++ b/src/rawdata/scss/themes/dark/_variables.scss @@ -95,8 +95,8 @@ $vars: ( forum-diff-insert-background: #233a18, forum-diff-insert-border-color: #30591b, - card-background: #222, - card-background-hover: #282828, + card-background: #282828, + card-background-hover: #333, irc-border-color: #333, irc-tab-current-shadow: 0px 0px 5px #000 inset, diff --git a/src/templates/mapping.go b/src/templates/mapping.go index c1ec220b..e68cd56a 100644 --- a/src/templates/mapping.go +++ b/src/templates/mapping.go @@ -249,6 +249,7 @@ func TimelineItemsToJSON(items []TimelineItem) string { builder := strings.Builder{} builder.WriteRune('[') for i, item := range items { + if i > 0 { builder.WriteRune(',') } diff --git a/src/templates/src/feed.html b/src/templates/src/feed.html index 3646c085..c5c2baee 100644 --- a/src/templates/src/feed.html +++ b/src/templates/src/feed.html @@ -4,7 +4,7 @@
- 4 RSS Feed + 4 RSS Feed {{ if .User }}
{{ csrftoken .Session }} diff --git a/src/templates/src/include/showcase_templates.html b/src/templates/src/include/showcase_templates.html index b5d64ee5..3affda67 100644 --- a/src/templates/src/include/showcase_templates.html +++ b/src/templates/src/include/showcase_templates.html @@ -1,18 +1,20 @@ + +