diff options
| author | Fuwn <[email protected]> | 2026-02-07 03:54:42 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-07 03:54:42 -0800 |
| commit | a7e4bb39eb7d4a4541dacdd43ce94656bddca311 (patch) | |
| tree | e68c8949a44a09fb08c4cbb87b13057e5b688655 /apps | |
| parent | fix: use Canvas text measurement for sidebar min width (diff) | |
| download | asa.news-a7e4bb39eb7d4a4541dacdd43ce94656bddca311.tar.xz asa.news-a7e4bb39eb7d4a4541dacdd43ce94656bddca311.zip | |
fix: include sidebar footer items in min width measurement
Notifications button text is wider than all entries. Now measures
all nav items AND footer links/buttons, taking the widest row plus
badge reserve as the sidebar minimum width.
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/web/app/reader/_components/reader-layout-shell.tsx | 67 |
1 files changed, 48 insertions, 19 deletions
diff --git a/apps/web/app/reader/_components/reader-layout-shell.tsx b/apps/web/app/reader/_components/reader-layout-shell.tsx index d3e5648..ac03ce4 100644 --- a/apps/web/app/reader/_components/reader-layout-shell.tsx +++ b/apps/web/app/reader/_components/reader-layout-shell.tsx @@ -52,37 +52,66 @@ export function ReaderLayoutShell({ const [sidebarDefaultWidth, setSidebarDefaultWidth] = useState("220px") const measureSidebarWidths = useCallback(() => { - const firstNavigationItem = document.querySelector("[data-sidebar-nav-item]") - if (!firstNavigationItem) return + const sidebarElement = document.querySelector("[data-panel-zone='sidebar']") + if (!sidebarElement) return const canvas = document.createElement("canvas") const canvasContext = canvas.getContext("2d") if (!canvasContext) return - const children = firstNavigationItem.querySelectorAll(":scope > *") - let totalTextWidth = 0 + function measureElementTextWidth( + element: Element, + context: CanvasRenderingContext2D + ): number { + const elementChildren = element.querySelectorAll(":scope > *") + if (elementChildren.length === 0) { + const computedStyle = getComputedStyle(element) + context.font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}` + return Math.ceil( + context.measureText(element.textContent ?? "").width + ) + } + let width = 0 + for (const child of elementChildren) { + const computedStyle = getComputedStyle(child) + context.font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}` + width += Math.ceil( + context.measureText(child.textContent ?? "").width + ) + } + return width + } + + let widestRowWidth = 0 - for (const child of children) { - const computedStyle = getComputedStyle(child) - canvasContext.font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}` - totalTextWidth += Math.ceil( - canvasContext.measureText(child.textContent ?? "").width - ) + const navigationItems = sidebarElement.querySelectorAll("[data-sidebar-nav-item]") + for (const navigationItem of navigationItems) { + const rowWidth = measureElementTextWidth(navigationItem, canvasContext) + widestRowWidth = Math.max(widestRowWidth, rowWidth) } - if (children.length < 2) { - const parentStyle = getComputedStyle(firstNavigationItem) - canvasContext.font = `400 0.625rem ${parentStyle.fontFamily}` - totalTextWidth += Math.ceil(canvasContext.measureText("999+").width) + const footerButtons = sidebarElement.querySelectorAll( + ".border-t a, .border-t button" + ) + for (const footerButton of footerButtons) { + const rowWidth = measureElementTextWidth(footerButton, canvasContext) + widestRowWidth = Math.max(widestRowWidth, rowWidth) } - const linkHorizontalPadding = 16 - const navigationContainerPadding = 16 + const sidebarStyle = getComputedStyle(sidebarElement) + canvasContext.font = `400 0.625rem ${sidebarStyle.fontFamily}` + const badgeReservedWidth = Math.ceil( + canvasContext.measureText("999+").width + ) + + const itemHorizontalPadding = 16 + const containerHorizontalPadding = 16 const minimumGap = 8 const measuredMinimumWidth = - totalTextWidth + - linkHorizontalPadding + - navigationContainerPadding + + widestRowWidth + + badgeReservedWidth + + itemHorizontalPadding + + containerHorizontalPadding + minimumGap setSidebarMinimumWidth(`${measuredMinimumWidth}px`) |