diff options
| author | Fuwn <[email protected]> | 2026-02-07 03:51:26 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-07 03:51:26 -0800 |
| commit | fa0a6387dfb4a3ddc2dc8b37a53e1562432298a0 (patch) | |
| tree | 54b57f4e541c9e1a7ec2962c28235847c3b87201 | |
| parent | fix: measure sidebar min width from children intrinsic widths (diff) | |
| download | asa.news-fa0a6387dfb4a3ddc2dc8b37a53e1562432298a0.tar.xz asa.news-fa0a6387dfb4a3ddc2dc8b37a53e1562432298a0.zip | |
fix: use Canvas text measurement for sidebar min width
getBoundingClientRect on wrapped text returns the narrow wrapped
width, not the single-line width. Canvas measureText is layout-
independent and gives the true single-line intrinsic text width.
| -rw-r--r-- | apps/web/app/reader/_components/reader-layout-shell.tsx | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/apps/web/app/reader/_components/reader-layout-shell.tsx b/apps/web/app/reader/_components/reader-layout-shell.tsx index bc7be8b..d3e5648 100644 --- a/apps/web/app/reader/_components/reader-layout-shell.tsx +++ b/apps/web/app/reader/_components/reader-layout-shell.tsx @@ -55,20 +55,35 @@ export function ReaderLayoutShell({ const firstNavigationItem = document.querySelector("[data-sidebar-nav-item]") if (!firstNavigationItem) return - let intrinsicContentWidth = 0 - for (const child of firstNavigationItem.children) { - intrinsicContentWidth += child.getBoundingClientRect().width + const canvas = document.createElement("canvas") + const canvasContext = canvas.getContext("2d") + if (!canvasContext) return + + const children = firstNavigationItem.querySelectorAll(":scope > *") + let totalTextWidth = 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 + ) } - if (firstNavigationItem.children.length < 2) { - intrinsicContentWidth += 28 + if (children.length < 2) { + const parentStyle = getComputedStyle(firstNavigationItem) + canvasContext.font = `400 0.625rem ${parentStyle.fontFamily}` + totalTextWidth += Math.ceil(canvasContext.measureText("999+").width) } const linkHorizontalPadding = 16 const navigationContainerPadding = 16 - const measuredMinimumWidth = Math.ceil( - intrinsicContentWidth + linkHorizontalPadding + navigationContainerPadding - ) + const minimumGap = 8 + const measuredMinimumWidth = + totalTextWidth + + linkHorizontalPadding + + navigationContainerPadding + + minimumGap setSidebarMinimumWidth(`${measuredMinimumWidth}px`) setSidebarDefaultWidth(`${Math.round(measuredMinimumWidth * 1.5)}px`) |