Skip to content

Commit f93f2b8

Browse files
committed
adds table-of-content for mobile device
1 parent 27df45a commit f93f2b8

File tree

7 files changed

+128
-10
lines changed

7 files changed

+128
-10
lines changed

src/app/[category]/[slug]/page.module.css

+15-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@
1919
.postHeader :global(#toc-title)::before {
2020
display: block;
2121
content: " ";
22-
margin-top: -72px;
23-
height: 72px;
2422
visibility: hidden;
2523
pointer-events: none;
24+
margin-top: -72px;
25+
height: 72px;
26+
@media (min-width: 640px) {
27+
margin-top: -96px;
28+
height: 96px;
29+
}
2630
}
2731

2832
.postTitle {
@@ -85,3 +89,12 @@
8589
height: calc(100vh - 96px);
8690
overflow-y: auto;
8791
}
92+
93+
.mobileTOC {
94+
position: fixed;
95+
bottom: 16px;
96+
right: 16px;
97+
@media (min-width: 1080px) {
98+
display: none;
99+
}
100+
}

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { getPostBySlug, getPostsByCategory } from "@/lib/posts";
66
import { Itoc } from "@/interfaces/Post";
77
import styles from "./page.module.css";
88
import ReactMarkdown from "@/components/ReactMarkdown";
9-
import TOC from "@/components/TOC";
9+
import { TOC, MobileTOC } from "@/components/TOC";
1010
import Comments from "@/components/Comments";
1111
import { SITE_CONFIG } from "@/app/site.config";
1212

@@ -72,6 +72,7 @@ export default function Page({ params }: { params: { category: string; slug: str
7272
<div className={styles.tocWrapper}>
7373
<TOC tocContent={tocContent} className={styles.toc} />
7474
</div>
75+
<MobileTOC tocContent={tocContent} className={styles.mobileTOC} />
7576
</div>
7677
);
7778
}

src/app/about/page.module.css

+24-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@
2121
flex-direction: column-reverse;
2222
}
2323
}
24+
25+
.header :global(#toc-title)::before {
26+
display: block;
27+
content: " ";
28+
visibility: hidden;
29+
pointer-events: none;
30+
margin-top: -72px;
31+
height: 72px;
32+
@media (min-width: 640px) {
33+
margin-top: -96px;
34+
height: 96px;
35+
}
36+
}
37+
2438
.titleContainer {
2539
height: min-content;
2640
@media (max-width: 640px) {
@@ -76,4 +90,13 @@
7690
width: 100%;
7791
height: calc(100vh - 96px);
7892
overflow-y: auto;
79-
}
93+
}
94+
95+
.mobileTOC {
96+
position: fixed;
97+
bottom: 16px;
98+
right: 16px;
99+
@media (min-width: 1080px) {
100+
display: none;
101+
}
102+
}

src/app/about/page.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import toc from "markdown-toc-unlazy";
55
import { getAboutPost } from "@/lib/posts";
66
import ReactMarkdown from "@/components/ReactMarkdown";
77
import Comments from "@/components/Comments";
8-
import TOC from "@/components/TOC";
8+
import { TOC, MobileTOC } from "@/components/TOC";
99
import { Itoc } from "@/interfaces/Post";
1010
import avatar from "@/assets/avatar.jpg";
1111
import styles from "./page.module.css";
@@ -33,7 +33,7 @@ export default function AboutPage() {
3333
<div className={`${styles.postWrapper} container`}>
3434
<div className={styles.header}>
3535
<div className={styles.titleContainer}>
36-
<div className={styles.title}>{frontMatter.title}</div>
36+
<div className={styles.title} id="toc-title">{frontMatter.title}</div>
3737
<div className={styles.description}>{frontMatter.description}</div>
3838
<div className={styles.postTime}>
3939
<span>
@@ -55,11 +55,12 @@ export default function AboutPage() {
5555
</div>
5656

5757
<ReactMarkdown abbrlink={frontMatter.abbrlink!}>{content}</ReactMarkdown>
58-
<Comments />
58+
<Comments id="toc-comments" />
5959
</div>
6060
<div className={styles.tocWrapper}>
6161
<TOC tocContent={tocContent} className={styles.toc} />
6262
</div>
63+
<MobileTOC tocContent={tocContent} className={styles.mobileTOC} />
6364
</div>
6465
);
6566
}

src/components/ReactMarkdown.module.css

+6-2
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,14 @@
150150
.reactMarkdown .anchor::before {
151151
display: block;
152152
content: " ";
153-
margin-top: -72px;
154-
height: 72px;
155153
visibility: hidden;
156154
pointer-events: none;
155+
margin-top: -72px;
156+
height: 72px;
157+
@media (min-width: 640px) {
158+
margin-top: -96px;
159+
height: 96px;
160+
}
157161
}
158162

159163
.codeWrapper {

src/components/TOC.module.css

+40
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,43 @@
1+
.IconWrapper {
2+
width: 36px;
3+
height: 36px;
4+
text-align: center;
5+
line-height: 44px;
6+
border: solid 1px var(--border-color);
7+
border-radius: 4px;
8+
background-color: var(--bg-color);
9+
}
10+
11+
.IconWrapper:hover {
12+
background-color: var(--hover-color);
13+
cursor: pointer;
14+
}
15+
16+
.IconWrapper > svg {
17+
fill: var(--svg-color);
18+
}
19+
20+
.mobileTOC {
21+
position: fixed;
22+
right: 56px;
23+
bottom: 56px;
24+
min-width: 200px;
25+
max-width: 280px;
26+
background-color: var(--bg-color);
27+
border: 0.5px solid var(--border-color);
28+
border-radius: 4px;
29+
padding: 12px 12px;
30+
max-height: calc(100vh - 200px);
31+
overflow-y: auto;
32+
@media (max-width: 640px) {
33+
max-height: calc(100vh - 128px);
34+
}
35+
}
36+
37+
.mobileTOC > .title {
38+
display: none;
39+
}
40+
141
.tocWrapper > * {
242
display: block;
343
}

src/components/TOC.tsx

+37-1
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,46 @@ const TOC = ({ tocContent, ...props }: { tocContent: Array<Itoc> } & React.HTMLA
6262
);
6363
};
6464

