Compare commits

..

4 Commits

4 changed files with 176 additions and 61 deletions

View File

@ -9,7 +9,8 @@
a { a {
/* Works better to set the size here for line-height reasons */ /* Works better to set the size here for line-height reasons */
font-size: 0.9em; font-size: 0.9em;
color: hsl(0, 0%, 50%); /* color: hsl(0, 0%, 25%); */
color: var(--accent-color);
} }
a:hover { a:hover {
@ -18,31 +19,45 @@
svg { svg {
width: 1em; width: 1em;
/* tiny tweak for optical alignment */
transform: translateY(2px);
} }
.before { .before {
display: none; display: none;
margin-right: 0.5rem; padding-right: 0.25em;
margin-left: calc(-1em - 0.5rem); margin-left: -1.25em;
} }
@media(min-width: 58rem) { @media(min-width: 58rem) {
.before { .before {
display: inline; display: inline;
opacity: 0;
transition: opacity 150ms;
} }
.h:hover .before, .before:hover {
opacity: 1;
}
.after { .after {
display: none; display: none;
} }
.h:hover {
cursor: default;
}
} }
</style> </style>
<svelte:element this={tag} {id} class="h"> <svelte:element this={tag} {id} class="h">
<a href="#{id}" class="before"> <span class="before">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> <a href="#{id}">
<path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244" /> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
</svg></a><span> <!-- Looks ugly but necessary to get rid of spurious whitespace --> <path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244" />
<slot></slot> </svg></a></span><span> <!-- Looks ugly but necessary to get rid of spurious whitespace -->
</span> <slot></slot>
</span>
<!-- Icon from https://heroicons.com/ --> <!-- Icon from https://heroicons.com/ -->
<a href="#{id}" class="after"> <a href="#{id}" class="after">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">

View File

@ -41,6 +41,42 @@
.post { .post {
grid-column: 2 / 3; grid-column: 2 / 3;
} }
.footer {
grid-column: 2 / 3;
margin-bottom: 2rem;
display: flex;
justify-content: space-between;
}
hr {
grid-column: 2 / 3;
width: 100%;
border-top: 1px solid hsl(0 0% 75%);
border-bottom: none;
margin: 2rem 0;
}
.footer a {
display: flex;
align-items: center;
gap: 1rem;
font-size: 0.9rem;
color: var(--content-color-faded);
text-decoration: none;
transition: 150ms;
will-change: transform;
}
.footer a:hover {
text-decoration: underline;
transform: scale(1.15);
}
.footer svg {
width: 1.5em;
}
</style> </style>
<svelte:head> <svelte:head>
@ -61,4 +97,22 @@
<div class="post"> <div class="post">
<slot></slot> <slot></slot>
</div> </div>
<hr>
<div class="footer">
<a href="#">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
</svg>
Previous
</a>
<a href="#">
Next
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3" />
</svg>
</a>
</div>
</div> </div>

View File

@ -1,4 +1,4 @@
<style lang="scss"> <style>
/* always applicable */ /* always applicable */
:global(body) { :global(body) {
counter-reset: sidenote; counter-reset: sidenote;
@ -8,30 +8,30 @@
counter-increment: sidenote; counter-increment: sidenote;
color: #444; color: #444;
margin-left: 0.05rem; margin-left: 0.05rem;
}
&:after { .counter:after {
font-size: 0.75em; font-size: 0.75em;
position: relative; position: relative;
bottom: 0.3rem; bottom: 0.3rem;
color: #8c0606; color: #8c0606;
}
} }
.sidenote { .sidenote {
color: #555; color: #555;
font-size: 0.8rem; font-size: 0.8rem;
}
&:before { .sidenote:before {
content: counter(sidenote) " "; content: counter(sidenote) " ";
/* absolute positioning puts it at the top-left corner of the sidenote, overlapping with the content /* absolute positioning puts it at the top-left corner of the sidenote, overlapping with the content
(because the sidenote is floated it counts as a positioned parent, I think) */ (because the sidenote is floated it counts as a positioned parent, I think) */
position: absolute; position: absolute;
/* translate moves it out to the left (and just a touch up to mimic the superscript efect) /* translate moves it out to the left (and just a touch up to mimic the superscript efect)
-100% refers to the width of the element, so it pushes it out further if necessary (i.e. two digits instead of one) */ -100% refers to the width of the element, so it pushes it out further if necessary (i.e. two digits instead of one) */
transform: translate(calc(-100% - 0.2rem), -0.15rem); transform: translate(calc(-100% - 0.2rem), -0.15rem);
font-size: 0.75rem; font-size: 0.75rem;
color: #8c0606; color: #8c0606;
}
} }
.sidenote-toggle { .sidenote-toggle {
@ -52,10 +52,22 @@
position: relative; position: relative;
float: right; float: right;
clear: right; clear: right;
margin-right: calc(0rem - var(--sidenote-width) - var(--gap)); // gives us 2rem of space between content and sidenote margin-right: calc(0rem - var(--sidenote-width) - var(--gap)); /* gives us 2rem of space between content and sidenote */
margin-bottom: 0.7rem; margin-bottom: 0.7rem;
} }
/* fade-in animation */
.sidenote {
opacity: 0;
animation: fade-in 600ms ease-out;
animation-delay: 500ms;
animation-fill-mode: forwards;
}
@keyframes fade-in {
from {opacity: 0;}
to {opacity: 1;}
}
.nested.sidenote { .nested.sidenote {
margin-right: 0; margin-right: 0;
margin-top: 0.7rem; margin-top: 0.7rem;
@ -107,11 +119,10 @@
font-size: 1.25rem; font-size: 1.25rem;
color: #8c0606; color: #8c0606;
cursor: pointer; cursor: pointer;
}
&:hover { .dismiss:hover {
transform: scale(1.1); transform: scale(1.1);
font-weight: 800; font-weight: 800;
}
} }
} }

