From 01196a8a3376057ee0fa7cf6263bbf20411c370e Mon Sep 17 00:00:00 2001 From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:49:55 +0900 Subject: [PATCH 1/6] =?UTF-8?q?loading.tsx=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/[docs_id]/loading.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 app/[docs_id]/loading.tsx diff --git a/app/[docs_id]/loading.tsx b/app/[docs_id]/loading.tsx new file mode 100644 index 0000000..272e542 --- /dev/null +++ b/app/[docs_id]/loading.tsx @@ -0,0 +1,12 @@ +export default function Loading() { + return ( +
+
{/* heading1 */}
+
{/*

*/}

+
{/* heading2 */}
+
{/*

*/}

+
{/* heading2 */}
+
{/*

*/}

+
+ ); +} From 8fcfe2cfef68e85c75b62a395a2cb1f5fb4b9f24 Mon Sep 17 00:00:00 2001 From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:03:54 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E8=AA=AD?= =?UTF-8?q?=E3=81=BF=E8=BE=BC=E3=81=BF=E6=99=82=E3=81=AE=E3=82=B5=E3=82=A4?= =?UTF-8?q?=E3=83=89=E3=83=90=E3=83=BC=E3=81=AE=E5=8B=95=E4=BD=9C=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/[docs_id]/dynamicMdContext.tsx | 40 -------- app/[docs_id]/pageContent.tsx | 13 +-- app/layout.tsx | 2 +- app/sidebar.tsx | 156 ++++++++++++++++++++++++----- 4 files changed, 135 insertions(+), 76 deletions(-) delete mode 100644 app/[docs_id]/dynamicMdContext.tsx diff --git a/app/[docs_id]/dynamicMdContext.tsx b/app/[docs_id]/dynamicMdContext.tsx deleted file mode 100644 index 779ff4e..0000000 --- a/app/[docs_id]/dynamicMdContext.tsx +++ /dev/null @@ -1,40 +0,0 @@ -"use client"; - -import { createContext, ReactNode, useContext, useState } from "react"; -import { DynamicMarkdownSection } from "./pageContent"; - -export interface ISidebarMdContext { - sidebarMdContent: DynamicMarkdownSection[]; - setSidebarMdContent: React.Dispatch>; -} - -const SidebarMdContext = createContext(null); - -export function useSidebarMdContext() { - const context = useContext(SidebarMdContext); - if (!context) { - throw new Error( - "useSidebarMdContext must be used within a SidebarMdProvider" - ); - } - return context; -} - -export function useSidebarMdContextOptional() { - return useContext(SidebarMdContext); -} - -export function SidebarMdProvider({ - children, -}: { - children: ReactNode; -}) { - const [sidebarMdContent, setSidebarMdContent] = - useState([]); - - return ( - - {children} - - ); -} diff --git a/app/[docs_id]/pageContent.tsx b/app/[docs_id]/pageContent.tsx index 418a518..c684ee8 100644 --- a/app/[docs_id]/pageContent.tsx +++ b/app/[docs_id]/pageContent.tsx @@ -5,7 +5,7 @@ import { MarkdownSection } from "./splitMarkdown"; import { ChatForm } from "./chatForm"; import { Heading, StyledMarkdown } from "./markdown"; import { useChatHistoryContext } from "./chatHistory"; -import { useSidebarMdContext } from "./dynamicMdContext"; +import { useSidebarMdContext } from "../sidebar"; import clsx from "clsx"; // MarkdownSectionに追加で、ユーザーが今そのセクションを読んでいるかどうか、などの動的な情報を持たせる @@ -41,12 +41,7 @@ export function PageContent(props: PageContentProps) { sectionId: `${props.docs_id}-${i}`, })); setDynamicMdContent(newContent); - setSidebarMdContent(newContent); - - // クリーンアップ:コンポーネントがアンマウントされたらcontextをクリア - return () => { - setSidebarMdContent([]); - }; + setSidebarMdContent(props.docs_id, newContent); }, [props.splitMdContent, props.docs_id, setSidebarMdContent]); const sectionRefs = useRef>([]); @@ -71,14 +66,14 @@ export function PageContent(props: PageContentProps) { // ローカルstateとcontextの両方を更新 setDynamicMdContent(updateContent); - setSidebarMdContent(updateContent); + setSidebarMdContent(props.docs_id, updateContent); }; window.addEventListener("scroll", handleScroll); handleScroll(); return () => { window.removeEventListener("scroll", handleScroll); }; - }, [setSidebarMdContent]); + }, [setSidebarMdContent, props.docs_id]); const [isFormVisible, setIsFormVisible] = useState(false); diff --git a/app/layout.tsx b/app/layout.tsx index dd56653..fcf18de 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -7,7 +7,7 @@ import { Sidebar } from "./sidebar"; import { ReactNode } from "react"; import { EmbedContextProvider } from "./terminal/embedContext"; import { AutoAnonymousLogin } from "./accountMenu"; -import { SidebarMdProvider } from "./[docs_id]/dynamicMdContext"; +import { SidebarMdProvider } from "./sidebar"; import { RuntimeProvider } from "./terminal/runtime"; export const metadata: Metadata = { diff --git a/app/sidebar.tsx b/app/sidebar.tsx index b95fda3..8fb23c1 100644 --- a/app/sidebar.tsx +++ b/app/sidebar.tsx @@ -4,17 +4,107 @@ import { usePathname } from "next/navigation"; import { pagesList } from "./pagesList"; import { AccountMenu } from "./accountMenu"; import { ThemeToggle } from "./[docs_id]/themeToggle"; -import { useSidebarMdContext } from "./[docs_id]/dynamicMdContext"; +import { + createContext, + ReactNode, + useCallback, + useContext, + useEffect, + useState, +} from "react"; +import { DynamicMarkdownSection } from "./[docs_id]/pageContent"; + +export interface ISidebarMdContext { + loadedDocsId: string; + sidebarMdContent: DynamicMarkdownSection[]; + setSidebarMdContent: ( + docsId: string, + content: + | DynamicMarkdownSection[] + | ((prev: DynamicMarkdownSection[]) => DynamicMarkdownSection[]) + ) => void; +} + +const SidebarMdContext = createContext(null); + +export function useSidebarMdContext() { + const context = useContext(SidebarMdContext); + if (!context) { + throw new Error( + "useSidebarMdContext must be used within a SidebarMdProvider" + ); + } + return context; +} + +export function useSidebarMdContextOptional() { + return useContext(SidebarMdContext); +} + +export function SidebarMdProvider({ children }: { children: ReactNode }) { + const [sidebarMdContent, setSidebarMdContent_] = useState< + DynamicMarkdownSection[] + >([]); + const [loadedDocsId, setLoadedDocsId] = useState(""); + const setSidebarMdContent = useCallback( + ( + docsId: string, + content: + | DynamicMarkdownSection[] + | ((prev: DynamicMarkdownSection[]) => DynamicMarkdownSection[]) + ) => { + setLoadedDocsId(docsId); + setSidebarMdContent_(content); + }, + [] + ); + return ( + + {children} + + ); +} export function Sidebar() { const pathname = usePathname(); - const docs_id = pathname.replace(/^\//, ""); - const { sidebarMdContent } = useSidebarMdContext(); - + const currentDocsId = pathname.replace(/^\//, ""); // ちょっと遅延がある + const sidebarContext = useSidebarMdContext(); + // sidebarMdContextの情報が古かったら使わない + const sidebarMdContent = + sidebarContext.loadedDocsId === currentDocsId + ? sidebarContext.sidebarMdContent + : []; + // 現在表示中のセクション(最初にinViewがtrueのもの)を見つける const currentSectionIndex = sidebarMdContent.findIndex( (section) => section.inView ); + + // 目次の開閉状態 + const [detailsOpen, setDetailsOpen] = useState([]); + const currentGroupIndex = pagesList.findIndex((group) => + currentDocsId.startsWith(`${group.id}-`) + ); + useEffect(() => { + // 表示しているグループが変わったときに現在のグループのdetailsを開く + if (currentGroupIndex !== -1) { + setDetailsOpen((detailsOpen) => { + const newDetailsOpen = [...detailsOpen]; + while (newDetailsOpen.length <= currentGroupIndex) { + newDetailsOpen.push(false); + } + newDetailsOpen[currentGroupIndex] = true; + return newDetailsOpen; + }); + } + }, [currentGroupIndex]); + return (
{/* todo: 背景色ほんとにこれでいい? */} @@ -51,9 +141,19 @@ export function Sidebar() {
    - {pagesList.map((group) => ( + {pagesList.map((group, i) => (
  • -
    +
    { + const newDetailsOpen = [...detailsOpen]; + while (newDetailsOpen.length <= i) { + newDetailsOpen.push(false); + } + newDetailsOpen[i] = e.currentTarget.open; + setDetailsOpen(newDetailsOpen); + }} + > {group.lang}
      {group.pages.map((page) => ( @@ -62,27 +162,31 @@ export function Sidebar() { {page.id}. {page.title} - {`${group.id}-${page.id}` === docs_id && sidebarMdContent.length > 0 && ( -
        - {sidebarMdContent.slice(1).map((section, idx) => { - // idx + 1 は実際のsectionIndexに対応(slice(1)で最初を除外しているため) - const isCurrentSection = idx + 1 === currentSectionIndex; - return ( -
      • - 0 && ( +
          + {sidebarMdContent.slice(1).map((section, idx) => { + // idx + 1 は実際のsectionIndexに対応(slice(1)で最初を除外しているため) + const isCurrentSection = + idx + 1 === currentSectionIndex; + return ( +
        • - {section.title} - -
        • - ); - })} -
        - )} + + {section.title} + +
      • + ); + })} +
      + )} ))}
    From c9d64b555526026eac5eec4bd0ac0f98f4d814d7 Mon Sep 17 00:00:00 2001 From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:50:10 +0900 Subject: [PATCH 3/6] =?UTF-8?q?getChat()=E3=82=92=E3=82=AD=E3=83=A3?= =?UTF-8?q?=E3=83=83=E3=82=B7=E3=83=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/[docs_id]/chatHistory.tsx | 24 +++++++- app/[docs_id]/page.tsx | 6 +- app/lib/cache.ts | 20 +++++++ app/lib/chatHistory.ts | 107 +++++++++++++++++++++++++++++----- 4 files changed, 136 insertions(+), 21 deletions(-) create mode 100644 app/lib/cache.ts diff --git a/app/[docs_id]/chatHistory.tsx b/app/[docs_id]/chatHistory.tsx index fc92e5d..184c2eb 100644 --- a/app/[docs_id]/chatHistory.tsx +++ b/app/[docs_id]/chatHistory.tsx @@ -1,6 +1,6 @@ "use client"; -import { ChatWithMessages } from "@/lib/chatHistory"; +import { ChatWithMessages, getChat } from "@/lib/chatHistory"; import { createContext, ReactNode, @@ -8,6 +8,7 @@ import { useEffect, useState, } from "react"; +import useSWR from "swr"; export interface IChatHistoryContext { chatHistories: ChatWithMessages[]; @@ -27,19 +28,38 @@ export function useChatHistoryContext() { export function ChatHistoryProvider({ children, + docs_id, initialChatHistories, }: { children: ReactNode; + docs_id: string; initialChatHistories: ChatWithMessages[]; }) { const [chatHistories, setChatHistories] = useState(initialChatHistories); + // 最初はSSRで取得したinitialChatHistoriesを使用(キャッシュされているので古い可能性がある) useEffect(() => { setChatHistories(initialChatHistories); }, [initialChatHistories]); + // その後、クライアント側で最新のchatHistoriesを改めて取得して更新する + const { data: fetchedChatHistories } = useSWR( + docs_id, + getChat, + { + // リクエストは古くても構わないので1回でいい + revalidateIfStale: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + } + ); + useEffect(() => { + if (fetchedChatHistories) { + setChatHistories(fetchedChatHistories); + } + }, [fetchedChatHistories]); + // チャットを更新した際にはクライアントサイドでchatHistoryに反映する const addChat = (chat: ChatWithMessages) => { - // サーバー側で追加された新しいchatをクライアント側にも反映する setChatHistories([...chatHistories, chat]); }; diff --git a/app/[docs_id]/page.tsx b/app/[docs_id]/page.tsx index cf41646..79c0c04 100644 --- a/app/[docs_id]/page.tsx +++ b/app/[docs_id]/page.tsx @@ -6,7 +6,7 @@ import { MarkdownSection, splitMarkdown } from "./splitMarkdown"; import pyodideLock from "pyodide/pyodide-lock.json"; import { PageContent } from "./pageContent"; import { ChatHistoryProvider } from "./chatHistory"; -import { getChat } from "@/lib/chatHistory"; +import { getChat, getChatFromCache } from "@/lib/chatHistory"; export default async function Page({ params, @@ -50,10 +50,10 @@ export default async function Page({ splitMarkdown(text) ); - const initialChatHistories = getChat(docs_id); + const initialChatHistories = getChatFromCache(docs_id); return ( - + = new Map(); +/** + * nodejsにcache apiがないので、web標準のcache APIに相当するものの自前実装 + */ +export const inMemoryCache = { + async put(key: string, response: Response): Promise { + const arrayBuffer = await response.arrayBuffer(); + cacheData.set(key, arrayBuffer); + }, + async match(key: string): Promise { + const arrayBuffer = cacheData.get(key); + if (arrayBuffer) { + return new Response(arrayBuffer); + } + return undefined; + }, + async delete(key: string): Promise { + return cacheData.delete(key); + }, +} as const; diff --git a/app/lib/chatHistory.ts b/app/lib/chatHistory.ts index 5e37c07..915f435 100644 --- a/app/lib/chatHistory.ts +++ b/app/lib/chatHistory.ts @@ -1,30 +1,74 @@ +"use server"; + import { headers } from "next/headers"; import { getAuthServer } from "./auth"; import { getDrizzle } from "./drizzle"; import { chat, message } from "@/schema/chat"; import { and, asc, eq } from "drizzle-orm"; +import { Auth } from "better-auth"; +import { inMemoryCache } from "./cache"; export interface CreateChatMessage { role: "user" | "ai" | "error"; content: string; } +// cacheに使うキーで、実際のURLではない +const CACHE_KEY_BASE = "https://my-code.utcode.net/chatHistory"; + +interface Context { + drizzle: Awaited>; + auth: Auth; + userId: string; +} +/** + * drizzleが初期化されてなければ初期化し、 + * authが初期化されてなければ初期化し、 + * userIdがなければセッションから取得してセットする。 + */ +async function initAll(ctx?: Partial): Promise { + if (!ctx) { + ctx = {}; + } + if (!ctx.drizzle) { + ctx.drizzle = await getDrizzle(); + } + if (!ctx.auth) { + ctx.auth = await getAuthServer(ctx.drizzle); + } + if (!ctx.userId) { + const session = await ctx.auth.api.getSession({ + headers: await headers(), + }); + if (!session) { + throw new Error("Not authenticated"); + } + ctx.userId = session.user.id; + } + return ctx as Context; +} +async function getCache() { + if ("caches" in globalThis) { + // worker + return await caches.open("chatHistory"); + } else { + // nodejs + return inMemoryCache; + } +} + export async function addChat( docsId: string, sectionId: string, - messages: CreateChatMessage[] + messages: CreateChatMessage[], + context?: Partial ) { - const drizzle = await getDrizzle(); - const auth = await getAuthServer(drizzle); - const session = await auth.api.getSession({ headers: await headers() }); - if (!session) { - throw new Error("Not authenticated"); - } + const { drizzle, userId } = await initAll(context); const [newChat] = await drizzle .insert(chat) .values({ - userId: session.user.id, + userId, docsId, sectionId, }) @@ -41,6 +85,14 @@ export async function addChat( ) .returning(); + console.log( + `deleting cache for chatHistory/getChat for user ${userId} and docs ${docsId}` + ); + const cache = await getCache(); + await cache.delete( + `${CACHE_KEY_BASE}/getChat?docsId=${docsId}&userId=${userId}` + ); + return { ...newChat, messages: chatMessages, @@ -49,16 +101,14 @@ export async function addChat( export type ChatWithMessages = Awaited>; -export async function getChat(docsId: string) { - const drizzle = await getDrizzle(); - const auth = await getAuthServer(drizzle); - const session = await auth.api.getSession({ headers: await headers() }); - if (!session) { - return []; - } +export async function getChat( + docsId: string, + context?: Partial +): Promise { + const { drizzle, userId } = await initAll(context); const chats = await drizzle.query.chat.findMany({ - where: and(eq(chat.userId, session.user.id), eq(chat.docsId, docsId)), + where: and(eq(chat.userId, userId), eq(chat.docsId, docsId)), with: { messages: { orderBy: [asc(message.createdAt)], @@ -67,8 +117,33 @@ export async function getChat(docsId: string) { orderBy: [asc(chat.createdAt)], }); + const cache = await getCache(); + await cache.put( + `${CACHE_KEY_BASE}/getChat?docsId=${docsId}&userId=${userId}`, + new Response(JSON.stringify(chats), { + headers: { "Cache-Control": "max-age=86400, s-maxage=86400" }, + }) + ); return chats; } +export async function getChatFromCache( + docsId: string, + context?: Partial +) { + const { drizzle, auth, userId } = await initAll(context); + + const cache = await getCache(); + const cachedResponse = await cache.match( + `${CACHE_KEY_BASE}/getChat?docsId=${docsId}&userId=${userId}` + ); + if (cachedResponse) { + console.log("Cache hit for chatHistory/getChat"); + const data = (await cachedResponse.json()) as ChatWithMessages[]; + return data; + } + console.log("Cache miss for chatHistory/getChat"); + return await getChat(docsId, { drizzle, auth, userId }); +} export async function migrateChatUser(oldUserId: string, newUserId: string) { const drizzle = await getDrizzle(); From 81d4d630b0680bd761fdbb0f1bc5abce3ed7cfea Mon Sep 17 00:00:00 2001 From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:34:54 +0900 Subject: [PATCH 4/6] =?UTF-8?q?inView=E5=88=A4=E5=AE=9A=E3=81=AE=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/[docs_id]/pageContent.tsx | 20 ++++++++++++-------- app/sidebar.tsx | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/app/[docs_id]/pageContent.tsx b/app/[docs_id]/pageContent.tsx index c684ee8..dad631a 100644 --- a/app/[docs_id]/pageContent.tsx +++ b/app/[docs_id]/pageContent.tsx @@ -21,7 +21,7 @@ interface PageContentProps { } export function PageContent(props: PageContentProps) { const { setSidebarMdContent } = useSidebarMdContext(); - + // SSR用のローカルstate const [dynamicMdContent, setDynamicMdContent] = useState< DynamicMarkdownSection[] @@ -52,18 +52,22 @@ export function PageContent(props: PageContentProps) { useEffect(() => { const handleScroll = () => { - const updateContent = (prevDynamicMdContent: DynamicMarkdownSection[]) => { + const updateContent = ( + prevDynamicMdContent: DynamicMarkdownSection[] + ) => { const dynMdContent = prevDynamicMdContent.slice(); // Reactの変更検知のために新しい配列を作成 for (let i = 0; i < sectionRefs.current.length; i++) { if (sectionRefs.current.at(i) && dynMdContent.at(i)) { const rect = sectionRefs.current.at(i)!.getBoundingClientRect(); + console.log(i, rect); dynMdContent.at(i)!.inView = - rect.top < window.innerHeight && rect.bottom >= 0; + rect.top < window.innerHeight * 0.9 && + rect.bottom >= window.innerHeight * 0.1; } } return dynMdContent; }; - + // ローカルstateとcontextの両方を更新 setDynamicMdContent(updateContent); setSidebarMdContent(props.docs_id, updateContent); @@ -102,8 +106,9 @@ export function PageContent(props: PageContentProps) {
{/* 右側に表示するチャット履歴欄 */} - {chatHistories.filter((c) => c.sectionId === section.sectionId).map( - ({chatId, messages}) => ( + {chatHistories + .filter((c) => c.sectionId === section.sectionId) + .map(({ chatId, messages }) => (
- ) - )} + ))}
))} diff --git a/app/sidebar.tsx b/app/sidebar.tsx index 8fb23c1..4ee2f06 100644 --- a/app/sidebar.tsx +++ b/app/sidebar.tsx @@ -83,7 +83,7 @@ export function Sidebar() { // 現在表示中のセクション(最初にinViewがtrueのもの)を見つける const currentSectionIndex = sidebarMdContent.findIndex( - (section) => section.inView + (section, i) => i >= 1 && section.inView ); // 目次の開閉状態 From d63ae2d787b72f27169b3d7ce582cdcc768b6181 Mon Sep 17 00:00:00 2001 From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:36:02 +0900 Subject: [PATCH 5/6] =?UTF-8?q?lint=E3=82=A8=E3=83=A9=E3=83=BC=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/[docs_id]/markdown.tsx | 4 ++-- app/[docs_id]/page.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/[docs_id]/markdown.tsx b/app/[docs_id]/markdown.tsx index b985c60..b3a8c03 100644 --- a/app/[docs_id]/markdown.tsx +++ b/app/[docs_id]/markdown.tsx @@ -1,7 +1,7 @@ import Markdown, { Components } from "react-markdown"; import remarkGfm from "remark-gfm"; import SyntaxHighlighter from "react-syntax-highlighter"; -import { type AceLang, EditorComponent, getAceLang } from "../terminal/editor"; +import { EditorComponent, getAceLang } from "../terminal/editor"; import { ExecFile } from "../terminal/exec"; import { useChangeTheme } from "./themeToggle"; import { @@ -9,7 +9,7 @@ import { atomOneDark, } from "react-syntax-highlighter/dist/esm/styles/hljs"; import { ReactNode } from "react"; -import { getRuntimeLang, RuntimeLang } from "@/terminal/runtime"; +import { getRuntimeLang } from "@/terminal/runtime"; import { ReplTerminal } from "@/terminal/repl"; export function StyledMarkdown({ content }: { content: string }) { diff --git a/app/[docs_id]/page.tsx b/app/[docs_id]/page.tsx index 79c0c04..2841b68 100644 --- a/app/[docs_id]/page.tsx +++ b/app/[docs_id]/page.tsx @@ -6,7 +6,7 @@ import { MarkdownSection, splitMarkdown } from "./splitMarkdown"; import pyodideLock from "pyodide/pyodide-lock.json"; import { PageContent } from "./pageContent"; import { ChatHistoryProvider } from "./chatHistory"; -import { getChat, getChatFromCache } from "@/lib/chatHistory"; +import { getChatFromCache } from "@/lib/chatHistory"; export default async function Page({ params, From b5182ad0bfd5d81e2939ca95243392d19296ebd1 Mon Sep 17 00:00:00 2001 From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:40:32 +0900 Subject: [PATCH 6/6] =?UTF-8?q?console.log=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/[docs_id]/pageContent.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/[docs_id]/pageContent.tsx b/app/[docs_id]/pageContent.tsx index dad631a..83406c7 100644 --- a/app/[docs_id]/pageContent.tsx +++ b/app/[docs_id]/pageContent.tsx @@ -59,7 +59,6 @@ export function PageContent(props: PageContentProps) { for (let i = 0; i < sectionRefs.current.length; i++) { if (sectionRefs.current.at(i) && dynMdContent.at(i)) { const rect = sectionRefs.current.at(i)!.getBoundingClientRect(); - console.log(i, rect); dynMdContent.at(i)!.inView = rect.top < window.innerHeight * 0.9 && rect.bottom >= window.innerHeight * 0.1;