Skip to content

Commit 92a0128

Browse files
committed
fix: a11y + random stuff
1 parent e26efbd commit 92a0128

6 files changed

Lines changed: 58 additions & 23 deletions

File tree

app/[...slug]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export default async function Page({ params }: { params: Promise<{ slug: string[
2929
<h1 className="text-3xl font-bold">{frontmatter.title}</h1>
3030
</div>
3131

32-
<main>
32+
<main id="content" tabIndex={-1}>
3333
<Component />
3434
</main>
3535

app/layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import React from 'react';
55
import { Outfit } from 'next/font/google';
66
import Footer from '@/components/ui/Footer';
77
import PlausibleProvider from 'next-plausible';
8+
import SkipToContent from '@/components/SkipToContent';
89

910
const outfit = Outfit({ style: ['normal'] });
1011

@@ -29,6 +30,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
2930
// @ts-ignore
3031
'data-api': 'https://analytics.tenshii.moe/api/record',
3132
}}>
33+
<SkipToContent />
3234
<Header />
3335
{children}
3436
<Footer />

components/Breadcrumb.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { findPathBySlug } from '@/components/Sidebar';
44
import Link from 'next/link';
55
import { usePathname } from 'next/navigation';
6-
import { ChevronRight } from 'lucide-react';
6+
import { ChevronRight, Home } from 'lucide-react';
77
import { mainSidebar } from '@/components/sidebars';
88

99
export default function Breadcrumb() {
@@ -17,7 +17,7 @@ export default function Breadcrumb() {
1717
'@type': 'ListItem',
1818
position: i + 1,
1919
name: item.label,
20-
item: (!item.slug || i === links.length - 1) ? undefined : new URL(item.slug, process.env.NEXT_PUBLIC_BASE_URL),
20+
item: !item.slug ? undefined : new URL(item.slug.endsWith('/') ? item.slug : `${item.slug}/`, process.env.NEXT_PUBLIC_BASE_URL),
2121
})),
2222
});
2323
if (links.length <= 1) {
@@ -26,7 +26,14 @@ export default function Breadcrumb() {
2626

2727
return <>
2828
<nav aria-label="Breadcrumb" className="mb-2">
29-
<ol className="flex gap-1 text-sm text-muted-foreground items-center">
29+
<ol className="flex items-center gap-1 text-sm">
30+
{!!links.length && (
31+
<li className="flex items-center gap-1">
32+
<Home size={20} />
33+
<ChevronRight size={20} />
34+
</li>
35+
)}
36+
3037
{links.map((item, i) => {
3138
const isLast = i === links.length - 1;
3239

@@ -38,17 +45,17 @@ export default function Breadcrumb() {
3845
);
3946
} else if (!item.slug) {
4047
return (
41-
<li key={item.label} className="flex items-center">
48+
<li key={item.label} className="flex items-center gap-1">
4249
<span>{item.label}</span>
43-
<ChevronRight className="ml-1" size={20} />
50+
<ChevronRight size={20} />
4451
</li>
4552
);
4653
}
4754

4855
return (
49-
<li key={item.label} className="flex items-center">
56+
<li key={item.label} className="flex items-center gap-1">
5057
<Link href={item.slug}>{item.label}</Link>
51-
<ChevronRight className="ml-1" size={20} />
58+
<ChevronRight size={20} />
5259
</li>
5360
);
5461
})}

components/SkipToContent.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function SkipToContent() {
2+
return (
3+
<a className="absolute -top-8 left-2 z-50 rounded-xl bg-indigo-900 px-2 py-1 focus:top-2" href="#content" tabIndex={0}>
4+
Skip to content
5+
</a>
6+
);
7+
}
-2.41 KB
Loading

mdx-components.tsx

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,43 @@ import LinkButton from '@/components/mdx/LinkButton';
1111
import { LinkIcon } from 'lucide-react';
1212

1313
const slugify = (title: string|React.ReactNode[]) => {
14-
const toReplace = /[\s()?!,]+/g;
15-
if (typeof title === 'string') return title.toLowerCase().replaceAll(toReplace, '-');
16-
return (title![0] as string)!.toLowerCase().replaceAll(toReplace, '-');
14+
const toReplace = /[\s()?!,'&]+/g;
15+
let res: string;
16+
17+
if (typeof title === 'string') {
18+
res = title.toLowerCase().replaceAll(toReplace, '-');
19+
} else {
20+
// Only get the first part for React components
21+
res = (title![0] as string)!.toLowerCase().replaceAll(toReplace, '-');
22+
}
23+
24+
if (res.endsWith('-')) res = res.slice(0, -1);
25+
return res;
1726
};
1827

1928
const components: MDXComponents = {
2029
h2: ({ children }) => (
21-
<div className="flex items-center mb-3 mt-6 gap-2 group" id={slugify(children)}>
30+
<div className="group mb-3 mt-6 flex items-center gap-2" id={slugify(children)}>
2231
<h2 className="text-2xl font-bold">{children}</h2>
23-
<Link href={`#${slugify(children)}`} className="size-5 md:opacity-0 md:group-hover:opacity-100 duration-100"><LinkIcon /></Link>
32+
<Link
33+
href={`#${slugify(children)}`} className="size-5 duration-100 md:opacity-0 md:group-hover:opacity-100" aria-hidden
34+
><LinkIcon /></Link>
2435
</div>
2536
),
2637
h3: ({ children }) => (
27-
<div className="flex items-center mb-3 mt-6 gap-2 group" id={slugify(children)}>
38+
<div className="group mb-3 mt-6 flex items-center gap-2" id={slugify(children)}>
2839
<h3 className="text-xl font-bold">{children}</h3>
29-
<Link href={`#${slugify(children)}`} className="size-5 md:opacity-0 md:group-hover:opacity-100 duration-100"><LinkIcon /></Link>
40+
<Link
41+
href={`#${slugify(children)}`} className="size-5 duration-100 md:opacity-0 md:group-hover:opacity-100" aria-hidden
42+
><LinkIcon /></Link>
3043
</div>
3144
),
3245
h4: ({ children }) => (
33-
<div className="flex items-center mb-3 mt-6 gap-2 group" id={slugify(children)}>
46+
<div className="group mb-3 mt-6 flex items-center gap-2" id={slugify(children)}>
3447
<h4 className="text-lg font-bold">{children}</h4>
35-
<Link href={`#${slugify(children)}`} className="size-5 md:opacity-0 md:group-hover:opacity-100 duration-100"><LinkIcon /></Link>
48+
<Link
49+
href={`#${slugify(children)}`} className="size-5 duration-100 md:opacity-0 md:group-hover:opacity-100" aria-hidden
50+
><LinkIcon /></Link>
3651
</div>
3752
),
3853
code: ({ children }) => (
@@ -42,27 +57,31 @@ const components: MDXComponents = {
4257
<p className="mt-3">{children}</p>
4358
),
4459
ul: ({ children }) => (
45-
<ul className="list-inside list-disc mt-2">{children}</ul>
60+
<ul className="mt-2 list-inside list-disc">{children}</ul>
4661
),
4762
ol: ({ children }) => (
48-
<ol className="list-inside list-decimal mt-2">{children}</ol>
63+
<ol className="mt-2 list-inside list-decimal">{children}</ol>
4964
),
5065
img: (props) => (
51-
<Image {...(props as ImageProps)} className="size-full md:w-auto" />
66+
<a href={props.src?.src || props.src} target="_blank" rel="nofollow">
67+
{/* The remark plugin will automatically extract the alt text from the Markdown */}
68+
{/* eslint-disable-next-line jsx-a11y/alt-text */}
69+
<Image {...(props as ImageProps)} className="size-full rounded-xl border border-border md:w-auto" />
70+
</a>
5271
),
5372
a: ({ href, children }: { href: string, children: React.ReactNode }) => {
5473
const isExternal = href.startsWith('http');
5574
if (!isExternal) {
56-
return <Link href={href} className="text-blue-500 hover:text-blue-600 transition-colors">{children}</Link>;
75+
return <Link href={href} className="text-blue-500 transition-colors hover:text-blue-600">{children}</Link>;
5776
}
5877

5978
return <a
6079
href={href} target="_blank" rel={href.startsWith('https://miwa.lol/') ? undefined : 'noreferrer'}
61-
className="text-blue-500 hover:text-blue-600 transition-colors"
80+
className="text-blue-500 transition-colors hover:text-blue-600"
6281
>{children}</a>;
6382
},
6483
th: ({ children }) => <th className="p-2 text-left">{children}</th>,
65-
td: ({ children }) => <td className="p-2 border-y border-border">{children}</td>,
84+
td: ({ children }) => <td className="border-y border-border p-2">{children}</td>,
6685

6786
Aside,
6887
Badge,

0 commit comments

Comments
 (0)