feat: typography, toc

This commit is contained in:
enscribe 2024-09-10 16:41:01 -07:00
parent ea68d4f02f
commit 8fe228e243
No known key found for this signature in database
GPG key ID: 9BBD5C4114E25322
16 changed files with 194 additions and 311 deletions

View file

@ -4,7 +4,7 @@ import SocialIcons from './SocialIcons.astro'
import { ModeToggle } from '@components/ui/mode-toggle'
---
<footer class="py-8">
<footer class="py-4">
<Container>
<div class="flex justify-between items-center">
<div class="flex items-center space-x-4">

View file

@ -1,5 +1,7 @@
---
import '../styles/global.css'
import '../styles/katex.css'
import '../styles/typography.css'
import '@fontsource/geist-sans'
import '@fontsource/geist-mono'

View file

@ -11,21 +11,23 @@ const items = [
]
---
<header class="sticky top-0 z-10" transition:persist>
<header class="sticky top-0 z-10 bg-background/50 backdrop-blur-md" transition:persist>
<Container>
<div class="flex items-center justify-between py-4">
<Link href="/" underline={false}>
{SITE.TITLE}<span class="ml-1">🍄</span>
<Link href="/" class="text-xl font-semibold hover:text-primary transition-colors duration-300">
{SITE.TITLE}
</Link>
<nav class="flex items-center space-x-1 text-sm">
{
items.map((item, index) => (
<>
<Link href={item.href}>{item.label}</Link>
{index < items.length - 1 && <span class="text-gray-400">/</span>}
</>
))
}
<nav class="flex items-center gap-4 md:gap-6 text-sm">
{items.map((item, index) => (
<Fragment key={item.href}>
<Link
href={item.href}
class="transition-colors hover:text-foreground/80 text-foreground/60 capitalize"
>
{item.label}
</Link>
</Fragment>
))}
</nav>
</div>
</Container>

View file

@ -4,22 +4,22 @@ import { cn } from '@lib/utils'
type Props = {
href: string
external?: boolean
underline?: boolean
group?: boolean
class?: string
'data-heading'?: string
}
const { href, external, underline = true, group = false, ...rest } = Astro.props
const { href, external, class: className, 'data-heading': dataHeading, ...rest } = Astro.props
---
<a
href={href}
target={external ? '_blank' : '_self'}
class={cn(
'inline-block transition-colors duration-300 ease-in-out',
underline && 'underline underline-offset-[3px]',
group && 'group',
'inline-block transition-colors duration-300 ease-in-out hover:underline underline-offset-[3px]',
className
)}
data-heading={dataHeading}
{...rest}
>
<slot />
</a>
</a>

View file

@ -27,17 +27,17 @@ function buildToc(headings: Heading[]) {
}
---
<details open class="rounded-lg border">
<summary>Table of Contents</summary>
<details open class="block xl:hidden rounded-lg border p-3 mb-8">
<summary class="text-xl font-semibold">Table of Contents</summary>
<nav>
<ul class="py-3">
{toc.map((heading) => <TableOfContentsHeading heading={heading} />)}
</ul>
</nav>
</details>
<style>
summary {
@apply cursor-pointer rounded-t-lg px-3 py-1.5 font-medium transition-colors;
}
</style>
<nav class="sticky top-16 hidden xl:block h-0 w-[calc(50vw-50%-4rem)] overflow-wrap-break-word text-xs leading-4 translate-x-[calc(-100%-2em)]">
<h2 class="text-xl font-semibold mb-4">Table of Contents</h2>
<ul class="space-y-2">
{toc.map((heading) => <TableOfContentsHeading heading={heading} />)}
</ul>
</nav>

View file

@ -2,18 +2,16 @@
import type { Heading } from './TableOfContents.astro'
import Link from './Link.astro'
// https://kld.dev/building-table-of-contents/
const { heading } = Astro.props
---
<li class="list-inside list-disc px-6 py-1.5 text-sm">
<Link href={'#' + heading.slug} underline>
<li class="list-inside list-disc px-6 py-1.5 xl:list-none xl:p-0 text-sm">
<Link href={'#' + heading.slug} class="toc-link" data-heading={heading.slug}>
{heading.text}
</Link>
{
heading.subheadings.length > 0 && (
<ul class="translate-x-3">
<ul class="translate-x-3 xl:translate-x-0 xl:ml-4 xl:mt-2 xl:space-y-2">
{heading.subheadings.map((subheading: Heading) => (
<Astro.self heading={subheading} />
))}
@ -21,3 +19,31 @@ const { heading } = Astro.props
)
}
</li>
<script>
function updateActiveHeading() {
const headings = document.querySelectorAll('h2, h3, h4, h5, h6');
const tocLinks = document.querySelectorAll('.toc-link');
let currentHeading = '';
headings.forEach(heading => {
const top = heading.getBoundingClientRect().top;
if (top < 100) {
currentHeading = heading.id;
}
});
tocLinks.forEach(link => {
const headingSlug = link.getAttribute('data-heading');
if (headingSlug === currentHeading) {
link.classList.add('underline');
} else {
link.classList.remove('underline');
}
});
}
window.addEventListener('scroll', updateActiveHeading);
window.addEventListener('load', updateActiveHeading);
</script>

View file

@ -28,7 +28,7 @@ export function ModeToggle() {
}, [theme])
return (
<DropdownMenu>
<DropdownMenu modal={false}>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />