From 3f2cddcd074aaa5aeb6c460be17c14a8f22bfb15 Mon Sep 17 00:00:00 2001 From: miteruzo Date: Sat, 4 Jul 2026 17:40:55 +0900 Subject: [PATCH] #385 --- frontend/src/components/MaterialSidebar.tsx | 36 ++++++------- frontend/src/components/TagDetailSidebar.tsx | 9 ++-- .../layout/SidebarComponent.test.tsx | 41 +++++++++++--- .../components/layout/SidebarComponent.tsx | 53 ++++++++++++------- .../src/pages/materials/MaterialBasePage.tsx | 6 ++- frontend/src/pages/posts/PostDetailPage.tsx | 12 ++--- frontend/src/pages/posts/PostListPage.tsx | 1 + 7 files changed, 101 insertions(+), 57 deletions(-) diff --git a/frontend/src/components/MaterialSidebar.tsx b/frontend/src/components/MaterialSidebar.tsx index e686a61..3fef9da 100644 --- a/frontend/src/components/MaterialSidebar.tsx +++ b/frontend/src/components/MaterialSidebar.tsx @@ -488,25 +488,23 @@ const MaterialSidebar: FC = () => { -
- -
- - {isLoading && ( -

読込中……

)} - {isError && ( -

- タグ一覧の取得に失敗しました. -

)} - {(!isLoading && !isError) && ( -
    - {renderDesktopTree (visibleRootTags)} -
)} -
-
-
+ +
+ + {isLoading && ( +

読込中……

)} + {isError && ( +

+ タグ一覧の取得に失敗しました. +

)} + {(!isLoading && !isError) && ( +
    + {renderDesktopTree (visibleRootTags)} +
)} +
+
) } diff --git a/frontend/src/components/TagDetailSidebar.tsx b/frontend/src/components/TagDetailSidebar.tsx index debc040..10b7eb6 100644 --- a/frontend/src/components/TagDetailSidebar.tsx +++ b/frontend/src/components/TagDetailSidebar.tsx @@ -146,10 +146,13 @@ const DropSlot = ({ cat }: { cat: Category }) => { } -type Props = { post: Post; sp?: boolean } +type Props = { + className?: string + post: Post + sp?: boolean } -const TagDetailSidebar: FC = ({ post, sp }) => { +const TagDetailSidebar: FC = ({ className, post, sp }) => { sp = Boolean (sp) const qc = useQueryClient () @@ -278,7 +281,7 @@ const TagDetailSidebar: FC = ({ post, sp }) => { }, [baseTags]) return ( - + container.querySelector ('[style*="--sidebar-width"]')! +const sidebarTree = (props: Partial[0]>) => ( + +
+ + Sidebar body + +
+
) + + const renderSidebar = ( props: Partial[0]> = {}, containerWidth = 800, @@ -24,14 +34,7 @@ const renderSidebar = ( }, }) - const rendered = render ( - -
- - Sidebar body - -
-
) + const rendered = render (sidebarTree (props)) return rendered } @@ -96,4 +99,26 @@ describe ('SidebarComponent', () => { expect (localStorage.getItem ('sidebar:test-sidebar:right:width')).toBeNull () expect (localStorage.getItem ('sidebar:other-sidebar:right:width')).toBe ('480') }) + + it ('clamps current width on maxWidth changes without re-reading storage', async () => { + localStorage.setItem ('sidebar:test-sidebar:left:width', '420') + + const { container, rerender } = renderSidebar ({ maxWidth: 420 }, 900) + + await waitFor (() => { + expect (sidebarWidth (sidebarRoot (container))).toBe ('420px') + }) + + rerender (sidebarTree ({ maxWidth: 300 })) + + await waitFor (() => { + expect (sidebarWidth (sidebarRoot (container))).toBe ('300px') + }) + + rerender (sidebarTree ({ maxWidth: 500 })) + + await waitFor (() => { + expect (sidebarWidth (sidebarRoot (container))).toBe ('300px') + }) + }) }) diff --git a/frontend/src/components/layout/SidebarComponent.tsx b/frontend/src/components/layout/SidebarComponent.tsx index a96b7a2..ea4b015 100644 --- a/frontend/src/components/layout/SidebarComponent.tsx +++ b/frontend/src/components/layout/SidebarComponent.tsx @@ -69,6 +69,7 @@ const SidebarComponent: FC = ({ side = 'left', }) => { const rootRef = useRef (null) + const maxWidthRef = useRef (maxWidth) const getContainerWidth = useCallback (() => { const containerWidth = rootRef.current ?.closest ('[data-sidebar-container]') @@ -83,12 +84,14 @@ const SidebarComponent: FC = ({ typeof window === 'undefined' ? containerWidth : window.innerWidth const viewportMaxWidth = Math.floor (viewportWidth * MAX_VIEWPORT_WIDTH_RATIO) const maxAllowedWidth = - maxWidth == null + maxWidthRef.current == null ? getSidebarMaxWidth (containerWidth) - : Math.max (MIN_SIDEBAR_WIDTH, Math.min (viewportMaxWidth, maxWidth)) + : Math.max ( + MIN_SIDEBAR_WIDTH, + Math.min (viewportMaxWidth, maxWidthRef.current)) return Math.min (maxAllowedWidth, Math.max (MIN_SIDEBAR_WIDTH, nextWidth)) - }, [maxWidth]) + }, []) const [width, setWidth] = useState (() => ( typeof window === 'undefined' @@ -153,6 +156,21 @@ const SidebarComponent: FC = ({ restoreBodyStyle () }, [clearLongPressTimer, restoreBodyStyle, sidebarKey]) + const applyWidth = useCallback ((nextWidth: number) => { + if (nextWidth === widthRef.current) + return + + widthRef.current = nextWidth + setWidth (nextWidth) + }, []) + + useEffect (() => { + maxWidthRef.current = maxWidth + const containerWidth = getContainerWidth () + const nextWidth = getClampedWidth (widthRef.current, containerWidth) + applyWidth (nextWidth) + }, [applyWidth, getClampedWidth, getContainerWidth, maxWidth]) + const updateWidth = useCallback ((clientX: number) => { const state = resizeRef.current if (state == null) @@ -163,9 +181,8 @@ const SidebarComponent: FC = ({ ? clientX - state.startX : state.startX - clientX const nextWidth = getClampedWidth (state.startWidth + delta, containerWidth) - widthRef.current = nextWidth - setWidth (nextWidth) - }, [getClampedWidth, getContainerWidth]) + applyWidth (nextWidth) + }, [applyWidth, getClampedWidth, getContainerWidth]) const handlePointerDown = (ev: PointerEvent) => { if (ev.pointerType !== 'mouse' && ev.pointerType !== 'touch') @@ -235,10 +252,9 @@ const SidebarComponent: FC = ({ const resetWidth = useCallback (() => { const containerWidth = getContainerWidth () const nextWidth = getClampedWidth (DEFAULT_SIDEBAR_WIDTH, containerWidth) - widthRef.current = nextWidth - setWidth (nextWidth) + applyWidth (nextWidth) window.localStorage.removeItem (storageKeyForSidebar (sidebarKey, side)) - }, [getClampedWidth, getContainerWidth, sidebarKey, side]) + }, [applyWidth, getClampedWidth, getContainerWidth, sidebarKey, side]) const handleDoubleClick = (ev: MouseEvent) => { ev.preventDefault () @@ -251,9 +267,14 @@ const SidebarComponent: FC = ({ const nextWidth = getClampedWidth ( readStoredSidebarWidth (sidebarKey, side), containerWidth) - widthRef.current = nextWidth - setWidth (nextWidth) - }, [getClampedWidth, getContainerWidth, sidebarKey, side]) + applyWidth (nextWidth) + }, [applyWidth, getClampedWidth, getContainerWidth, sidebarKey, side]) + + useEffect (() => { + const containerWidth = getContainerWidth () + const nextWidth = getClampedWidth (widthRef.current, containerWidth) + applyWidth (nextWidth) + }, [applyWidth, getClampedWidth, getContainerWidth]) useEffect (() => { if (typeof window === 'undefined') @@ -262,16 +283,12 @@ const SidebarComponent: FC = ({ const handleResize = () => { const containerWidth = getContainerWidth () const nextWidth = getClampedWidth (widthRef.current, containerWidth) - if (nextWidth === widthRef.current) - return - - widthRef.current = nextWidth - setWidth (nextWidth) + applyWidth (nextWidth) } window.addEventListener ('resize', handleResize) return () => window.removeEventListener ('resize', handleResize) - }, [getClampedWidth, getContainerWidth]) + }, [applyWidth, getClampedWidth, getContainerWidth]) useEffect (() => { onWidthChange?.(width) diff --git a/frontend/src/pages/materials/MaterialBasePage.tsx b/frontend/src/pages/materials/MaterialBasePage.tsx index c7b6292..c444b79 100644 --- a/frontend/src/pages/materials/MaterialBasePage.tsx +++ b/frontend/src/pages/materials/MaterialBasePage.tsx @@ -6,9 +6,11 @@ import type { FC } from 'react' const MaterialBasePage: FC = () => ( -
+
) -export default MaterialBasePage \ No newline at end of file +export default MaterialBasePage diff --git a/frontend/src/pages/posts/PostDetailPage.tsx b/frontend/src/pages/posts/PostDetailPage.tsx index e5e823d..015c16c 100644 --- a/frontend/src/pages/posts/PostDetailPage.tsx +++ b/frontend/src/pages/posts/PostDetailPage.tsx @@ -92,16 +92,16 @@ const PostDetailPage: FC = ({ user }) => { : 'bg-gray-500 hover:bg-gray-600') return ( -
+
{(post?.thumbnail || post?.thumbnailBase) && ( )} {post && {`${ post.title || post.url } | ${ SITE_TITLE }`}} -
- {post && } -
+ {post && } {post @@ -179,9 +179,7 @@ const PostDetailPage: FC = ({ user }) => { : 'Loading...'} -
- {post && } -
+ {post && }
) } diff --git a/frontend/src/pages/posts/PostListPage.tsx b/frontend/src/pages/posts/PostListPage.tsx index 9fe7d25..6b116c8 100644 --- a/frontend/src/pages/posts/PostListPage.tsx +++ b/frontend/src/pages/posts/PostListPage.tsx @@ -70,6 +70,7 @@ const PostListPage: FC = () => { return (