move all sidenote logic to Sidenote component

This commit is contained in:
Joseph Montanaro 2022-05-14 11:18:11 -07:00
parent 4658511759
commit 3413b7ae7e
2 changed files with 57 additions and 41 deletions

View File

@ -2,53 +2,18 @@
import { onMount } from 'svelte';
import { formatDate } from './datefmt.js';
import { makeSlug } from '$lib/slug.js';
import Link from './Link.svelte';
export { Link as a };
</script>
<script>
export let title, date;
// deal with sidenote collisions
function tileNotes() {
const minNoteGap = 15;
// let sidenotes = Array.from(document.getElementsByClassName('sidenote'));
let notes = document.querySelectorAll('.sidenote');
if (window.getComputedStyle(notes[0]).position === 'fixed') {
// fixed position means we are in mobile territory, so
// get rid of the overflow stuff and then exit
for (let note of notes) {
note.style.top = '';
}
return;
}
let labels = document.querySelectorAll('label.counter');
var prev = 0;
for (var i=0; i < notes.length; i++) {
let labelTop = labels[i].getBoundingClientRect().y + window.scrollY;
let noteHeight = notes[i].getBoundingClientRect().height;
if (labelTop < prev + minNoteGap) {
// there is a collision
notes[i].style.top = `${prev + minNoteGap}px`;
prev = prev + minNoteGap + noteHeight;
}
else {
// no collision
notes[i].style.top = `${labelTop}px`;
prev = labelTop + noteHeight;
}
}
}
onMount(async () => {
tileNotes();
window.addEventListener('resize', tileNotes);
});
</script>
<svelte:head>
<title>{title}</title>
<link rel="stylesheet" href="/prism-dracula.css" />
</svelte:head>
<div id="post">

View File

@ -87,12 +87,63 @@
}
</style>
<script>
let id = Math.random().toString().slice(2);
<script context="module">
import { browser } from '$app/env';
var sidenotes = {};
function tileNotes() {
// find and fix collisions between sidenotes
const minNoteGap = 15;
var prevBottom = 0;
Object.values(sidenotes).forEach(s => {
if (window.getComputedStyle(s.note).position === 'fixed') {
// fixed position means we are in mobile territory,
// so get rid of the overflow stuff
s.note.style.top = '';
return;
}
let labelTop = s.label.getBoundingClientRect().y + window.scrollY;
let noteHeight = s.note.getBoundingClientRect().height;
if (labelTop < prevBottom + minNoteGap) {
// there is a collision
s.note.style.top = `${prevBottom + minNoteGap}px`;
prevBottom = prevBottom + minNoteGap + noteHeight;
}
else {
// no collision, but these don't quite match otherwise
s.note.style.top = `${labelTop}px`;
prevBottom = labelTop + noteHeight;
}
})
}
if (browser) {
window.addEventListener('resize', tileNotes);
}
</script>
<label for={id} class="counter"></label>
<script>
import { onMount } from 'svelte';
const id = Math.random().toString().slice(2);
sidenotes[id] = {mounted: false};
let label;
let note;
onMount(async () => {
sidenotes[id] = {mounted: true, label, note};
if (Object.values(sidenotes).every(n => n.mounted)) {
// all sidenotes have been mounted, now we can fix the collisions
tileNotes();
}
return () => sidenotes[id].mounted = false;
});
</script>
<label bind:this={label} for={id} class="counter"></label>
<input type="checkbox" class="sidenote-toggle" {id}/>
<span class="sidenote">
<span bind:this={note} class="sidenote">
<slot></slot>
</span>