65+
const MobileTOC = ({ tocContent, ...props }: { tocContent: Array<Itoc> } & React.HTMLAttributes<HTMLDivElement>) => {
66+
const [isOpen, setIsOpen] = useState<boolean>(false);
67+
return (
68+
<div {...props}>
69+
<div
70+
className={styles.IconWrapper}
71+
onClick={() => {
72+
setIsOpen(!isOpen);
73+
}}
74+
>
75+
<SettingIcon />
76+
</div>
77+
<TOC tocContent={tocContent} className={styles.mobileTOC} style={{ display: isOpen ? "block" : "none" }} />
78+
</div>
79+
);
80+
};
81+
82+
const SettingIcon = (props: React.SVGProps<SVGSVGElement>) => (
83+
<svg xmlns="http://www.w3.org/2000/svg" width={20} height={20} className="icon" viewBox="0 0 1024 1024" {...props}>
84+
<style>
85+
{
86+
"@keyframes spinner_zKoa{to{transform:rotate(360deg)}}@keyframes spinner_YpZS{0%{stroke-dasharray:0 150;stroke-dashoffset:0}47.5%{stroke-dasharray:42 150;stroke-dashoffset:-16}95%,to{stroke-dasharray:42 150;stroke-dashoffset:-59}}"
87+
}
88+
</style>
89+
<g
90+
style={{
91+
transformOrigin: "center",
92+
animation: "spinner_zKoa 2s linear infinite",
93+
}}
94+
>
95+
<path d="M512 697.6c102.4 0 182.4-83.2 182.4-185.6 0-102.4-83.2-185.6-182.4-185.6-102.4 0-182.4 83.2-182.4 185.6 0 102.4 83.2 185.6 182.4 185.6zm0-51.2c-73.6 0-134.4-60.8-134.4-134.4 0-73.6 60.8-134.4 134.4-134.4 73.6 0 134.4 60.8 134.4 134.4 0 73.6-60.8 134.4-134.4 134.4z" />
96+
<path d="M249.015 843.179c35.2 28.8 73.6 51.2 112 67.2 41.6-38.4 96-60.8 150.4-60.8 57.6 0 108.8 22.4 150.4 60.8 41.6-16 80-38.4 112-67.2-12.8-54.4-3.2-112 22.4-163.2 28.8-48 73.6-86.4 128-102.4 3.2-22.4 6.4-44.8 6.4-67.2 0-22.4-3.2-44.8-6.4-67.2-54.4-16-99.2-54.4-128-102.4-28.8-48-35.2-108.8-22.4-163.2-35.2-28.8-73.6-51.2-112-67.2-41.6 38.4-92.8 60.8-150.4 60.8-54.4 0-108.8-22.4-150.4-60.8-41.6 16-80 38.4-112 67.2 12.8 54.4 3.2 112-22.4 163.2-28.8 48-73.6 86.4-128 102.4-3.2 22.4-6.4 44.8-6.4 67.2 0 22.4 3.2 44.8 6.4 67.2 54.4 16 99.2 54.4 128 102.4 25.6 51.2 35.2 108.8 22.4 163.2m112 115.2c-54.4-19.2-105.6-48-150.4-89.6-6.4-6.4-9.6-16-6.4-22.4 16-48 9.6-99.2-16-140.8-25.6-44.8-64-73.6-112-83.2-9.6-3.2-16-9.6-16-19.2-6.4-28.8-9.6-60.8-9.6-89.6 0-28.8 3.2-57.6 9.6-89.6 3.2-9.6 9.6-16 16-19.2 48-12.8 89.6-41.6 112-83.2 25.6-44.8 28.8-92.8 16-140.8-3.2-9.6 0-19.2 6.4-22.4 44.8-38.4 96-67.2 150.4-89.6 9.6-3.2 16 0 22.4 6.4 35.2 35.2 80 57.6 128 57.6s96-19.2 128-57.6c6.4-6.4 16-9.6 22.4-6.4 54.4 19.2 105.6 48 150.4 89.6 6.4 6.4 9.6 16 6.4 22.4-16 48-9.6 99.2 16 140.8 25.6 44.8 64 73.6 112 83.2 9.6 3.2 16 9.6 16 19.2 6.4 28.8 9.6 60.8 9.6 89.6 0 28.8-3.2 57.6-9.6 89.6-3.2 9.6-9.6 16-16 19.2-48 12.8-89.6 41.6-112 83.2-25.6 44.8-28.8 92.8-16 140.8 3.2 9.6 0 19.2-6.4 22.4-44.8 38.4-96 67.2-150.4 89.6-9.6 3.2-16 0-22.4-6.4-35.2-35.2-80-57.6-128-57.6s-96 19.2-128 57.6c-3.2 3.2-9.6 6.4-16 6.4h-6.4z" />
97+
</g>
98+
</svg>
99+
);
100+
65101
const handleSlug = (slug: string) =>
66102
slug
67103
.toLowerCase()
68104
.replace(/[^\p{Script=Han}a-z0-9]+/gu, "-")
69105
.replace(/^-|-$/g, "") || slug;
70106

71-
export default TOC;
107+
export { TOC, MobileTOC };

0 commit comments

Comments
 (0)