import HelpAndAccountMenu from '@/components/HelpAndAccountMenu' import ScrollToTopButton from '@/components/ScrollToTopButton' import { ReadOnlySessionIndicator } from '@/components/ReadOnlySessionIndicator' import { Titlebar } from '@/components/Titlebar' import { Button } from '@/components/ui/button' import { FOCUS_SECONDARY_SCROLL_SHORTCUT_KEY, isRadixDialogOpen, shouldIgnoreKeyboardShortcutEvent } from '@/lib/keyboard-shortcuts' import { useSecondaryPage } from '@/PageManager' import { DeepBrowsingProvider } from '@/providers/DeepBrowsingProvider' import { useScreenSize } from '@/providers/ScreenSizeProvider' import { cn } from '@/lib/utils' import { ChevronLeft } from 'lucide-react' import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react' import { useTranslation } from 'react-i18next' const SecondaryPageLayout = forwardRef( ( { children, index, title, controls, hideBackButton = false, hideTitlebarBottomBorder = false, displayScrollToTopButton = false, titlebar }: { children?: React.ReactNode index?: number title?: React.ReactNode controls?: React.ReactNode hideBackButton?: boolean hideTitlebarBottomBorder?: boolean displayScrollToTopButton?: boolean titlebar?: React.ReactNode }, ref ) => { const scrollAreaRef = useRef(null) const { isSmallScreen } = useScreenSize() const { currentIndex } = useSecondaryPage() const shouldRenderTitlebar = titlebar != null || (title != null && title !== '') || !hideBackButton useImperativeHandle( ref, () => ({ scrollToTop: (behavior: ScrollBehavior = 'smooth') => { setTimeout(() => { if (scrollAreaRef.current) { return scrollAreaRef.current.scrollTo({ top: 0, behavior }) } window.scrollTo({ top: 0, behavior }) }, 10) } }), [] ) useEffect(() => { if (!isSmallScreen) return setTimeout(() => scrollAreaRef.current?.scrollTo({ top: 0 }), 10) }, [isSmallScreen]) useEffect(() => { if (isSmallScreen) return if (currentIndex !== index) return const onKeyDown = (e: KeyboardEvent) => { if (!e.altKey || !e.shiftKey || e.key.toLowerCase() !== FOCUS_SECONDARY_SCROLL_SHORTCUT_KEY) return if (e.metaKey || e.ctrlKey) return if (shouldIgnoreKeyboardShortcutEvent(e.target)) return if (isRadixDialogOpen()) return e.preventDefault() scrollAreaRef.current?.focus({ preventScroll: true }) } document.addEventListener('keydown', onKeyDown) return () => document.removeEventListener('keydown', onKeyDown) }, [isSmallScreen, currentIndex, index]) if (isSmallScreen) { return (
{shouldRenderTitlebar ? ( ) : null}
{children}
{displayScrollToTopButton && }
) } return (
{shouldRenderTitlebar ? ( ) : null}
{children}
{displayScrollToTopButton && } ) } ) SecondaryPageLayout.displayName = 'SecondaryPageLayout' export default SecondaryPageLayout function SecondaryPageTitlebar({ title, controls, hideBackButton = false, hideBottomBorder = false, titlebar, sticky = false }: { title?: React.ReactNode controls?: React.ReactNode hideBackButton?: boolean hideBottomBorder?: boolean titlebar?: React.ReactNode /** Keep back visible while the page scrolls (mobile secondary stack). */ sticky?: boolean }): JSX.Element { const { isSmallScreen } = useScreenSize() const { t } = useTranslation() const titlebarInset = isSmallScreen ? 'py-1 pl-2 pr-[max(0.75rem,env(safe-area-inset-right,0px))]' : 'p-1' const stickyClass = sticky ? 'sticky top-0 z-20 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80' : '' if (titlebar) { return (
{titlebar}
{isSmallScreen ? : null}
) } return (
{hideBackButton ? ( title ? (
{title}
) : null ) : (
{title ?? t('back')}
)}
{controls}
{isSmallScreen ? : null}
) } function BackButton({ children }: { children?: React.ReactNode }) { const { t } = useTranslation() const { pop } = useSecondaryPage() return ( ) }