summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-07 03:54:42 -0800
committerFuwn <[email protected]>2026-02-07 03:54:42 -0800
commita7e4bb39eb7d4a4541dacdd43ce94656bddca311 (patch)
treee68c8949a44a09fb08c4cbb87b13057e5b688655 /apps
parentfix: use Canvas text measurement for sidebar min width (diff)
downloadasa.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.tsx67
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`)