style: final consistency pass — theme, responsive, animations
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import type { Metadata } from 'next'
|
import type { Metadata } from 'next'
|
||||||
import { Inter, Merriweather, JetBrains_Mono } from 'next/font/google'
|
import { Inter, Merriweather, JetBrains_Mono } from 'next/font/google'
|
||||||
import { ThemeProvider } from '@wrksz/themes/next'
|
import { ThemeProvider } from '@wrksz/themes/next'
|
||||||
import { Providers } from './providers'
|
|
||||||
import './globals.css'
|
import './globals.css'
|
||||||
import 'katex/dist/katex.min.css'
|
import 'katex/dist/katex.min.css'
|
||||||
import { Header } from '@/components/layout/Header'
|
import { Header } from '@/components/layout/Header'
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export default function NotFound() {
|
|||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p className="font-mono text-sm text-ink-soft mb-4">404</p>
|
<p className="font-mono text-sm text-ink-soft mb-4">404</p>
|
||||||
<h1 className="font-sans text-4xl font-bold tracking-tight text-ink mb-4">Page not found</h1>
|
<h1 className="font-sans text-4xl font-bold tracking-tight text-ink mb-4">Page not found</h1>
|
||||||
<p className="text-ink-soft mb-8">The page you're looking for doesn't exist.</p>
|
<p className="text-ink-soft mb-8">The page you{`'`}re looking for doesn{`'`}t exist.</p>
|
||||||
<Link href="/" className="inline-block rounded-lg bg-ink px-6 py-3 text-sm font-medium text-canvas hover:opacity-80 transition-opacity">
|
<Link href="/" className="inline-block rounded-lg bg-ink px-6 py-3 text-sm font-medium text-canvas hover:opacity-80 transition-opacity">
|
||||||
Go home
|
Go home
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -8,10 +8,8 @@ interface TOCItem {
|
|||||||
level: number;
|
level: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TableOfContents() {
|
function useHeadings(): TOCItem[] {
|
||||||
const [headings, setHeadings] = useState<TOCItem[]>([]);
|
const [headings, setHeadings] = useState<TOCItem[]>([]);
|
||||||
const [activeId, setActiveId] = useState("");
|
|
||||||
const observerRef = useRef<IntersectionObserver | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const elements = Array.from(
|
const elements = Array.from(
|
||||||
@@ -24,8 +22,19 @@ export function TableOfContents() {
|
|||||||
level: el.tagName === "H2" ? 2 : 3,
|
level: el.tagName === "H2" ? 2 : 3,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||||
setHeadings(parsed);
|
setHeadings(parsed);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return headings;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TableOfContents() {
|
||||||
|
const [activeId, setActiveId] = useState("");
|
||||||
|
const observerRef = useRef<IntersectionObserver | null>(null);
|
||||||
|
const headings = useHeadings();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
observerRef.current = new IntersectionObserver(
|
observerRef.current = new IntersectionObserver(
|
||||||
(entries) => {
|
(entries) => {
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
@@ -37,6 +46,10 @@ export function TableOfContents() {
|
|||||||
{ rootMargin: "-20% 0px -70% 0px", threshold: 0 }
|
{ rootMargin: "-20% 0px -70% 0px", threshold: 0 }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const elements = Array.from(
|
||||||
|
document.querySelectorAll("article h2, article h3")
|
||||||
|
) as HTMLElement[];
|
||||||
|
|
||||||
elements.forEach((el) => observerRef.current?.observe(el));
|
elements.forEach((el) => observerRef.current?.observe(el));
|
||||||
|
|
||||||
return () => observerRef.current?.disconnect();
|
return () => observerRef.current?.disconnect();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import path from 'path'
|
|||||||
import matter from 'gray-matter'
|
import matter from 'gray-matter'
|
||||||
import { compileMDX } from 'next-mdx-remote/rsc'
|
import { compileMDX } from 'next-mdx-remote/rsc'
|
||||||
import { cache } from 'react'
|
import { cache } from 'react'
|
||||||
import { useMDXComponents } from '@/mdx-components'
|
import { useMDXComponents as getMDXComponents } from '@/mdx-components'
|
||||||
import remarkMath from 'remark-math'
|
import remarkMath from 'remark-math'
|
||||||
import remarkGfm from 'remark-gfm'
|
import remarkGfm from 'remark-gfm'
|
||||||
import rehypeKatex from 'rehype-katex'
|
import rehypeKatex from 'rehype-katex'
|
||||||
@@ -58,7 +58,7 @@ export const getPost = async (slug: string): Promise<Post | null> => {
|
|||||||
const filePath = path.join(postsDirectory, file)
|
const filePath = path.join(postsDirectory, file)
|
||||||
const raw = await fs.readFile(filePath, 'utf8')
|
const raw = await fs.readFile(filePath, 'utf8')
|
||||||
const { data, content } = matter(raw)
|
const { data, content } = matter(raw)
|
||||||
const components = useMDXComponents({})
|
const components = getMDXComponents({})
|
||||||
|
|
||||||
const { content: compiledContent } = await compileMDX({
|
const { content: compiledContent } = await compileMDX({
|
||||||
source: content,
|
source: content,
|
||||||
|
|||||||
Reference in New Issue
Block a user