Skip to content

Commit 21d4fe9

Browse files
committed
画面内のセクションを取得する機能を追加
1 parent 5605e7f commit 21d4fe9

2 files changed

Lines changed: 58 additions & 8 deletions

File tree

app/[docs_id]/page.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { join } from "node:path";
55
import { MarkdownSection, splitMarkdown } from "./splitMarkdown";
66
import { Section } from "./section";
77
import pyodideLock from "pyodide/pyodide-lock.json";
8+
import { PageContent } from "./pageContent";
89

910
export default async function Page({
1011
params,
@@ -45,14 +46,7 @@ export default async function Page({
4546

4647
return (
4748
<div className="p-4">
48-
{splitMdContent.map((section, index) => {
49-
const sectionId = `${docs_id}-${index}`;
50-
return (
51-
<div key={index} id={`${index}`}>
52-
<Section section={section} sectionId={sectionId} />
53-
</div>
54-
);
55-
})}
49+
<PageContent splitMdContent={splitMdContent} docs_id={docs_id} />
5650
</div>
5751
);
5852
}

app/[docs_id]/pageContent.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"use client";
2+
3+
import { useEffect, useRef, useState } from "react";
4+
import { Section } from "./section";
5+
import { MarkdownSection } from "./splitMarkdown";
6+
7+
interface PageContentProps {
8+
splitMdContent: MarkdownSection[];
9+
docs_id: string;
10+
}
11+
export function PageContent(props: PageContentProps) {
12+
// 各セクションが画面内にあるかどうかを調べる
13+
const [sectionInView, setSectionInView] = useState<boolean[]>([]);
14+
const sectionRefs = useRef<Array<HTMLDivElement | null>>([]);
15+
// sectionRefsの長さをsplitMdContentに合わせる
16+
while (sectionRefs.current.length < props.splitMdContent.length) {
17+
sectionRefs.current.push(null);
18+
}
19+
sectionRefs.current = sectionRefs.current.slice(
20+
0,
21+
props.splitMdContent.length
22+
);
23+
24+
useEffect(() => {
25+
const handleScroll = () => {
26+
const newSectionInView = sectionRefs.current.map((sectionRef) => {
27+
if (sectionRef) {
28+
const rect = sectionRef.getBoundingClientRect();
29+
return rect.top < window.innerHeight && rect.bottom >= 0;
30+
}
31+
return false;
32+
});
33+
setSectionInView(newSectionInView);
34+
};
35+
window.addEventListener("scroll", handleScroll);
36+
handleScroll();
37+
return () => {
38+
window.removeEventListener("scroll", handleScroll);
39+
};
40+
}, []);
41+
42+
return props.splitMdContent.map((section, index) => {
43+
const sectionId = `${props.docs_id}-${index}`;
44+
return (
45+
<div
46+
key={index}
47+
id={`${index}`} // 目次からaタグで飛ぶために必要
48+
ref={(el) => {
49+
sectionRefs.current[index] = el;
50+
}}
51+
>
52+
<Section section={section} sectionId={sectionId} />
53+
</div>
54+
);
55+
});
56+
}

0 commit comments

Comments
 (0)