-
Notifications
You must be signed in to change notification settings - Fork 322
/
Layout.tsx
147 lines (140 loc) 路 5.73 KB
/
Layout.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { useEffect, useState } from "react";
import Head from "next/head.js";
import { NextRouter, useRouter } from "next/router.js";
import clsx from "clsx";
import { useTableOfContents } from "./useTableOfContents";
import { collectHeadings } from "../../utils";
import { Nav } from "../Nav";
import { SiteToc, NavItem, NavGroup } from "../SiteToc";
import { Comments, CommentsConfig } from "../Comments";
import { Footer } from "./Footer";
import { EditThisPage } from "./EditThisPage";
import { TableOfContents, TocSection } from "./TableOfContents";
import { NavConfig, ThemeConfig } from "../Nav";
import { AuthorConfig } from "../types";
interface Props extends React.PropsWithChildren {
showComments: boolean;
showEditLink: boolean;
showSidebar: boolean;
showToc: boolean;
nav: NavConfig;
author: AuthorConfig;
theme: ThemeConfig;
urlPath: string;
commentsConfig: CommentsConfig;
siteMap: Array<NavItem | NavGroup>;
editUrl?: string;
}
export const Layout: React.FC<Props> = ({
children,
nav,
author,
theme,
showEditLink,
showToc,
showSidebar,
urlPath,
showComments,
commentsConfig,
editUrl,
siteMap,
}) => {
const [isScrolled, setIsScrolled] = useState(false);
const [tableOfContents, setTableOfContents] = useState<TocSection[]>([]);
const currentSection = useTableOfContents(tableOfContents);
const router: NextRouter = useRouter();
useEffect(() => {
if (!showToc) return;
const headingNodes: NodeListOf<HTMLHeadingElement> =
document.querySelectorAll("h1,h2,h3");
const toc = collectHeadings(headingNodes);
setTableOfContents(toc ?? []);
}, [router.asPath, showToc]); // update table of contents on route change with next/link
useEffect(() => {
function onScroll() {
setIsScrolled(window.scrollY > 0);
}
onScroll();
window.addEventListener("scroll", onScroll, { passive: true });
return () => {
window.removeEventListener("scroll", onScroll);
};
}, []);
return (
<>
<Head>
<link
rel="icon"
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>馃拹</text></svg>"
/>
<meta charSet="utf-8" />
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
<div className="min-h-screen bg-background dark:bg-background-dark">
{/* NAVBAR */}
<div
className={clsx(
"sticky top-0 z-50 w-full",
isScrolled
? "dark:bg-background-dark/95 bg-background/95 backdrop-blur [@supports(backdrop-filter:blur(0))]:dark:bg-background-dark/75"
: "dark:bg-background-dark bg-background"
)}
>
<div className="max-w-8xl mx-auto p-4 md:px-8">
<Nav
title={nav.title}
logo={nav.logo}
links={nav.links}
search={nav.search}
social={nav.social}
defaultTheme={theme.defaultTheme}
themeToggleIcon={theme.themeToggleIcon}
version={nav.version}
>
{showSidebar && <SiteToc currentPath={urlPath} nav={siteMap} />}
</Nav>
</div>
</div>
{/* wrapper for sidebar, main content and ToC */}
<div
className={clsx(
"max-w-8xl mx-auto px-4 md:px-8",
showSidebar && "lg:ml-[18rem]"
)}
>
{/* SIDEBAR */}
{showSidebar && (
<div className="hidden lg:block fixed z-20 w-[18rem] top-[4.6rem] right-auto bottom-0 left-[max(0px,calc(50%-44rem))] pt-8 pl-8 overflow-y-auto">
<SiteToc currentPath={urlPath} nav={siteMap} />
</div>
)}
{/* MAIN CONTENT & FOOTER */}
<main className="mx-auto pt-8">
{children}
{/* EDIT THIS PAGE LINK */}
{showEditLink && editUrl && <EditThisPage url={editUrl} />}
{/* PAGE COMMENTS */}
{showComments && (
<div
className="prose mx-auto pt-6 pb-6 text-center text-gray-700 dark:text-gray-300"
id="comment"
>
{<Comments commentsConfig={commentsConfig} slug={urlPath} />}
</div>
)}
</main>
<Footer links={nav.links} author={author} />
{/** TABLE OF CONTENTS */}
{showToc && tableOfContents.length > 0 && (
<div className="hidden xl:block fixed z-20 w-[18rem] top-[4.6rem] bottom-0 right-[max(0px,calc(50%-44rem))] left-auto pt-8 pr-8 overflow-y-auto">
<TableOfContents
tableOfContents={tableOfContents}
currentSection={currentSection}
/>
</div>
)}
</div>
</div>
</>
);
};