rework sidenotes with pure css
This commit is contained in:
parent
ca903e2d15
commit
93ee753974
@ -9,6 +9,8 @@
|
||||
|
||||
<script>
|
||||
export let title, date;
|
||||
export const description = '';
|
||||
export const draft = false;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -18,6 +18,7 @@
|
||||
}
|
||||
|
||||
.sidenote {
|
||||
color: #555;
|
||||
font-size: 0.8rem;
|
||||
|
||||
&:before {
|
||||
@ -40,10 +41,15 @@
|
||||
}
|
||||
|
||||
.sidenote {
|
||||
position: absolute;
|
||||
left: calc(50vw + var(--content-width) / 2 + 1rem);
|
||||
max-width: 12rem;
|
||||
--gap: 2rem;
|
||||
--sidenote-width: min(14rem, calc(50vw - var(--gap) - var(--content-width) / 2));
|
||||
max-width: var(--sidenote-width);
|
||||
hyphens: auto;
|
||||
position: relative;
|
||||
float: right;
|
||||
clear: right;
|
||||
margin-right: calc(0rem - var(--sidenote-width) - var(--gap)); // gives us 2rem of space between content and sidenote
|
||||
margin-bottom: 0.7rem;
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,69 +97,29 @@
|
||||
</style>
|
||||
|
||||
<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;
|
||||
if (labelTop === 0) {
|
||||
// sometimes we get spurious results, only in dev mode though
|
||||
// I think it's related to hot module reloading
|
||||
return;
|
||||
}
|
||||
labelTop += 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);
|
||||
}
|
||||
var activeToggle = null;
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const id = Math.random().toString().slice(2);
|
||||
sidenotes[id] = {mounted: false};
|
||||
let label;
|
||||
let note;
|
||||
let toggle;
|
||||
|
||||
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();
|
||||
function toggleState() {
|
||||
if (activeToggle === toggle) {
|
||||
activeToggle = null;
|
||||
}
|
||||
|
||||
return () => sidenotes[id].mounted = false;
|
||||
});
|
||||
else if (activeToggle !== null) {
|
||||
activeToggle.checked = false;
|
||||
activeToggle = toggle;
|
||||
}
|
||||
else {
|
||||
activeToggle = toggle;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<label bind:this={label} for={id} class="counter"></label>
|
||||
<input type="checkbox" class="sidenote-toggle" {id}/>
|
||||
<span bind:this={note} class="sidenote">
|
||||
<label for={id} on:click={toggleState} class="counter"></label>
|
||||
<input {id} bind:this={toggle} type="checkbox" class="sidenote-toggle" />
|
||||
<span class="sidenote">
|
||||
<slot></slot>
|
||||
</span>
|
Loading…
x
Reference in New Issue
Block a user