Files
boris/src/components/ThreePaneLayout.tsx
Gigi 507288f51c feat: add image caching for offline mode
- Add imageCacheService with localStorage-based image caching and LRU eviction
- Create useImageCache hook for React components to fetch and cache images
- Integrate image caching with article service to cache cover images on load
- Add image cache settings (enable/disable, size limit) to user settings
- Update ReaderHeader to use cached images for article covers
- Update BookmarkViews (CardView, LargeView) to use cached images
- Add image cache configuration UI in OfflineModeSettings with:
  - Toggle to enable/disable image caching
  - Slider to set cache size limit (10-200 MB)
  - Display current cache stats (size and image count)
  - Clear cache button

Images are cached in localStorage for offline viewing, with a configurable
size limit (default 50MB). LRU eviction ensures cache stays within limits.
2025-10-09 17:23:31 +01:00

173 lines
6.2 KiB
TypeScript

import React from 'react'
import { RelayPool } from 'applesauce-relay'
import { IEventStore } from 'applesauce-core'
import { BookmarkList } from './BookmarkList'
import ContentPanel from './ContentPanel'
import { HighlightsPanel } from './HighlightsPanel'
import Settings from './Settings'
import Toast from './Toast'
import { HighlightButton } from './HighlightButton'
import { RelayStatusIndicator } from './RelayStatusIndicator'
import { ViewMode } from './Bookmarks'
import { Bookmark } from '../types/bookmarks'
import { Highlight } from '../types/highlights'
import { ReadableContent } from '../services/readerService'
import { UserSettings } from '../services/settingsService'
import { HighlightVisibility } from './HighlightsPanel'
import { HighlightButtonRef } from './HighlightButton'
import { BookmarkReference } from '../utils/contentLoader'
interface ThreePaneLayoutProps {
// Layout state
isCollapsed: boolean
isHighlightsCollapsed: boolean
showSettings: boolean
// Bookmarks pane
bookmarks: Bookmark[]
bookmarksLoading: boolean
viewMode: ViewMode
isRefreshing: boolean
onToggleSidebar: () => void
onLogout: () => void
onViewModeChange: (mode: ViewMode) => void
onOpenSettings: () => void
onRefresh: () => void
relayPool: RelayPool | null
eventStore: IEventStore | null
// Content pane
readerLoading: boolean
readerContent?: ReadableContent
selectedUrl?: string
settings: UserSettings
onSaveSettings: (settings: UserSettings) => Promise<void>
onCloseSettings: () => void
classifiedHighlights: Highlight[]
showHighlights: boolean
selectedHighlightId?: string
highlightVisibility: HighlightVisibility
onHighlightClick: (id: string) => void
onTextSelection: (text: string) => void
onClearSelection: () => void
currentUserPubkey?: string
followedPubkeys: Set<string>
// Highlights pane
highlights: Highlight[]
highlightsLoading: boolean
onToggleHighlightsPanel: () => void
onSelectUrl: (url: string, bookmark?: BookmarkReference) => void
onToggleHighlights: (show: boolean) => void
onRefreshHighlights: () => void
onHighlightVisibilityChange: (visibility: HighlightVisibility) => void
// Highlight button
highlightButtonRef: React.RefObject<HighlightButtonRef>
onCreateHighlight: (text: string) => void
hasActiveAccount: boolean
// Toast
toastMessage?: string
toastType?: 'success' | 'error'
onClearToast: () => void
}
const ThreePaneLayout: React.FC<ThreePaneLayoutProps> = (props) => {
return (
<>
<div className={`three-pane ${props.isCollapsed ? 'sidebar-collapsed' : ''} ${props.isHighlightsCollapsed ? 'highlights-collapsed' : ''}`}>
<div className="pane sidebar">
<BookmarkList
bookmarks={props.bookmarks}
onSelectUrl={props.onSelectUrl}
isCollapsed={props.isCollapsed}
onToggleCollapse={props.onToggleSidebar}
onLogout={props.onLogout}
viewMode={props.viewMode}
onViewModeChange={props.onViewModeChange}
selectedUrl={props.selectedUrl}
onOpenSettings={props.onOpenSettings}
onRefresh={props.onRefresh}
isRefreshing={props.isRefreshing}
loading={props.bookmarksLoading}
relayPool={props.relayPool}
settings={props.settings}
/>
</div>
<div className="pane main">
{props.showSettings ? (
<Settings
settings={props.settings}
onSave={props.onSaveSettings}
onClose={props.onCloseSettings}
relayPool={props.relayPool}
/>
) : (
<ContentPanel
loading={props.readerLoading}
title={props.readerContent?.title}
html={props.readerContent?.html}
markdown={props.readerContent?.markdown}
image={props.readerContent?.image}
summary={props.readerContent?.summary}
published={props.readerContent?.published}
selectedUrl={props.selectedUrl}
highlights={props.classifiedHighlights}
showHighlights={props.showHighlights}
highlightStyle={props.settings.highlightStyle || 'marker'}
highlightColor={props.settings.highlightColor || '#ffff00'}
onHighlightClick={props.onHighlightClick}
selectedHighlightId={props.selectedHighlightId}
highlightVisibility={props.highlightVisibility}
onTextSelection={props.onTextSelection}
onClearSelection={props.onClearSelection}
currentUserPubkey={props.currentUserPubkey}
followedPubkeys={props.followedPubkeys}
settings={props.settings}
/>
)}
</div>
<div className="pane highlights">
<HighlightsPanel
highlights={props.highlights}
loading={props.highlightsLoading}
isCollapsed={props.isHighlightsCollapsed}
onToggleCollapse={props.onToggleHighlightsPanel}
onSelectUrl={props.onSelectUrl}
selectedUrl={props.selectedUrl}
onToggleHighlights={props.onToggleHighlights}
selectedHighlightId={props.selectedHighlightId}
onRefresh={props.onRefreshHighlights}
onHighlightClick={props.onHighlightClick}
currentUserPubkey={props.currentUserPubkey}
highlightVisibility={props.highlightVisibility}
onHighlightVisibilityChange={props.onHighlightVisibilityChange}
followedPubkeys={props.followedPubkeys}
relayPool={props.relayPool}
eventStore={props.eventStore}
/>
</div>
</div>
{props.hasActiveAccount && (
<HighlightButton
ref={props.highlightButtonRef}
onHighlight={props.onCreateHighlight}
highlightColor={props.settings.highlightColor || '#ffff00'}
/>
)}
<RelayStatusIndicator relayPool={props.relayPool} />
{props.toastMessage && (
<Toast
message={props.toastMessage}
type={props.toastType}
onClose={props.onClearToast}
/>
)}
</>
)
}
export default ThreePaneLayout