rework front page to have shuffle and lazy infinite scroll
This commit is contained in:
parent
9729f45842
commit
b75bad995a
|
@ -315,6 +315,7 @@ def generate(args):
|
|||
list_template = jenv.get_template("list.html")
|
||||
categorization_template = jenv.get_template("categorization.html")
|
||||
work_template = jenv.get_template("work.html")
|
||||
index_template = jenv.get_template("index.html")
|
||||
|
||||
con = sqlite3.connect(args.destdir / 'meta.db')
|
||||
cur = con.cursor()
|
||||
|
@ -408,7 +409,7 @@ def generate(args):
|
|||
copy_recursive(r / 'static', args.destdir / 'site' / 'static')
|
||||
|
||||
with open(args.destdir / 'site' / 'index.html', 'w') as f:
|
||||
f.write(list_template.render(depth=0, works=works))
|
||||
f.write(index_template.render(depth=0, works=works))
|
||||
|
||||
con.close()
|
||||
|
||||
|
|
|
@ -5,9 +5,56 @@ body {
|
|||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* index stuff */
|
||||
|
||||
#top {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: end;
|
||||
gap: 40px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
#top .nav {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
#top-padding, #controls {
|
||||
flex-grow: 1;
|
||||
flex-basis: 0;
|
||||
}
|
||||
|
||||
@media all and (max-width: 600px) {
|
||||
#top {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
}
|
||||
#top .nav {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
#controls button {
|
||||
position: relative;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 5px 2px;
|
||||
}
|
||||
|
||||
#controls button img {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -20px 0 0 -20px;
|
||||
}
|
||||
|
||||
/* listing stuff */
|
||||
|
||||
#title, nav {
|
||||
#title, .nav {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
@ -20,7 +67,7 @@ body {
|
|||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.card-listing {
|
||||
#card-listing {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
|
|
12
dlibrary/static/icons/shuffle.svg
Normal file
12
dlibrary/static/icons/shuffle.svg
Normal file
|
@ -0,0 +1,12 @@
|
|||
<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='180' height='180' viewBox='-40 -40 180 180'>
|
||||
<defs>
|
||||
<clipPath id="crossing">
|
||||
<path d='M -30 40 L -10 40 C 65 40 25 140 100 140 L 120 140 L -30 140 Z'/>
|
||||
<path d='M -20 -40 L -10 -40 C 65 -40 25 60 100 60 L 130 60 L 130 -40 Z'/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<path d='M -20 0 L -10 0 C 65 0 25 100 100 100 L 120 100' fill='none' stroke='#ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='10'/>
|
||||
<path d='M -20 100 L -10 100 C 65 100 25 0 100 0 L 120 0' fill='none' clip-path='url(#crossing)' stroke='#ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='10'/>
|
||||
<path d='M 105 85 L 120 100 L 105 115' fill='none' stroke='#ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='10'/>
|
||||
<path d='M 105 -15 L 120 0 L 105 15' fill='none' stroke='#ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='10'/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
6
dlibrary/static/icons/sort.svg
Normal file
6
dlibrary/static/icons/sort.svg
Normal file
|
@ -0,0 +1,6 @@
|
|||
<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='180' height='180' viewBox='-20 -20 180 180'>
|
||||
<path d='M 30 0 L 30 140' fill='none' stroke='#ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='10'/>
|
||||
<path d='M 0 110 L 30 140 L 60 110' fill='none' stroke='#ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='10'/>
|
||||
<path d='M 110 0 L 110 140' fill='none' stroke='#ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='10'/>
|
||||
<path d='M 80 30 L 110 0 L 140 30' fill='none' stroke='#ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='10'/>
|
||||
</svg>
|
After Width: | Height: | Size: 765 B |
117
dlibrary/static/index.js
Normal file
117
dlibrary/static/index.js
Normal file
|
@ -0,0 +1,117 @@
|
|||
const LCG_M = Math.pow(2, 32);
|
||||
const LCG_A = 0xd9f5;
|
||||
const LCG_C = 69;
|
||||
|
||||
function lcg(seed) {
|
||||
let value = seed % LCG_M;
|
||||
|
||||
return (n) => {
|
||||
value = (LCG_A * value + LCG_C) % LCG_M;
|
||||
return Math.floor(n * value / LCG_M);
|
||||
};
|
||||
}
|
||||
|
||||
function seedableShuffledCopy(list, seed) {
|
||||
const gen = lcg(seed);
|
||||
const l = [...list];
|
||||
|
||||
for (let i = 0; i < l.length - 1; ++i) {
|
||||
j = i + gen(l.length - i);
|
||||
const tmp = l[i];
|
||||
l[i] = l[j];
|
||||
l[j] = tmp;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
function newSeed() {
|
||||
return Math.floor(Math.random() * LCG_M);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const shuffleButton = document.getElementById('shuffle');
|
||||
const sortButton = document.getElementById('sort');
|
||||
const listContainer = document.getElementById('card-listing');
|
||||
let ordering = localStorage.getItem('indexOrdering') || 'dateDesc';
|
||||
|
||||
let orderedWorks;
|
||||
|
||||
function scrollHandler() {
|
||||
while (orderedWorks.length > 0 && listContainer.clientHeight - window.scrollY < 5000) {
|
||||
const work = orderedWorks.shift();
|
||||
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card';
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = `${ROOT}/works/${work.id}/${INDEX}`;
|
||||
card.appendChild(link);
|
||||
|
||||
const thumb = document.createElement('img');
|
||||
thumb.src = `${ROOT}/thumbnails/${work.id}.jpg`;
|
||||
link.appendChild(thumb);
|
||||
|
||||
const creators = document.createElement('div');
|
||||
creators.className = 'card-creators';
|
||||
let creatorsInfo = `[${work.circle || ''}`;
|
||||
if (work.authors) {
|
||||
let authorList = work.authors[0];
|
||||
for (let i = 1; i < work.authors.length; ++i) {
|
||||
authorList += `, ${work.authors[i]}`;
|
||||
}
|
||||
creatorsInfo += (work.circle ? ` (${authorList})]` : `${authorList}]`);
|
||||
}
|
||||
creators.textContent = creatorsInfo;
|
||||
link.appendChild(creators);
|
||||
|
||||
const title = document.createElement('div');
|
||||
title.className = 'card-title';
|
||||
title.textContent = work.title;
|
||||
link.appendChild(title);
|
||||
|
||||
listContainer.appendChild(card);
|
||||
}
|
||||
}
|
||||
|
||||
function applyOrdering() {
|
||||
listContainer.replaceChildren();
|
||||
scrollHandler();
|
||||
}
|
||||
|
||||
switch (ordering) {
|
||||
case 'shuffle':
|
||||
let seed = parseInt(localStorage.getItem('shuffleSeed')) || newSeed();
|
||||
orderedWorks = seedableShuffledCopy(WORKS, seed);
|
||||
break;
|
||||
case 'dateAsc':
|
||||
orderedWorks = WORKS.toReversed();
|
||||
break;
|
||||
default:
|
||||
orderedWorks = [...WORKS];
|
||||
break;
|
||||
}
|
||||
applyOrdering();
|
||||
|
||||
window.addEventListener('scroll', scrollHandler);
|
||||
|
||||
document.getElementById('shuffle').onclick = () => {
|
||||
let seed = newSeed();
|
||||
localStorage.setItem('shuffleSeed', seed);
|
||||
ordering = 'shuffle';
|
||||
localStorage.setItem('indexOrdering', ordering);
|
||||
|
||||
orderedWorks = seedableShuffledCopy(WORKS, seed);
|
||||
applyOrdering();
|
||||
};
|
||||
document.getElementById('sort').onclick = () => {
|
||||
if (ordering === 'dateDesc') {
|
||||
ordering = 'dateAsc';
|
||||
orderedWorks = WORKS.toReversed();
|
||||
} else {
|
||||
ordering = 'dateDesc';
|
||||
orderedWorks = [...WORKS];
|
||||
}
|
||||
localStorage.setItem('indexOrdering', ordering);
|
||||
applyOrdering();
|
||||
};
|
||||
});
|
|
@ -4,7 +4,7 @@
|
|||
{% from 'utils.html' import urlcat, index, root with context %}
|
||||
<h1 id="title"><a href="{{ root() }}/{{ index() }}">DLibrary</a> > {{ categorization.capitalize() }}</h1>
|
||||
{% include 'nav.html' %}
|
||||
<div class="card-listing">
|
||||
<div id="card-listing">
|
||||
{% for cat in categories %}
|
||||
<div class="card {% if not work_style_cards %}category{% endif %}">
|
||||
<a href="{{ urlcat(cat) }}/{{ index() }}">
|
||||
|
|
25
dlibrary/templates/index.html
Normal file
25
dlibrary/templates/index.html
Normal file
|
@ -0,0 +1,25 @@
|
|||
{% extends 'base.html' %}
|
||||
{% from 'utils.html' import index, root with context %}
|
||||
{% block head %}
|
||||
<script>
|
||||
const ROOT = "{{ root() }}";
|
||||
const INDEX = "{{ index() }}";
|
||||
const WORKS = {{ works | tojson }};
|
||||
</script>
|
||||
<script src="{{ root() }}/static/index.js"></script>
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<div id="top">
|
||||
<div id="top-padding"></div>
|
||||
<div id="header">
|
||||
<h1 id="title"><a href="{{ root() }}/{{ index() }}">DLibrary</a></h1>
|
||||
{% include 'nav.html' %}
|
||||
</div>
|
||||
<div id="controls">
|
||||
<button id="shuffle" name="Shuffle"><img src="{{ root() }}/static/icons/shuffle.svg"/></button>
|
||||
<button id="sort" name="Sort"><img src="{{ root() }}/static/icons/sort.svg"/></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="card-listing">
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -3,12 +3,12 @@
|
|||
{% from 'utils.html' import index, root with context %}
|
||||
<h1 id="title"><a href="{{ root() }}/{{ index() }}">DLibrary</a>{% if categorization %} > <a href="{{ root() }}/{{ categorization }}/{{ index() }}">{{ categorization.capitalize() }}</a>{% endif %}{% if title %} > {{ title }}{% endif %}</h1>
|
||||
{% include 'nav.html' %}
|
||||
<div class="card-listing">
|
||||
<div id="card-listing">
|
||||
{% for work in works %}
|
||||
<div class="card">
|
||||
<a href="{{ root() }}/works/{{ work['id'] }}/{{ index() }}">
|
||||
<img src="{{ root() }}/thumbnails/{{ work['id'] }}.jpg">
|
||||
<div class="card-authors">
|
||||
<div class="card-creators">
|
||||
[{% if work['circle'] %}{{ work['circle'] }}{% endif %}{% if work['circle'] and work['authors'] %} ({% endif %}{{ ', '.join(work['authors']) }}{% if work['circle'] and work['authors'] %}){% endif %}]
|
||||
</div>
|
||||
<div class="card-title">
|
||||
|
|
Loading…
Reference in a new issue