Compare commits
4 Commits
5817d94043
...
3a59f45e58
Author | SHA1 | Date | |
---|---|---|---|
3a59f45e58 | |||
0519291bda | |||
d1aa23e7c7 | |||
25ce1b2d85 |
@ -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">
|
||||||
|
@ -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>
|
@ -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;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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>
|
Loading…
x
Reference in New Issue
Block a user