From a77cd1741931369c4031bb81c8af431449b96ade Mon Sep 17 00:00:00 2001 From: gbanyan Date: Thu, 20 Nov 2025 22:42:59 +0800 Subject: [PATCH] Fix TOC button to be truly fixed-position using React Portal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TOC toggle button was appearing near the end of posts instead of floating at a fixed position. This happened because the button was rendered inside the PostLayout component hierarchy. Changes: - Use React Portal to render TOC button at document.body level - Add mounted state for proper SSR/client hydration - Button now floats like back-to-top button, visible from start This ensures the button is always visible and accessible, similar to the back-to-top button behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- components/post-layout.tsx | 48 ++++++++++++++++++++++---------------- next-env.d.ts | 2 +- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/components/post-layout.tsx b/components/post-layout.tsx index 1a08c6e..14f3d06 100644 --- a/components/post-layout.tsx +++ b/components/post-layout.tsx @@ -1,6 +1,7 @@ 'use client'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; +import { createPortal } from 'react-dom'; import { FiList, FiChevronRight } from 'react-icons/fi'; import { PostToc } from './post-toc'; import { clsx, type ClassValue } from 'clsx'; @@ -12,6 +13,30 @@ function cn(...inputs: ClassValue[]) { export function PostLayout({ children, hasToc = true, contentKey }: { children: React.ReactNode; hasToc?: boolean; contentKey?: string }) { const [isTocOpen, setIsTocOpen] = useState(hasToc); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + const tocButton = hasToc && mounted ? ( + + ) : null; return (
@@ -47,25 +72,8 @@ export function PostLayout({ children, hasToc = true, contentKey }: { children:
)} - {/* Toggle Button (Glassmorphism Pill) */} - {hasToc && ( - - )} + {/* Toggle Button - Rendered via Portal */} + {tocButton && createPortal(tocButton, document.body)} ); } diff --git a/next-env.d.ts b/next-env.d.ts index 9edff1c..c4b7818 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.