Use CSS grids instead of JS Gridify.

This commit is contained in:
Syfaro 2019-09-02 12:06:50 -05:00
parent f908050843
commit 393c0495de
4 changed files with 51 additions and 141 deletions

View File

@ -13,13 +13,13 @@
<section class="artwork">
<h3>Artwork</h3>
<div class="grid" id="art">
<div id="art">
{{ partial "char/grid.html" (dict "ctx" . "type" "artwork") }}
</div>
<h3>Icons</h3>
<div class="grid" id="icons">
<div id="icons">
{{ partial "char/grid.html" (dict "ctx" . "type" "icon") }}
</div>
</section>

View File

@ -1,41 +1,47 @@
{{ $size := "200x" }}
{{ $retSize := "400x" }}
{{ $gridClass := "grid-200" }}
{{ if eq .type "artwork" }}
{{ $size = "400x" }}
{{ $retSize = "800x" }}
{{ $gridClass = "grid-400" }}
{{ end }}
{{ range .ctx.Pages }}
{{ $page := . }}
{{ range .Resources.ByType "image" }}
{{ $shouldDisplay := false }}
<div class="artwork-grid {{ $gridClass }}">
{{ range .ctx.Pages }}
{{ $page := . }}
{{ range .Resources.ByType "image" }}
{{ $shouldDisplay := false }}
{{ if and .Params.icon (eq $.type "icon") }}
{{ $shouldDisplay = true }}
{{ end }}
{{ if and (not .Params.icon) (eq $.type "artwork") }}
{{ $shouldDisplay = true }}
{{ end }}
{{ if $shouldDisplay }}
{{ $reg := .Resize $size }}
{{ $ret := .Resize $retSize }}
{{ $link := .Params.source }}
{{ if not $link }}
{{ $link = $page.Params.link }}
{{ if and .Params.icon (eq $.type "icon") }}
{{ $shouldDisplay = true }}
{{ end }}
<a
href="{{ $link }}"
{{ if .Params.message }} data-message="{{ .Params.message }}" {{ end }}
{{ if .Params.nsfw }} class="nsfw" {{ end }}
>
<img
src="{{ $reg.RelPermalink }}"
srcset="{{ $reg.RelPermalink }} 1x, {{ $ret.RelPermalink }} 2x">
</a>
{{ if and (not .Params.icon) (eq $.type "artwork") }}
{{ $shouldDisplay = true }}
{{ end }}
{{ if $shouldDisplay }}
{{ $reg := .Resize $size }}
{{ $ret := .Resize $retSize }}
{{ $link := .Params.source }}
{{ if not $link }}
{{ $link = $page.Params.link }}
{{ end }}
<div class="grid-item">
<a
href="{{ $link }}"
{{ if .Params.message }} data-message="{{ .Params.message }}" {{ end }}
{{ if .Params.nsfw }} class="nsfw" {{ end }}
>
<img
src="{{ $reg.RelPermalink }}"
srcset="{{ $reg.RelPermalink }} 1x, {{ $ret.RelPermalink }} 2x">
</a>
</div>
{{ end }}
{{ end }}
{{ end }}
{{ end }}
</div>

View File

@ -1,124 +1,14 @@
class Gridify {
constructor(node, opts = {}) {
this.node = node;
this.opts = opts;
this.node.style.position = 'relative';
window.addEventListener('resize', this.render.bind(this));
this.imagesLoaded().then(this.render.bind(this));
}
imagesLoaded() {
return new Promise((resolve, reject) => {
const images = this.node.querySelectorAll('img');
let count = images.length;
if (count === 0)
resolve();
let loaded = ev => {
count--;
if (count === 0)
resolve();
};
images.forEach(image => {
const img = new Image();
img.addEventListener('load', loaded);
img.addEventListener('error', loaded);
img.src = image.src;
});
});
}
render() {
const items = Array.from(this.node.querySelectorAll(this.opts['srcNode'])).filter(item => !item.parentNode.classList.contains('nsfw'));
const transition = (this.opts['transition'] || 'all 0.5s ease') + ', height 0s, width 0s';
const width = this.node.clientWidth;
const itemMargin = parseInt(this.opts['margin'], 10) || 0;
const itemWidth = parseInt(this.opts['width'] || 200, 10);
const columnCount = Math.max(Math.floor(width / (itemWidth + itemMargin)), 1);
const left = columnCount === 1 ? itemMargin / 2 : (width % (itemWidth + itemMargin)) / 2;
let columns = [];
for (let i = 0; i < columnCount; i++) {
columns.push(0);
}
items.forEach(item => {
const idx = Gridify.indexOfSmallest(columns);
const style = item.style;
style.position = 'absolute';
style.width = itemWidth + 'px';
style.margin = (itemMargin / 2) + 'px';
style.top = (columns[idx] + itemMargin / 2) + 'px';
style.left = ((itemWidth + itemMargin) * idx + left) + 'px';
style.transition = transition;
columns[idx] += item.clientHeight + itemMargin;
});
this.node.style.height = Gridify.highestColumn(columns) + 'px';
if (this.opts['onRender']) {
this.opts['onRender']();
}
}
static indexOfSmallest(a) {
let lowest = 0;
for (let i = 1, length = a.length; i < length; i++) {
if (a[i] < a[lowest])
lowest = i;
}
return lowest;
}
static highestColumn(cols) {
let highest = 0;
for (let i = 0, length = cols.length; i < length; i++) {
if (cols[i] > highest)
highest = cols[i];
}
return highest;
}
}
;
const gridArt = document.querySelector('#art');
const show = document.querySelector('.reveal');
const hidden = document.querySelectorAll('.nsfw');
let screenWidth = 0;
const urlParams = window.location.hash.slice(1).toLowerCase().split(',');
const needsToScroll = urlParams.includes('art');
let hasScrolled = false;
function updateWidth() {
const element = document.documentElement;
screenWidth = Math.max(element.clientWidth, element.offsetWidth, element.scrollWidth);
window.requestAnimationFrame(() => updateGrid());
}
updateWidth();
function getItemWidth(big) {
return big ? 400 : 200;
}
function updateGrid() {
if (screenWidth <= 450) {
return;
}
new Gridify(gridArt, {
srcNode: 'img',
margin: '16px',
width: getItemWidth(true).toString() + 'px',
onRender: () => {
if (needsToScroll && !hasScrolled) {
gridArt.scrollIntoView();
hasScrolled = true;
}
}
});
new Gridify(document.querySelector('#icons'), {
srcNode: 'img',
margin: '8px',
width: getItemWidth(false).toString() + 'px'
});
}
function revealNSFW(ev) {
if (ev) {
ev.preventDefault();
}
hidden.forEach(item => item.classList.remove('nsfw'));
updateGrid();
show.classList.add('nsfw');
}
show.addEventListener('click', revealNSFW);
window.addEventListener('load', updateGrid);
window.addEventListener('resize', updateWidth);
if (urlParams.includes('nsfw')) {
revealNSFW(null);
}

View File

@ -292,6 +292,20 @@ section.char-desc li:not(:first-child) {
padding-top: 8px;
}
.artwork-grid {
column-gap: 2px;
}
.artwork-grid.grid-200 {
columns: 12 200px;
grid-auto-columns: 200px;
}
.artwork-grid.grid-400 {
columns: 6 400px;
grid-auto-columns: 400px;
}
.peppershrike {
width: 100%;
background-color: #eadef6;