View File

@ -6,31 +6,43 @@
items.forEach(i => i.slug = makeSlug(i.text)); items.forEach(i => i.slug = makeSlug(i.text));
const selector = 'h1[id], h2[id], h3[id], h4[id], h6[id]'; let headings = [];
let currentHeadingSlug = null; let currentHeadingSlug = null;
let currentSubheadingSlug = null;
function setCurrentHeading() { function setCurrentHeading() {
for (const h of document.querySelectorAll(selector)) { const start = performance.now();
for (const h of headings) {
const yPos = h.getBoundingClientRect().y; const yPos = h.getBoundingClientRect().y;
if (yPos > (window.innerHeight / 3)) { if (yPos > (window.innerHeight / 3)) {
break; break;
} }
currentHeadingSlug = h.id; if (h.tagName === 'H2') {
currentHeadingSlug = h.id;
currentSubheadingSlug = null;
}
if (h.tagName === 'H3') {
currentSubheadingSlug = h.id
}
} }
const end = performance.now();
console.log(`Elapsed: ${end - start}`);
} }
onMount (() => { onMount (() => {
document.addEventListener('scroll', setCurrentHeading); // These shouldn't change over the life of the page, so we can cache them
headings = Array.from(document.querySelectorAll('h2[id], h3[id]'));
setCurrentHeading(); setCurrentHeading();
}); });
</script> </script>
<svelte:window on:scroll={setCurrentHeading} />
<style> <style>
/* move everything out to the left and center it vertically */
#toc { #toc {
position: sticky; position: sticky;
top: 1.5rem; top: 1.5rem;
margin-right: 4rem; margin-right: 2rem;
max-width: 14rem; max-width: 14rem;
color: var(--content-color-faded); color: var(--content-color-faded);
@ -42,7 +54,7 @@
@keyframes fade-in { @keyframes fade-in {
from {opacity: 0} from {opacity: 0}
to {opacity: 100%} to {opacity: 1}
} }
/* margin-left is to match the padding on the top-level list items, /* margin-left is to match the padding on the top-level list items,
@ -53,14 +65,12 @@
max-width: fit-content; max-width: fit-content;
margin-top: 0; margin-top: 0;
/* 0.5rem for indent, 0.1rem for border */
margin-left: 0.6rem;
margin-bottom: 0.25em; margin-bottom: 0.25em;
padding-right: 1.5rem;
padding-bottom: 0.25em; padding-bottom: 0.25em;
border-bottom: 1px solid currentcolor; border-bottom: 1px solid currentcolor;
/* make the border stretch beyond the text just a bit, because I like the effect */
padding-right: 1.5rem;
} }
ul { ul {
@ -69,22 +79,42 @@
list-style: none; list-style: none;
} }
/* margin for indentation, padding so that the accent bar for the current
item isn't right on top of it */
li { li {
margin-left: var(--indent, 0); position: relative;
padding-left: 0.5rem;
margin-bottom: 0.15rem;
font-size: 0.9rem; font-size: 0.9rem;
border-left: 0.1rem solid transparent;
} }
li:hover { li.depth-2 {
color: var(--content-color); align-items: stretch;
border-left: 0.1rem solid var(--accent-color); margin-bottom: 0.2rem;
} }
li.current { li.depth-3 {
align-items: center;
margin-bottom: 0.05rem;
}
.marker {
position: absolute;
left: -0.6rem;
}
.bar {
width: 0.1rem;
height: 100%;
}
.dot {
width: 0.15rem;
height: 0.15rem;
border-radius: 50%;
/* vertically center within its containing block */
top: 0;
bottom: 0;
margin: auto 0;
}
li.current, li:hover {
color: var(--content-color); color: var(--content-color);
border-left: 0.1rem solid var(--accent-color); }
.current .marker, li:hover .marker {
background-color: var(--accent-color);
} }
a { a {
@ -100,12 +130,17 @@
</h5> </h5>
<ul> <ul>
{#each items as item} {#each items as item}
<li {#if item.depth === 2}
style:--indent="{(item.depth - 2) * 0.75}em" <li class="depth-2" class:current={item.slug === currentHeadingSlug} style:align-items="stretch">
class:current={item.slug === currentHeadingSlug} <span class="marker bar"></span>
> <a href="#{item.slug}">{item.text}</a>
<a href="#{item.slug}">{item.text}</a> </li>
</li> {:else if item.depth === 3}
<li class="depth-3" class:current={item.slug === currentSubheadingSlug} style:align-items="center" style:margin-left="0.75em">
<span class="marker dot"></span>
<a href="#{item.slug}">{item.text}</a>
</li>
{/if}
{/each} {/each}
</ul> </ul>
</div> </div>