initial feed implementation
This commit is contained in:
@ -13,6 +13,9 @@
|
||||
export const description = '';
|
||||
export const draft = false;
|
||||
export let toc = null;
|
||||
|
||||
export let prev = null;
|
||||
export let next = null;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@ -46,7 +49,6 @@
|
||||
grid-column: 2 / 3;
|
||||
margin-bottom: 2rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
hr {
|
||||
@ -101,18 +103,23 @@
|
||||
<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>
|
||||
{#if prev}
|
||||
<a href="/{prev}" data-sveltekit-preload-data="hover">
|
||||
<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>
|
||||
{/if}
|
||||
|
||||
<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>
|
||||
{#if next}
|
||||
<!-- we use margin-left rather than justify-content so it works regardless of whether the "previous" link exists -->
|
||||
<a href="/{next}" style="margin-left: auto;" data-sveltekit-preload-data="hover">
|
||||
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>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -23,7 +23,7 @@
|
||||
}
|
||||
|
||||
.sidenote:before {
|
||||
content: counter(sidenote) " ";
|
||||
content: var(--sidenote-index, counter(sidenote)) " ";
|
||||
/* 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) */
|
||||
position: absolute;
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
.sidenote {
|
||||
--gap: 2rem;
|
||||
--sidenote-width: min(14rem, calc(50vw - var(--gap) - var(--content-width) / 2));
|
||||
--sidenote-width: min(16rem, calc(50vw - var(--gap) - 1rem - var(--content-width) / 2));
|
||||
width: var(--sidenote-width);
|
||||
hyphens: auto;
|
||||
position: relative;
|
||||
|
@ -11,7 +11,6 @@
|
||||
let currentSubheadingSlug = null;
|
||||
|
||||
function setCurrentHeading() {
|
||||
const start = performance.now();
|
||||
for (const h of headings) {
|
||||
const yPos = h.getBoundingClientRect().y;
|
||||
if (yPos > (window.innerHeight / 3)) {
|
||||
@ -25,8 +24,6 @@
|
||||
currentSubheadingSlug = h.id
|
||||
}
|
||||
}
|
||||
const end = performance.now();
|
||||
console.log(`Elapsed: ${end - start}`);
|
||||
}
|
||||
|
||||
onMount (() => {
|
||||
|
94
src/lib/xml.js
Normal file
94
src/lib/xml.js
Normal file
@ -0,0 +1,94 @@
|
||||
// const Node = {
|
||||
// addChild(child) {
|
||||
// this.children.push(child);
|
||||
// return child;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
export function tag(name, attrs, children) {
|
||||
return {
|
||||
type: 'tag',
|
||||
tag: name,
|
||||
attrs: attrs || {},
|
||||
children: children || [],
|
||||
|
||||
addTag(name, attrs, children) {
|
||||
const child = tag(name, attrs, children);
|
||||
this.children.push(child);
|
||||
return child;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function text(content) {
|
||||
return {
|
||||
type: 'text',
|
||||
text: content,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function serialize(node, depth) {
|
||||
if (!depth) {
|
||||
depth = 0;
|
||||
}
|
||||
|
||||
const indent = ' '.repeat(depth * 4);
|
||||
let fragments = [];
|
||||
|
||||
// version tag, if this is the top level
|
||||
if (depth === 0) {
|
||||
fragments.push('<?xml version="1.0" encoding="UTF-8"?>\n')
|
||||
}
|
||||
|
||||
fragments.push(`${indent}<${node.tag}`);
|
||||
|
||||
// this happens if there are multiple text nodes within the same parent
|
||||
if (node.type === 'text') {
|
||||
return `${indent}${escape(node.text)}`;
|
||||
}
|
||||
|
||||
if (node.children === undefined) {
|
||||
console.log(node);
|
||||
}
|
||||
|
||||
// opening tag <element attr="value">
|
||||
for (const attr in node.attrs) {
|
||||
fragments.push(` ${attr}="${node.attrs[attr]}"`);
|
||||
}
|
||||
if (node.children.length === 0) {
|
||||
fragments.push(' />');
|
||||
return fragments.join('');
|
||||
}
|
||||
fragments.push('>');
|
||||
|
||||
// if the only child is a single text node, skip recursion and just dump contents directly
|
||||
if (node.children.length === 1 && node.children[0].type === 'text') {
|
||||
const text = escape(node.children[0].text);
|
||||
fragments.push(text);
|
||||
}
|
||||
// otherwise, start a new line for each child node, then recurse
|
||||
else {
|
||||
for (const child of node.children) {
|
||||
fragments.push('\n');
|
||||
fragments.push(serialize(child, depth + 1));
|
||||
}
|
||||
// no need to verify that there were children, we already did that
|
||||
fragments.push(`\n${indent}`);
|
||||
}
|
||||
|
||||
fragments.push(`</${node.tag}>`);
|
||||
|
||||
return fragments.join('');
|
||||
}
|
||||
|
||||
|
||||
function escape(text) {
|
||||
// we aren't going to bother with escaping attributes, so we won't worry about quotes
|
||||
return text
|
||||
.replaceAll('&', '&')
|
||||
.replaceAll('<', '>')
|
||||
.replaceAll('>', '<');
|
||||
}
|
Reference in New Issue
Block a user