add heading anchors
This commit is contained in:
parent
6431267827
commit
b1dc3ae0ea
52
src/lib/Heading.svelte
Normal file
52
src/lib/Heading.svelte
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<script>
|
||||||
|
export let level;
|
||||||
|
export let id = '';
|
||||||
|
|
||||||
|
const tag = `h${level}`;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
/* Works better to set the size here for line-height reasons */
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: hsl(0, 0%, 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
border-bottom: 0.05em solid currentcolor;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.before {
|
||||||
|
display: none;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
margin-left: calc(-1em - 0.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(min-width: 58rem) {
|
||||||
|
.before {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<svelte:element this={tag} {id} class="h">
|
||||||
|
<a href="#{id}" 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">
|
||||||
|
<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></a><span> <!-- Looks ugly but necessary to get rid of spurious whitespace -->
|
||||||
|
<slot></slot>
|
||||||
|
</span>
|
||||||
|
<!-- Icon from https://heroicons.com/ -->
|
||||||
|
<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">
|
||||||
|
<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>
|
||||||
|
</a>
|
||||||
|
</svelte:element>
|
@ -1,7 +1,7 @@
|
|||||||
<script context="module">
|
<script context="module">
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { formatDate } from './datefmt.js';
|
import { formatDate } from './datefmt.js';
|
||||||
import { makeSlug } from '$lib/slug.js';
|
import { makeSlug } from '$lib/utils.js';
|
||||||
|
|
||||||
import Link from './Link.svelte';
|
import Link from './Link.svelte';
|
||||||
export { Link as a };
|
export { Link as a };
|
||||||
|
@ -12,15 +12,16 @@ export function localPlugins() {
|
|||||||
let dropcapAdded = false;
|
let dropcapAdded = false;
|
||||||
|
|
||||||
let moduleScript;
|
let moduleScript;
|
||||||
let imports = [];
|
let imports = new Set();
|
||||||
if (needsDropcap) {
|
if (needsDropcap) {
|
||||||
imports.push("import Dropcap from '$lib/Dropcap.svelte';");
|
imports.add("import Dropcap from '$lib/Dropcap.svelte';");
|
||||||
}
|
}
|
||||||
|
|
||||||
visit(tree, node => {
|
visit(tree, node => {
|
||||||
// add slugs to headings
|
// add slugs to headings
|
||||||
if (isHeading(node)) {
|
if (isHeading(node)) {
|
||||||
processHeading(node);
|
processHeading(node);
|
||||||
|
imports.add("import Heading from '$lib/Heading.svelte';");
|
||||||
return SKIP;
|
return SKIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ export function localPlugins() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// insert our imports at the top of the `<script context="module">` tag
|
// insert our imports at the top of the `<script context="module">` tag
|
||||||
if (imports.length > 0) {
|
if (imports.size > 0) {
|
||||||
const script = moduleScript.value;
|
const script = moduleScript.value;
|
||||||
// split the script where the opening tag ends
|
// split the script where the opening tag ends
|
||||||
const i = script.indexOf('>');
|
const i = script.indexOf('>');
|
||||||
@ -46,15 +47,18 @@ export function localPlugins() {
|
|||||||
const remainder = script.slice(i + 1);
|
const remainder = script.slice(i + 1);
|
||||||
|
|
||||||
// mdvsex uses tabs so we will as well
|
// mdvsex uses tabs so we will as well
|
||||||
const importScript = imports.join('\n\t');
|
const importScript = Array.from(imports).join('\n\t');
|
||||||
|
|
||||||
moduleScript.value = `${openingTag}\n\t${imports}${remainder}`;
|
moduleScript.value = `${openingTag}\n\t${importScript}${remainder}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function processHeading(node) {
|
function processHeading(node) {
|
||||||
|
const level = node.tagName.slice(1);
|
||||||
|
node.tagName = 'Heading';
|
||||||
|
node.properties.level = level;
|
||||||
node.properties.id = makeSlug(toText(node));
|
node.properties.id = makeSlug(toText(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user