add custom headings with deep link

This commit is contained in:
2026-04-04 14:58:59 -04:00
parent 68bb25357b
commit 675ef1003d
11 changed files with 145 additions and 37 deletions

View File

@@ -3,9 +3,10 @@ export interface Props {
name: string,
width?: string,
height?: string,
display?: string,
};
const { name, width, height } = Astro.props;
const { name, width, height, display } = Astro.props;
const icons = import.meta.glob<{string: string}>('@components/icons/*.svg', { query: '?raw', import: 'default' });
const path = `/src/components/icons/${name}.svg`;
@@ -17,8 +18,9 @@ const icon = await icons[path]();
<span class="icon" set:html={icon} />
<style define:vars={{ width, height }}>
<style define:vars={{ width, height, display }}>
.icon :global(svg) {
display: var(--display, block);
width: var(--width, 100%);
height: var(--height, 100%);
}

View File

@@ -9,6 +9,7 @@ import Toc from '@components/Toc.vue';
import { formatDate } from '@lib/datefmt';
import Icon from '@components/Icon.astro';
import { headingElements } from '@components/headings';
export interface Props {
entry: CollectionEntry<'posts'>,
@@ -20,6 +21,41 @@ const { entry, prevSlug, nextSlug } = Astro.props;
const { Content, headings } = await render(entry);
---
<article class="prose" data-dropcap-style={entry.data.dropcap}>
<header class="title">
<h1>
<!-- <SmallCaps text={entry.data.title} upperWeight={500} lowerWeight={800} /> -->
{ entry.data.title }
</h1>
<p class="subtitle">{ formatDate(entry.data.date) }</p>
</header>
<div id="left-gutter">
<Toc client:load {headings} />
</div>
<section class="post">
<Content components={headingElements} />
</section>
<div id="right-gutter" />
<footer>
{prevSlug && (
<div class="footer-link left">
<Icon name="arrow-left" height="1em" />
<a href={`/${prevSlug}`} data-astro-prefetch>Older</a>
</div>
)}
{nextSlug && (
<div class="footer-link right">
<a href={`/${nextSlug}`} data-astro-prefetch>Newer</a>
<Icon name="arrow-right" height="1em" />
</div>
)}
</footer>
</article>
<style>
/* 3-column grid: left gutter, center content, and right gutter */
article {
@@ -126,38 +162,3 @@ article {
}
}
</style>
<article class="prose" data-dropcap-style={entry.data.dropcap}>
<header class="title">
<h1>
<!-- <SmallCaps text={entry.data.title} upperWeight={500} lowerWeight={800} /> -->
{ entry.data.title }
</h1>
<p class="subtitle">{ formatDate(entry.data.date) }</p>
</header>
<div id="left-gutter">
<Toc client:load {headings} />
</div>
<section class="post">
<Content />
</section>
<div id="right-gutter" />
<footer>
{prevSlug && (
<div class="footer-link left">
<Icon name="arrow-left" height="1em" />
<a href={`/${prevSlug}`} data-astro-prefetch>Older</a>
</div>
)}
{nextSlug && (
<div class="footer-link right">
<a href={`/${nextSlug}`} data-astro-prefetch>Newer</a>
<Icon name="arrow-right" height="1em" />
</div>
)}
</footer>
</article>

View File

@@ -0,0 +1,7 @@
---
import Heading from './Heading.astro';
---
<Heading tag="h1" {...Astro.props}>
<slot />
</Heading>

View File

@@ -0,0 +1,7 @@
---
import Heading from './Heading.astro';
---
<Heading tag="h2" {...Astro.props}>
<slot />
</Heading>

View File

@@ -0,0 +1,7 @@
---
import Heading from './Heading.astro';
---
<Heading tag="h3" {...Astro.props}>
<slot />
</Heading>

View File

@@ -0,0 +1,7 @@
---
import Heading from './Heading.astro';
---
<Heading tag="h4" {...Astro.props}>
<slot />
</Heading>

View File

@@ -0,0 +1,7 @@
---
import Heading from './Heading.astro';
---
<Heading tag="h5" {...Astro.props}>
<slot />
</Heading>

View File

@@ -0,0 +1,7 @@
---
import Heading from './Heading.astro';
---
<Heading tag="h6" {...Astro.props}>
<slot />
</Heading>

View File

@@ -0,0 +1,45 @@
---
import Icon from '@components/Icon.astro';
export interface Props extends astroHTML.JSX.HTMLAttributes {
tag: string,
}
const { tag: Tag, ...rest } = Astro.props;
---
<Tag {...rest}>
<slot />
<a href={`#${Astro.props.id}`} class="deep-link" >
<Icon name="link" height="0.9em" width="0.9em" display="inline" />
</a>
</Tag>
<style>
h1, h2, h3, h4, h5, h6 {
position: relative;
&:hover :global(svg) {
color: var(--accent-color);
}
}
a {
& :global(svg) {
color: var(--content-color-faded);
padding-bottom: 0.15em;
}
&:hover :global(svg), &:active :global(svg) {
color: var(--accent-color);
}
@media(min-width: 60rem) {
position: absolute;
top: 0.1em;
left: -1.25em;
padding-right: 0.5em;
}
}
</style>

View File

@@ -0,0 +1,15 @@
import H1 from './H1.astro';
import H2 from './H2.astro';
import H3 from './H3.astro';
import H4 from './H4.astro';
import H5 from './H5.astro';
import H6 from './H6.astro';
export const headingElements = {
h1: H1,
h2: H2,
h3: H3,
h4: H4,
h5: H5,
h6: H6,
};

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244" />
</svg>

After

Width:  |  Height:  |  Size: 353 B