diff options
-rw-r--r-- | src/data/things/group.js | 4 | ||||
-rw-r--r-- | src/data/yaml.js | 2 | ||||
-rw-r--r-- | src/misc-templates.js | 55 | ||||
-rw-r--r-- | src/page/group.js | 8 | ||||
-rw-r--r-- | src/static/site2.css | 28 |
5 files changed, 91 insertions, 6 deletions
diff --git a/src/data/things/group.js b/src/data/things/group.js index 26fe9a55..111d6715 100644 --- a/src/data/things/group.js +++ b/src/data/things/group.js @@ -17,6 +17,8 @@ export class Group extends Thing { urls: Thing.common.urls(), + featuredAlbumsByRef: Thing.common.referenceList(Album), + // Update only albumData: Thing.common.wikiData(Album), @@ -24,6 +26,8 @@ export class Group extends Thing { // Expose only + featuredAlbums: Thing.common.dynamicThingsFromReferenceList('featuredAlbumsByRef', 'albumData', find.album), + descriptionShort: { flags: {expose: true}, diff --git a/src/data/yaml.js b/src/data/yaml.js index f967cee3..a5a0e798 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -356,6 +356,8 @@ export const processGroupDocument = makeProcessDocument(T.Group, { directory: 'Directory', description: 'Description', urls: 'URLs', + + featuredAlbumsByRef: 'Featured Albums', }, }); diff --git a/src/misc-templates.js b/src/misc-templates.js index 7887dcbd..71c62883 100644 --- a/src/misc-templates.js +++ b/src/misc-templates.js @@ -642,6 +642,48 @@ function unbound_getFlashGridHTML({ // Carousel reels +// Layout constants: +// +// Carousels support fitting 4-18 items, with a few "dead" zones to watch out +// for, namely when a multiple of 6, 5, or 4 columns would drop the last tiles. +// +// Carousels are limited to 1-3 rows and 4-6 columns. +// Lower edge case: 1-3 items are treated as 4 items (with blank space). +// Upper edge case: all items past 18 are dropped (treated as 18 items). +// +// This is all done through JS instead of CSS because it's just... ANNOYING... +// to write a mapping like this in CSS lol. +const carouselLayoutMap = [ + // 0-3 + null, null, null, null, + + // 4-6 + {rows: 1, columns: 4}, // 4: 1x4, drop 0 + {rows: 1, columns: 5}, // 5: 1x5, drop 0 + {rows: 1, columns: 6}, // 6: 1x6, drop 0 + + // 7-12 + {rows: 1, columns: 6}, // 7: 1x6, drop 1 + {rows: 2, columns: 4}, // 8: 2x4, drop 0 + {rows: 2, columns: 4}, // 9: 2x4, drop 1 + {rows: 2, columns: 5}, // 10: 2x5, drop 0 + {rows: 2, columns: 5}, // 11: 2x5, drop 1 + {rows: 2, columns: 6}, // 12: 2x6, drop 0 + + // 13-18 + {rows: 2, columns: 6}, // 13: 2x6, drop 1 + {rows: 2, columns: 6}, // 14: 2x6, drop 2 + {rows: 3, columns: 5}, // 15: 3x5, drop 0 + {rows: 3, columns: 5}, // 16: 3x5, drop 1 + {rows: 3, columns: 5}, // 17: 3x5, drop 2 + {rows: 3, columns: 6}, // 18: 3x6, drop 0 +]; + +const minCarouselLayoutItems = carouselLayoutMap.findIndex(x => x !== null); +const maxCarouselLayoutItems = carouselLayoutMap.length - 1; +const shortestCarouselLayout = carouselLayoutMap[minCarouselLayoutItems]; +const longestCarouselLayout = carouselLayoutMap[maxCarouselLayoutItems]; + function unbound_getCarouselHTML({ html, img, @@ -653,11 +695,24 @@ function unbound_getCarouselHTML({ linkFn = (x, {text}) => text, srcFn, }) { + if (empty(items)) { + return; + } + + const {rows, columns} = ( + items.length < minCarouselLayoutItems ? shortestCarouselLayout : + items.length > maxCarouselLayoutItems ? longestCarouselLayout : + carouselLayoutMap[items.length]); + + items = items.slice(0, maxCarouselLayoutItems + 1); + return (x => x)(html.tag('div', {class: 'carousel-container'}, repeat(3, html.tag('div', { class: 'carousel-grid', + 'data-carousel-rows': rows, + 'data-carousel-columns': columns, 'aria-hidden': 'true', }, items diff --git a/src/page/group.js b/src/page/group.js index 429097f8..26230b45 100644 --- a/src/page/group.js +++ b/src/page/group.js @@ -129,7 +129,9 @@ export function write(group, {wikiData}) { page: ({ generateInfoGalleryLinks, generateNavigationLinks, + getAlbumCover, getAlbumGridHTML, + getCarouselHTML, getLinkThemeString, getThemeString, html, @@ -149,6 +151,12 @@ export function write(group, {wikiData}) { group: group.name, })), + getCarouselHTML({ + items: group.featuredAlbums.slice(0, 12 + 1), + srcFn: getAlbumCover, + linkFn: link.album, + }), + html.tag('p', {class: 'quick-info'}, language.$('groupGalleryPage.infoLine', { diff --git a/src/static/site2.css b/src/static/site2.css index fe90d4de..86b815d2 100644 --- a/src/static/site2.css +++ b/src/static/site2.css @@ -943,17 +943,22 @@ img { } .carousel-grid { + --carousel-tile-min-width: 120px; + --carousel-row-count: 3; + --carousel-column-count: 6; + + /* Thanks to: https://css-tricks.com/an-auto-filling-css-grid-with-max-columns/ */ + --carousel-gap-count: calc(var(--carousel-column-count) - 1); + --carousel-total-gap-width: calc(var(--carousel-gap-count) * 10px); + --carousel-calculated-tile-max-width: calc((100% - var(--carousel-total-gap-width)) / var(--carousel-column-count)); + display: grid; - grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); - grid-template-rows: repeat(2, auto); + grid-template-columns: repeat(auto-fill, minmax(max(var(--carousel-tile-min-width), var(--carousel-calculated-tile-max-width)), 1fr)); + grid-template-rows: repeat(var(--carousel-row-count), auto); grid-auto-flow: dense; grid-auto-rows: 0; overflow: hidden; margin: auto; - flex-wrap: wrap; - justify-content: center; - align-items: flex-start; - z-index: 1; transform: translateX(0); animation: carousel-marquee1 40s linear infinite; @@ -961,6 +966,17 @@ img { z-index: 5; } +html[data-url-key="localized.home"] .carousel-grid { + --carousel-tile-size: 140px; +} + +.carousel-grid[data-carousel-rows="1"] { --carousel-row-count: 1; } +.carousel-grid[data-carousel-rows="2"] { --carousel-row-count: 2; } +.carousel-grid[data-carousel-rows="3"] { --carousel-row-count: 3; } +.carousel-grid[data-carousel-columns="4"] { --carousel-column-count: 4; } +.carousel-grid[data-carousel-columns="5"] { --carousel-column-count: 5; } +.carousel-grid[data-carousel-columns="6"] { --carousel-column-count: 6; } + .carousel-item { display: inline-block; margin: 0; |