import { useEffect, useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { FileText, PanelRightClose, PanelRightOpen } from 'lucide-react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { api } from '../api/client'; interface FolderReadmePanelProps { folderId: number; } // Persist the collapsed choice so hiding the README once keeps it hidden // across folder switches and page reloads (#2520 item 2). const COLLAPSE_STORAGE_KEY = 'fileManager.readmeCollapsed'; /** * Markdown panel for the selected folder (#1268). * * Docks as a collapsible right-hand rail on wide screens so the README sits * *beside* the file list instead of pushing it down and eating vertical * space (#2520 item 2); on narrow screens it stacks above the list * (`order-first`) where the page itself scrolls. Collapsing shrinks it to a * thin strip (desktop) / slim bar (mobile) with a one-click reopen, and the * choice is persisted. Auto-hidden when the folder has no markdown. Raw HTML * is disabled and links stay text-only — same posture as the print-archive * note panel. */ export function FolderReadmePanel({ folderId }: FolderReadmePanelProps) { const { t } = useTranslation(); const [collapsed, setCollapsed] = useState( () => localStorage.getItem(COLLAPSE_STORAGE_KEY) === '1', ); useEffect(() => { localStorage.setItem(COLLAPSE_STORAGE_KEY, collapsed ? '1' : '0'); }, [collapsed]); const { data, isLoading, error } = useQuery({ queryKey: ['folder-readme', folderId], queryFn: () => api.getLibraryFolderReadme(folderId), retry: false, staleTime: 30_000, }); if (isLoading || error || !data) return null; if (collapsed) { return (
{/* Mobile: a slim horizontal bar that reopens the panel. */} {/* Desktop: a thin vertical strip with a reopen button. */}
); } return (
{data.filename} {data.truncated && ( {t('fileManager.readme.truncated')} )}

{children}

, h2: ({ children }) =>

{children}

, h3: ({ children }) =>

{children}

, p: ({ children }) =>

{children}

, ul: ({ children }) =>
    {children}
, ol: ({ children }) =>
    {children}
, li: ({ children }) =>
  • {children}
  • , code: ({ children, ...props }) => { const inline = !(props as { className?: string }).className; return inline ? ( {children} ) : ( {children} ); }, pre: ({ children }) =>
    {children}
    , blockquote: ({ children }) => (
    {children}
    ), a: ({ children, href }) => ( {children} ), table: ({ children }) => (
    {children}
    ), th: ({ children }) => {children}, td: ({ children }) => {children}, hr: () =>
    , }} > {data.content}
    ); }