rework layout and add table of contents
This commit is contained in:
parent
33d6838dc4
commit
5817d94043
41
package-lock.json
generated
41
package-lock.json
generated
@ -11,6 +11,7 @@
|
||||
"@sveltejs/adapter-static": "^1.0.0-next.21",
|
||||
"@sveltejs/kit": "next",
|
||||
"hast-util-to-text": "^3.1.2",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
"mdsvex": "^0.9.8",
|
||||
"node-sass": "^6.0.1",
|
||||
"svelte": "^3.42.6",
|
||||
@ -171,6 +172,15 @@
|
||||
"@types/unist": "^2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mdast": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.0.tgz",
|
||||
"integrity": "sha512-YLeG8CujC9adtj/kuDzq1N4tCDYKoZ5l/bnjq8d74+t/3q/tHquJOJKUQXJrLCflOHpKjXgcI/a929gpmLOEng==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/minimist": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
|
||||
@ -1773,6 +1783,19 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-to-string": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
|
||||
"integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdsvex": {
|
||||
"version": "0.9.8",
|
||||
"resolved": "https://registry.npmjs.org/mdsvex/-/mdsvex-0.9.8.tgz",
|
||||
@ -3613,6 +3636,15 @@
|
||||
"@types/unist": "^2"
|
||||
}
|
||||
},
|
||||
"@types/mdast": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.0.tgz",
|
||||
"integrity": "sha512-YLeG8CujC9adtj/kuDzq1N4tCDYKoZ5l/bnjq8d74+t/3q/tHquJOJKUQXJrLCflOHpKjXgcI/a929gpmLOEng==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"@types/minimist": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
|
||||
@ -4778,6 +4810,15 @@
|
||||
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
|
||||
"dev": true
|
||||
},
|
||||
"mdast-util-to-string": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
|
||||
"integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/mdast": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"mdsvex": {
|
||||
"version": "0.9.8",
|
||||
"resolved": "https://registry.npmjs.org/mdsvex/-/mdsvex-0.9.8.tgz",
|
||||
|
@ -15,7 +15,8 @@
|
||||
"svelte-preprocess": "^4.9.8",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"unist-util-find": "^2.0.0",
|
||||
"hast-util-to-text": "^3.1.2"
|
||||
"hast-util-to-text": "^3.1.2",
|
||||
"mdast-util-to-string": "^4.0.0"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
@ -16,11 +16,31 @@
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, var(--content-width)) minmax(0, 1fr);
|
||||
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
grid-column: 2 / 3;
|
||||
}
|
||||
|
||||
.left-gutter {
|
||||
grid-column: 1 / 2;
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 0.9em;
|
||||
font-style: italic;
|
||||
margin-top: -0.5rem;
|
||||
}
|
||||
|
||||
.post {
|
||||
grid-column: 2 / 3;
|
||||
}
|
||||
</style>
|
||||
|
||||
<svelte:head>
|
||||
@ -28,9 +48,17 @@
|
||||
<link rel="stylesheet" href="/prism-dracula.css" />
|
||||
</svelte:head>
|
||||
|
||||
<div id="post">
|
||||
<div class="page">
|
||||
<div class="title">
|
||||
<h1 id="{makeSlug(title)}">{title}</h1>
|
||||
<p class="subtitle">{formatDate(date)}</p>
|
||||
</div>
|
||||
|
||||
<div class="left-gutter">
|
||||
<Toc items={toc} />
|
||||
</div>
|
||||
|
||||
<div class="post">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
@ -115,18 +115,6 @@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// /* slight tweaks for in between state */
|
||||
// @media (min-width: 52.5em) and (max-width: 70em) {
|
||||
// .sidenote {
|
||||
// padding-left: calc(50vw - 19rem);
|
||||
// }
|
||||
// }
|
||||
// @media (max-width: 52.5em) {
|
||||
// .sidenote {
|
||||
// padding-left: 2rem;
|
||||
// }
|
||||
// }
|
||||
</style>
|
||||
|
||||
<script context="module">
|
||||
|
@ -1,32 +1,66 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { makeSlug } from '$lib/utils.js';
|
||||
|
||||
export let items;
|
||||
|
||||
console.log(items);
|
||||
items.forEach(i => i.slug = makeSlug(i.text));
|
||||
|
||||
const selector = 'h1[id], h2[id], h3[id], h4[id], h6[id]';
|
||||
let currentHeadingSlug = null;
|
||||
function setCurrentHeading() {
|
||||
for (const h of document.querySelectorAll(selector)) {
|
||||
const yPos = h.getBoundingClientRect().y;
|
||||
if (yPos > (window.innerHeight / 3)) {
|
||||
break;
|
||||
}
|
||||
currentHeadingSlug = h.id;
|
||||
}
|
||||
}
|
||||
|
||||
onMount (() => {
|
||||
document.addEventListener('scroll', setCurrentHeading);
|
||||
setCurrentHeading();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
/* move everything out to the left and center it vertically */
|
||||
#toc {
|
||||
position: fixed;
|
||||
left: 1rem;
|
||||
/* setting top at 50vh sticks it halfway down the viewport,
|
||||
then translating back up by 50% gets it vertically centered
|
||||
even with a dynamic width */
|
||||
top: 50vh;
|
||||
transform: translateY(-50%);
|
||||
position: sticky;
|
||||
top: 1.5rem;
|
||||
margin-right: 4rem;
|
||||
|
||||
max-width: 14rem;
|
||||
color: var(--content-color-faded);
|
||||
opacity: 0;
|
||||
animation: fade-in 600ms ease-out;
|
||||
animation-delay: 500ms;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
/* margin-left is to match the list items; this allows the accent bar
|
||||
for the current item to appear to float out in space */
|
||||
@keyframes fade-in {
|
||||
from {opacity: 0}
|
||||
to {opacity: 100%}
|
||||
}
|
||||
|
||||
/* margin-left is to match the padding on the top-level list items,
|
||||
but here it needs to be margin so that the border is also shifted */
|
||||
h5 {
|
||||
margin-left: 0.5rem;
|
||||
padding-bottom: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
border-bottom: 0.1em solid currentcolor;
|
||||
font-variant: petite-caps;
|
||||
font-weight: 500;
|
||||
max-width: fit-content;
|
||||
|
||||
margin-top: 0;
|
||||
/* 0.5rem for indent, 0.1rem for border */
|
||||
margin-left: 0.6rem;
|
||||
margin-bottom: 0.25em;
|
||||
|
||||
padding-right: 1.5rem;
|
||||
padding-bottom: 0.25em;
|
||||
|
||||
border-bottom: 1px solid currentcolor;
|
||||
}
|
||||
|
||||
ul {
|
||||
@ -35,13 +69,21 @@
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/* margin for indentation, padding so that the accent bar for the current
|
||||
item isn't right on top of it */
|
||||
li {
|
||||
margin-left: var(--indent, 0);
|
||||
padding-left: 0.5rem;
|
||||
margin-bottom: 0.15rem;
|
||||
font-size: 0.9rem;
|
||||
border-left: 0.1rem solid transparent;
|
||||
}
|
||||
li:hover {
|
||||
color: var(--content-color);
|
||||
border-left: 0.1rem solid var(--accent-color);
|
||||
}
|
||||
li.current {
|
||||
color: var(--content-color);
|
||||
border-left: 0.1rem solid var(--accent-color);
|
||||
}
|
||||
|
||||
@ -49,18 +91,20 @@
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div id="toc">
|
||||
<h5>Table of Contents</h5>
|
||||
<h5>
|
||||
<span class="heading">Contents</span>
|
||||
</h5>
|
||||
<ul>
|
||||
{#each items as item}
|
||||
<li style:--indent="{(item.depth - 2) * 0.75}em">
|
||||
<a href="#{makeSlug(item.text)}">{item.text}</a>
|
||||
<li
|
||||
style:--indent="{(item.depth - 2) * 0.75}em"
|
||||
class:current={item.slug === currentHeadingSlug}
|
||||
>
|
||||
<a href="#{item.slug}">{item.text}</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
@ -1,39 +1,43 @@
|
||||
<style>
|
||||
:global(main) {
|
||||
--content-width: 42rem;
|
||||
box-sizing: border-box;
|
||||
max-width: var(--content-width);
|
||||
margin: 0 auto;
|
||||
padding: 0 15px;
|
||||
}
|
||||
<script>
|
||||
import Toc from '$lib/Toc.svelte';
|
||||
|
||||
#header {
|
||||
const items = [
|
||||
{depth: 2, text: 'The Suboptimal Solution: Absolute Positioning'},
|
||||
{depth: 2, text: 'CSS Wizardry'},
|
||||
{depth: 2, text: 'Implementation'},
|
||||
];
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.header {
|
||||
grid-column-start: 1;
|
||||
grid-column-end: 4;
|
||||
background-color: #4f5f68;
|
||||
}
|
||||
|
||||
#nav-main {
|
||||
nav {
|
||||
max-width: 30rem;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(6rem, 8rem));
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
#nav-main a {
|
||||
nav a {
|
||||
width: 8rem;
|
||||
min-width: 6rem;
|
||||
font-size: 1.5rem;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
#nav-main a:hover {
|
||||
nav a:hover {
|
||||
background-color: #00000025;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="header">
|
||||
<nav id="nav-main">
|
||||
<div class="header">
|
||||
<nav>
|
||||
<a sveltekit:prefetch href="/">Home</a>
|
||||
<a sveltekit:prefetch href="/posts">Posts</a>
|
||||
<a sveltekit:prefetch href="/">About</a>
|
||||
|
@ -29,10 +29,12 @@ html {
|
||||
line-height: var(--content-line-height);
|
||||
letter-spacing: -0.005em;
|
||||
color: var(--content-color);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
--content-width: 42rem;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { mdsvex } from 'mdsvex';
|
||||
import staticAdapter from '@sveltejs/adapter-static';
|
||||
import svp from 'svelte-preprocess';
|
||||
// import slug from './src/lib/slug.js';
|
||||
// import { addDropcaps } from './src/lib/dropcapify.js';
|
||||
import { localPlugins } from './src/plugins/rehype.js';
|
||||
|
||||
import { localRemark } from './src/plugins/remark.js';
|
||||
import { localRehype } from './src/plugins/rehype.js';
|
||||
|
||||
|
||||
const config = {
|
||||
@ -11,7 +11,8 @@ const config = {
|
||||
preprocess: [
|
||||
mdsvex({
|
||||
layout: './src/lib/Post.svelte',
|
||||
rehypePlugins: [localPlugins],
|
||||
remarkPlugins: [localRemark],
|
||||
rehypePlugins: [localRehype],
|
||||
}),
|
||||
svp.scss(),
|
||||
],
|
||||
|
Loading…
x
Reference in New Issue
Block a user