-
Notifications
You must be signed in to change notification settings - Fork 0
/
_main.tsx
127 lines (123 loc) · 3.51 KB
/
_main.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
// deno-lint-ignore-file no-explicit-any no-undef
import { React } from "./_deps.tsx";
import type { PagicLayout } from "./_deps.tsx";
import throttle from "https://cdn.pagic.org/lodash@4.17.20/esnext/throttle.js";
import Loading from "./_loading.tsx";
import { dateFormatter } from "./_utils.tsx";
// @ts-ignore need for parse
const Main: PagicLayout = (props) => {
const {
config,
content,
contentTitle,
contentBody,
blog,
author,
date,
loading,
toc,
prev,
next,
gitalk,
} = props;
React.useEffect(() => {
if (window.Deno) {
return;
}
const scrollHandler = () => {
const anchorPositionMap = new Map<
any,
"aboveViewport" | "inViewport" | "belowViewport"
>();
// @ts-ignore need for parse
for (const a of document.querySelectorAll(".toc a")) {
// @ts-ignore need for parse
const bounding = document.getElementById(a.hash.slice(1))
.getBoundingClientRect();
const belowTop = bounding.y > 64;
const aboveBottom =
// @ts-ignore need for parse
bounding.y + bounding.height + 16 <= window.innerHeight;
if ((belowTop && aboveBottom) || (!belowTop && !aboveBottom)) {
anchorPositionMap.set(a, "inViewport");
} else if (belowTop && !aboveBottom) {
anchorPositionMap.set(a, "belowViewport");
} else if (!belowTop && aboveBottom) {
anchorPositionMap.set(a, "aboveViewport");
}
}
let activeAnchor = null;
for (const [a, position] of anchorPositionMap) {
if (position === "aboveViewport") {
activeAnchor = a;
} else if (position === "inViewport") {
if (activeAnchor === null) {
activeAnchor = a;
break;
}
}
}
if (activeAnchor) {
// @ts-ignore need for parse
document.querySelectorAll(".toc a.active").forEach((node) =>
node.classList.remove("active")
);
activeAnchor.classList.add("active");
}
};
window.addEventListener("scroll", throttle(scrollHandler, 100));
scrollHandler();
}, []);
return (
<section className="main">
<div className="main_article">
{loading
? (
<Loading />
)
: blog?.isPost
? (
<>
{contentTitle}
{date && (
<div className="main_post_meta">
<time dateTime={date.toString()}>
{dateFormatter["yyyy-MM-dd"](date)}
</time>{" "}
· {author ?? "unknown"}
</div>
)}
{contentBody}
</>
)
: (
content
)}
{(prev || next) && (
<div className="prev_next">
{prev && (
<a className="prev button" href={`${config.root}${prev.link}`}>
« {prev.text}
</a>
)}
{next && (
<a className="next button" href={`${config.root}${next.link}`}>
{next.text} »
</a>
)}
</div>
)}
{gitalk}
</div>
{toc && (
<aside className="main_toc_container nav_link_container">
<div className="main_toc">
{config.tocAd && <div className="toc_ad">{config.tocAd}</div>}
{toc}
</div>
</aside>
)}
</section>
);
};
export default Main;