diff options
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/web/app/reader/_components/command-palette.tsx | 36 | ||||
| -rw-r--r-- | apps/web/app/reader/_components/reader-layout-shell.tsx | 42 | ||||
| -rw-r--r-- | apps/web/app/reader/_components/reader-shell.tsx | 21 | ||||
| -rw-r--r-- | apps/web/lib/stores/user-interface-store.ts | 12 |
4 files changed, 74 insertions, 37 deletions
diff --git a/apps/web/app/reader/_components/command-palette.tsx b/apps/web/app/reader/_components/command-palette.tsx index e9b7b04..cca04b6 100644 --- a/apps/web/app/reader/_components/command-palette.tsx +++ b/apps/web/app/reader/_components/command-palette.tsx @@ -195,39 +195,9 @@ export function CommandPalette() { <Command.Item onSelect={() => actionAndClose(() => { - const sidebarPanel = document.querySelector('[data-panel-id="sidebar"]') as HTMLElement | null - const mainContentPanel = document.querySelector('[data-panel-id="main-content"]') as HTMLElement | null - if (sidebarPanel && mainContentPanel) { - const totalPixels = sidebarPanel.offsetWidth + mainContentPanel.offsetWidth - const minPixels = 192 - const maxPixels = parseInt(sidebarPanel.style.maxWidth, 10) || Math.round(totalPixels * 0.35) - const midpoint = Math.round((minPixels + maxPixels) / 2) - localStorage.setItem( - "react-resizable-panels:asa-sidebar-layout:sidebar:main-content", - JSON.stringify({ sidebar: midpoint, "main-content": totalPixels - midpoint }) - ) - } else { - localStorage.removeItem( - "react-resizable-panels:asa-sidebar-layout:sidebar:main-content" - ) - } - - const entryListPanel = document.querySelector('[data-panel-id="entry-list"]') as HTMLElement | null - const detailPanel = document.querySelector('[data-panel-id="detail-panel"]') as HTMLElement | null - if (entryListPanel && detailPanel) { - const totalPixels = entryListPanel.offsetWidth + detailPanel.offsetWidth - const halfPixels = Math.round(totalPixels / 2) - localStorage.setItem( - "react-resizable-panels:asa-detail-layout:entry-list:detail-panel", - JSON.stringify({ "entry-list": halfPixels, "detail-panel": totalPixels - halfPixels }) - ) - } else { - localStorage.removeItem( - "react-resizable-panels:asa-detail-layout:entry-list:detail-panel" - ) - } - - window.location.reload() + const store = useUserInterfaceStore.getState() + store.resetSidebarLayout?.() + store.resetDetailLayout?.() }) } className="cursor-pointer px-2 py-1 text-text-secondary aria-selected:bg-background-tertiary aria-selected:text-text-primary" diff --git a/apps/web/app/reader/_components/reader-layout-shell.tsx b/apps/web/app/reader/_components/reader-layout-shell.tsx index 3ff2fa8..9d2eb24 100644 --- a/apps/web/app/reader/_components/reader-layout-shell.tsx +++ b/apps/web/app/reader/_components/reader-layout-shell.tsx @@ -1,7 +1,7 @@ "use client" -import { Suspense, useEffect, useMemo, useState } from "react" -import { Group, Panel, Separator, useDefaultLayout } from "react-resizable-panels" +import { Suspense, useEffect, useMemo, useRef, useState } from "react" +import { Group, Panel, Separator, useDefaultLayout, useGroupRef } from "react-resizable-panels" import { useUserInterfaceStore } from "@/lib/stores/user-interface-store" import { classNames } from "@/lib/utilities" import { useIsMobile } from "@/lib/hooks/use-is-mobile" @@ -60,7 +60,7 @@ export function ReaderLayoutShell({ const sidebarMaxWidth = useMemo(() => { if (typeof window === "undefined") return "35%" - if (!subscriptionsData && !customFeedsData) return "35%" + if (!subscriptionsData || !customFeedsData) return "35%" const canvas = document.createElement("canvas") const maybeContext = canvas.getContext("2d") @@ -159,6 +159,41 @@ export function ReaderLayoutShell({ storage: typeof window !== "undefined" ? localStorage : { getItem: () => null, setItem: () => {} }, }) + const sidebarGroupRef = useGroupRef() + const sidebarMaxWidthRef = useRef(sidebarMaxWidth) + sidebarMaxWidthRef.current = sidebarMaxWidth + const sidebarOnLayoutChangedRef = useRef(sidebarLayout.onLayoutChanged) + sidebarOnLayoutChangedRef.current = sidebarLayout.onLayoutChanged + + useEffect(() => { + useUserInterfaceStore.getState().setResetSidebarLayout(() => { + const group = sidebarGroupRef.current + if (!group) return + const groupElement = document.querySelector("[data-group]") as HTMLElement | null + if (!groupElement) return + const totalPixels = groupElement.offsetWidth + if (totalPixels === 0) return + const minPixels = 192 + const maxWidthValue = sidebarMaxWidthRef.current + let maxPixels: number + if (maxWidthValue.endsWith("px")) { + maxPixels = parseFloat(maxWidthValue) + } else if (maxWidthValue.endsWith("%")) { + maxPixels = totalPixels * parseFloat(maxWidthValue) / 100 + } else { + maxPixels = totalPixels * 0.35 + } + const midpointPixels = Math.round((minPixels + maxPixels) / 2) + const midpointPercent = (midpointPixels / totalPixels) * 100 + const appliedLayout = group.setLayout({ + sidebar: midpointPercent, + "main-content": 100 - midpointPercent, + }) + sidebarOnLayoutChangedRef.current?.(appliedLayout) + }) + return () => useUserInterfaceStore.getState().setResetSidebarLayout(null) + }, [sidebarGroupRef]) + useKeyboardNavigation() useEffect(() => { @@ -308,6 +343,7 @@ export function ReaderLayoutShell({ orientation="horizontal" defaultLayout={sidebarLayout.defaultLayout} onLayoutChanged={isSidebarCollapsed ? undefined : sidebarLayout.onLayoutChanged} + groupRef={sidebarGroupRef} > {!isSidebarCollapsed && ( <> diff --git a/apps/web/app/reader/_components/reader-shell.tsx b/apps/web/app/reader/_components/reader-shell.tsx index 09278c3..247ec8d 100644 --- a/apps/web/app/reader/_components/reader-shell.tsx +++ b/apps/web/app/reader/_components/reader-shell.tsx @@ -1,6 +1,7 @@ "use client" -import { Group, Panel, Separator, useDefaultLayout } from "react-resizable-panels" +import { useEffect, useRef } from "react" +import { Group, Panel, Separator, useDefaultLayout, useGroupRef } from "react-resizable-panels" import { useUserInterfaceStore } from "@/lib/stores/user-interface-store" import { useMarkAllAsRead } from "@/lib/queries/use-mark-all-as-read" import { useSubscriptions } from "@/lib/queries/use-subscriptions" @@ -58,6 +59,23 @@ export function ReaderShell({ storage: typeof window !== "undefined" ? localStorage : { getItem: () => null, setItem: () => {} }, }) + const detailGroupRef = useGroupRef() + const detailOnLayoutChangedRef = useRef(detailLayout.onLayoutChanged) + detailOnLayoutChangedRef.current = detailLayout.onLayoutChanged + + useEffect(() => { + useUserInterfaceStore.getState().setResetDetailLayout(() => { + const group = detailGroupRef.current + if (!group) return + const appliedLayout = group.setLayout({ + "entry-list": 50, + "detail-panel": 50, + }) + detailOnLayoutChangedRef.current?.(appliedLayout) + }) + return () => useUserInterfaceStore.getState().setResetDetailLayout(null) + }, [detailGroupRef]) + useRealtimeEntries() let pageTitle = feedFilter === "saved" ? "saved" : "all entries" @@ -192,6 +210,7 @@ export function ReaderShell({ className="min-h-0 flex-1" defaultLayout={detailLayout.defaultLayout} onLayoutChanged={detailLayout.onLayoutChanged} + groupRef={detailGroupRef} > <Panel id="entry-list" defaultSize={selectedEntryIdentifier ? "40%" : "100%"} minSize="25%"> <div data-panel-zone="entryList" className={classNames( diff --git a/apps/web/lib/stores/user-interface-store.ts b/apps/web/lib/stores/user-interface-store.ts index 5890167..01dceba 100644 --- a/apps/web/lib/stores/user-interface-store.ts +++ b/apps/web/lib/stores/user-interface-store.ts @@ -44,6 +44,8 @@ interface UserInterfaceState { isShortcutsDialogOpen: boolean expandedFolderIdentifiers: string[] navigableEntryIdentifiers: string[] + resetSidebarLayout: (() => void) | null + resetDetailLayout: (() => void) | null toggleSidebar: () => void setSidebarCollapsed: (isCollapsed: boolean) => void @@ -67,6 +69,8 @@ interface UserInterfaceState { toggleShortcutsDialog: () => void toggleFolderExpansion: (folderIdentifier: string) => void setNavigableEntryIdentifiers: (identifiers: string[]) => void + setResetSidebarLayout: (callback: (() => void) | null) => void + setResetDetailLayout: (callback: (() => void) | null) => void } export const useUserInterfaceStore = create<UserInterfaceState>()( @@ -92,6 +96,8 @@ export const useUserInterfaceStore = create<UserInterfaceState>()( isShortcutsDialogOpen: false, expandedFolderIdentifiers: [], navigableEntryIdentifiers: [], + resetSidebarLayout: null, + resetDetailLayout: null, toggleSidebar: () => set((state) => ({ isSidebarCollapsed: !state.isSidebarCollapsed })), @@ -155,6 +161,12 @@ export const useUserInterfaceStore = create<UserInterfaceState>()( setNavigableEntryIdentifiers: (identifiers) => set({ navigableEntryIdentifiers: identifiers }), + + setResetSidebarLayout: (callback) => + set({ resetSidebarLayout: callback }), + + setResetDetailLayout: (callback) => + set({ resetDetailLayout: callback }), }), { name: "asa-news-ui-preferences", |