summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-07 03:51:26 -0800
committerFuwn <[email protected]>2026-02-07 03:51:26 -0800
commitfa0a6387dfb4a3ddc2dc8b37a53e1562432298a0 (patch)
tree54b57f4e541c9e1a7ec2962c28235847c3b87201
parentfix: measure sidebar min width from children intrinsic widths (diff)
downloadasa.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.tsx31
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`)