Skip to content

Redesign document list with Finder-style views, sidebar workflows, and recents polish#91

Open
richardr1126 wants to merge 23 commits into
mainfrom
redesign/app-view-documents-list
Open

Redesign document list with Finder-style views, sidebar workflows, and recents polish#91
richardr1126 wants to merge 23 commits into
mainfrom
redesign/app-view-documents-list

Conversation

@richardr1126
Copy link
Copy Markdown
Owner

@richardr1126 richardr1126 commented May 28, 2026

Summary

  • Replace the legacy document list/folder UI with a Finder-style workspace (toolbar, resizable sidebar, status bar, icons/list/gallery views).
  • Introduce shared drag-and-drop and selection infrastructure for multi-select drag operations and folder workflows.
  • Add sidebar filters (all/recents/kinds/folders), recently-opened metadata, and persisted list/view/sidebar preferences.
  • Refresh uploader and skeleton states, modernize document preview/cache behavior, and update test selectors for the new UI.
  • Polish mobile behavior and recents UX: mobile drawer now closes on explicit row actions only, recents hides sort controls, and status shows visible selected-count.

Major Changes

  • New doclist window shell and controls: FinderWindow, FinderToolbar, FinderSidebar, FinderStatusBar.
  • New views/components: IconsView, ListView, GalleryView, DocumentTile, iconsGrid.
  • New drag/selection layer: DocumentDndProvider, DocumentSelectionContext, dndTypes.
  • DocumentList rewritten around new view/filter state model and persisted sidebar/view settings.
  • Removed legacy components: DocumentFolder, DocumentListItem, SortControls.
  • Added touch DnD backend dependency and cache/recently-opened metadata enhancements.

Summary by CodeRabbit

  • New Features

    • Full “finder” document UI: icons/list/gallery views, detail pane, toolbar, resizable sidebar with folder filters, and folder creation via drag‑and‑drop
    • Multi‑select, batch actions, and touch‑friendly drag‑and‑drop (merge/move)
    • Uploader: new overlay mode plus compact/default variants
  • Improvements

    • Document previews show human‑readable sizes and faster image readiness
    • Simplified home layout to surface documents immediately
    • Accessibility and test locator refinements

Review Change Stack

…ndowed UI

Revamp the document list experience by introducing a Finder-style window
interface with multiple views (icons, list, columns, gallery) and a new
sidebar filter system. Remove legacy folder and list item components in
favor of modular, windowed views. Integrate react-dnd-touch-backend and
custom DnD context for improved drag-and-drop, including mobile support.
Update uploader and dialog styles for consistency. Extend document types
to support new view modes, icon sizing, and sidebar state.
…roved file size formatting

Integrate DocumentUploader in overlay mode to wrap all document views, enabling drag-and-drop uploads across the entire list area. Refine file size formatting to support KB, MB, and GB units in all views and tiles. Standardize button scaling and padding for consistent UI rhythm. Update DocumentPreview and detail panels to display both type and human-readable size. Add overlay drag visual feedback for uploads.

These changes improve usability, visual clarity, and consistency in the document list interface.
…tons and columns UI

Simplify document list state handling by centralizing loading and empty logic into DocumentList.
Remove redundant state management from HomeContent. Refactor DocumentListSkeleton to support all view modes and icon sizes for improved visual consistency during loading. Enhance ColumnsView styling for folder and document rows, improving selection, hover, and drag feedback. Use useMemo for visible order calculation to optimize rendering.

These changes streamline the document list rendering flow, unify skeleton loading visuals, and improve the clarity and responsiveness of the columns view interface.
… in document list

Enhance mobile and desktop sidebar behavior by introducing a separate state for mobile sidebar visibility and ensuring it does not persist from desktop state. Update FinderToolbar to visually indicate sidebar open state and make the toolbar sticky for better accessibility. Refine FinderSidebar width handling for improved responsiveness. Remove redundant border in mobile sidebar dialog for a cleaner appearance. These changes provide a more consistent and intuitive sidebar experience across viewports.
… variables

Replace fixed Tailwind grid column classes with a responsive CSS grid
that leverages tile width variables per icon size. Grid columns now
adapt automatically via `auto-fit` and `minmax`, and grid gaps are
centralized for consistency. This update enhances layout flexibility,
maintainability, and responsiveness in the icons view.
…iew toggle

Replace inline icon size buttons with a dropdown menu that appears when
the icons view toggle is active. This change improves toolbar clarity by
grouping related controls and enhances accessibility with better focus
handling. The update also streamlines the button structure for view mode
selection.
…list

Introduce recentlyOpenedAt field to document types and fetch per-document
recently opened timestamps from local cache. Update the "Recently Opened"
sidebar filter to sort by this value and show only documents with recent
activity. Adjust grid layout logic for icons view to better handle small
numbers of documents. Update sidebar label for clarity.
…der UI

Eliminate folder grouping logic and related UI from all document list views.
Switch to a flat document array model for rendering, selection, and filtering.
Remove folder collapse/expand state and folder drag-and-drop handling. Update
sidebar and toolbar components to remove folder creation and management
controls. Simplify props and internal state across all views for consistency.
…eadiness

Update gallery view document tiles with refined border, shadow, and background
styles for better visual feedback and accessibility. Enhance image preview
component to immediately reveal cached images by checking decode state on mount,
preventing opacity glitches on remount. Adjust gallery rail scrolling to reset
on document list changes for consistent navigation.
…tion

Introduce a "Remove All Folders" action accessible via a new sidebar menu,
allowing users to clear all folders at once. Add a confirmation dialog to
prevent accidental removal. Update the FinderSidebar to include a menu button
with the new action, and implement supporting state and handlers in the
document list. Add DotsHorizontalIcon for menu UI. Expand folder tests to
cover the new bulk removal flow.
… behavior

Eliminate unused loading state and related effects from document tile and list
row components. Standardize navigation by disabling prefetch on all document
open links in doclist views for consistent client-side routing. Cache
document list state on load to improve state restoration and initialization.
… and accessibility

Revise test helpers and specs to use stricter role-based selectors for document
actions, including delete buttons and document links. Improve accessibility and
upload tests by asserting document presence via explicit file lists instead of
generic text checks. Remove redundant summary assertion from delete flow.
…tility

Move grid style and template calculation for icon views into a shared
iconsGrid.ts utility. Replace inline grid logic in IconsView and DocumentListSkeleton
with calls to the new iconsGridStyle function for consistency and maintainability.
Shift app-level actions (settings and user menu) from the top bar to the bottom
of the sidebar for improved navigation consistency. Introduce a new "sidebar"
variant for the UserMenu component with tailored styling and behavior for
sidebar placement. Update SettingsModal to support a customizable trigger label
and styling for sidebar integration. Refactor FinderSidebar to accept an
optional bottomSlot, enabling flexible placement of sidebar controls.
Eliminate the deprecated "columns" view mode from the document list, toolbar,
icons, and skeleton components. Update all related types and logic to only
support "icons", "list", and "gallery" views. Standardize user-facing labels
from "HTML" to "Text" for improved clarity across the sidebar, segment
locator labels, and document counts. Clean up associated code and types to
reflect these changes.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
open-reader-web-ui Ready Ready Preview, Comment May 29, 2026 3:24pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2690cb34-9f7c-46f3-b9cc-969b329e2526

📥 Commits

Reviewing files that changed from the base of the PR and between c5b39f5 and c6047ff.

📒 Files selected for processing (3)
  • src/contexts/OnboardingFlowContext.tsx
  • tests/folders.spec.ts
  • tests/helpers.ts
💤 Files with no reviewable changes (2)
  • tests/helpers.ts
  • tests/folders.spec.ts

📝 Walkthrough

Walkthrough

This PR refactors the document list into a Finder-style layout with touch-aware react-dnd backend switching, a selection context for multi-select, three view modes (icons/list/gallery), sidebar folders with persistence, finder toolbar/sidebar/status components, preview cache dedupe, Dexie lookup for recently opened, UI/skeleton/uploader updates, and test locator adjustments.

Changes

Document List View System Refactoring

Layer / File(s) Summary
Type System & Persisted UI Model
src/types/documents.ts
Adds ViewMode, IconSize, SidebarFilter, recentlyOpenedAt on BaseDocument, and extends DocumentListState with view/icon/sidebar fields.
DnD backend & Selection
package.json, src/components/doclist/dnd/DocumentDndProvider.tsx, src/components/doclist/dnd/DocumentSelectionContext.tsx, src/components/doclist/dnd/dndTypes.ts, src/components/doclist/formatSize.ts
Adds react-dnd-touch-backend; DocumentDndProvider selects TouchBackend vs HTML5 and remounts subtree on change; DocumentSelectionProvider implements multi-select semantics; DnD types and size formatter added.
Core DocumentList Refactor
src/components/doclist/DocumentList.tsx
Refactors DocumentList into provider/composition model with cached init/persistence, document assembly enriched by getDocumentRecentlyOpenedMap(), sidebar/search filters, centralized sorting, and folder/merge/delete modal flows.
Views & Tiles
src/components/doclist/views/IconsView.tsx, src/components/doclist/views/ListView.tsx, src/components/doclist/views/GalleryView.tsx, src/components/doclist/views/DocumentTile.tsx, src/components/doclist/views/iconsGrid.ts
Adds Icons/List/Gallery views, DocumentTile with DnD and multi-select behavior, and responsive iconsGridStyle.
Finder Layout Components
src/components/doclist/window/FinderWindow.tsx, src/components/doclist/window/FinderToolbar.tsx, src/components/doclist/window/FinderSidebar.tsx, src/components/doclist/window/FinderStatusBar.tsx, src/components/doclist/window/finderIcons.tsx
Adds FinderWindow layout with desktop sidebar and mobile drawer, toolbar (view/sort/search), sidebar with drag-drop folder targets and resizing, status bar, and icon set.
Supporting Components & Integration
src/components/doclist/DocumentListSkeleton.tsx, src/components/doclist/DocumentPreview.tsx, src/components/documents/DocumentUploader.tsx, src/components/auth/UserMenu.tsx, src/components/SettingsModal.tsx, src/app/(app)/layout.tsx, src/app/(app)/app/page.tsx, src/components/HomeContent.tsx, src/lib/client/cache/previews.ts, src/lib/client/dexie.ts, src/components/icons/Icons.tsx, src/components/reader/SegmentsSidebar.tsx
Updates skeleton to three view modes, preview overlay size display, uploader overlay variant and children, user/settings trigger/variant props, layout height/overflow tweaks, HomeContent to render DocumentList, preview cache in-flight dedupe, Dexie helper for recently opened, adds horizontal dots icon and reader label tweak.
Tests & Helpers
tests/accessibility.spec.ts, tests/delete.spec.ts, tests/folders.spec.ts, tests/helpers.ts, tests/upload.spec.ts
Playwright updates for more specific locators, folder persistence tests, delete targeting, helper refinements, and re-validating document lists after viewer navigation.

Sequence Diagram (high-level flow)

sequenceDiagram
  participant Browser
  participant DocumentDndProvider
  participant DocumentSelectionProvider
  participant DocumentList
  participant DexieDB
  Browser->>DocumentDndProvider: detect touch or mouse
  DocumentDndProvider->>DocumentSelectionProvider: wrap children
  DocumentList->>DexieDB: getDocumentRecentlyOpenedMap()
  DocumentList->>DocumentSelectionProvider: setVisibleOrder / selection events
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 A finder window hops into view,
With folder rows and selection too!
Touch and drag, or list and peek—
Three new views, all shiny and sleek.
Persistence saved, the docs align,
This refactoring's truly divine! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: a comprehensive redesign of the document list UI with Finder-style views, sidebar workflows, and recents functionality.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch redesign/app-view-documents-list

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/contexts/OnboardingFlowContext.tsx

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/auth/UserMenu.tsx`:
- Around line 75-86: The disconnect button in UserMenu.tsx currently exposes
only the user email (session.user.email || 'Account') as its accessible name;
update the button (the element with onClick={handleDisconnectAccount}) to
provide an explicit action label for screen readers—either add
aria-label="Disconnect account" (or "Sign out") to the <button> or include a
visually-hidden span (e.g., className="sr-only") with the action text alongside
the email so assistive tech announces the sign-out action clearly while
preserving the visible email.

In `@src/components/doclist/dnd/dndTypes.ts`:
- Around line 5-11: The drag payload currently loses type info because
DocumentDragItem.ids: string[] only holds raw IDs; change the shape to preserve
type by replacing ids with e.g. items: { id: string; type: string }[] (or a
composite key string if you prefer) and update references to DocumentDragItem
(including usages in folder move/dedupe logic and any functions expecting ids)
to use the new items list or composite key so consumers can distinguish same-id
documents of different types; ensure DocumentDragItem.docs and any conversion
helpers are updated to derive or match the new item type.

In `@src/components/doclist/DocumentList.tsx`:
- Around line 384-401: The folder move/merge logic in handleDropOnFolder (the
setFolders mapping that uses item.ids, existingIds.has, and filtering by d.id)
compares only numeric ids and thus conflates cross-type items (e.g., "pdf/123"
vs "html/123"); change all identity comparisons (item.ids.includes(d.id),
existingIds.has(d.id), and any s.id !== target.id logic) to compare the same
composite key used by selection (e.g., `${type}/${id}` or the existing
selectionKey on DocumentDragItem and Document entries) so removal/deduping only
matches when both type and id match; apply the same fix to the other block
mentioned (lines 410-443) where documents are compared/filtered by id.
- Around line 272-305: The maps (allDocumentsById, foldersWithLiveDocs,
folderNameById, folderIdByDocId) are keyed only by doc.id causing collisions
across different document types; change them to use a stable composite key of
type+id (e.g. `${doc.type}|${doc.id}` or JSON.stringify({type,id})) when
building and looking up entries (update the map creation in allDocumentsById and
folderIdByDocId and the lookups in foldersWithLiveDocs and folderNameById to use
that composite key so document/folder hydration and badge lookups use {type,id}
identity).

In `@src/components/doclist/formatSize.ts`:
- Around line 1-8: The formatDocumentSize function renders sub-1KB sizes as
fractional KB; add a branch at the start of formatDocumentSize to handle bytes <
1024 and return an integer bytes string with "B" (e.g., "0 B", "512 B") instead
of using KB formatting; keep the existing GB and MB branches and the KB branch
for >=1024 to preserve current behavior.

In `@src/components/doclist/views/DocumentTile.tsx`:
- Around line 82-105: The drag payload’s item callback in DocumentTile’s useDrag
closes over selection.getSelectedDocs() and selection.replace(...) but the hook
deps are only [doc, isSelected], causing stale payloads when selection changes;
update the implementation so the item callback reads the current selection (or a
selection-version token) at drag-start by making the item function stable with
correct dependencies: include the selection reference or a selection
version/getter in the useDrag dependency array (or wrap the item callback in a
useCallback that depends on selection / selection.getSelectedDocs() /
selectionVersion) so selection.getSelectedDocs() and selection.replace() are
always up-to-date when dragging begins.

In `@src/components/doclist/views/GalleryView.tsx`:
- Around line 144-168: The keyboard handler in GalleryView.tsx can set activeIdx
to -1 when documents.length === 0; update the onKey handler (the useEffect that
defines onKey) to guard against an empty gallery by returning early if
documents.length === 0 (or otherwise skipping ArrowLeft/ArrowRight logic).
Specifically, inside the onKey callback referenced by window.addEventListener,
check documents.length === 0 before computing or calling setActiveIdx so
ArrowRight/ArrowLeft cannot produce negative or out-of-range indices for
activeIdx.

In `@src/components/doclist/window/finderIcons.tsx`:
- Around line 5-16: The baseSvg function currently sets width and height
defaults before spreading ...props, which allows callers to pass explicit
undefined to override the defaults; modify baseSvg (and use IconProps) to
destructure width and height with defaults from props (e.g., const { width =
'1em', height = '1em', ...rest } = props) and then return the SVG object using
width and height from those variables and spread ...rest so undefined values on
props do not clobber the defaults.

In `@src/components/doclist/window/FinderStatusBar.tsx`:
- Around line 1-14: The local formatSize function in FinderStatusBar.tsx causes
sub-1MB values to round to 0; remove this local formatSize and instead import
and use the shared size formatter used by the document list UI (replace calls to
formatSize in FinderStatusBar with the shared formatter), keeping
FinderStatusBarProps and all usage of itemCount/selectedCount/totalSize
unchanged so the status bar uses the canonical formatting logic.

In `@src/components/doclist/window/FinderWindow.tsx`:
- Around line 63-65: The Dialog in FinderWindow currently calls
onSidebarOpenChange(false) via its onClose prop which allows backdrop clicks and
Escape to dismiss the mobile drawer; remove the onClose handler (or replace it
with a no-op) from the Dialog component so it no longer closes via the generic
dismiss path, and ensure the existing explicit row action callbacks (the
sidebar/row action handlers that already call onSidebarOpenChange(false)) remain
the only places that close the drawer.

In `@src/components/documents/DocumentUploader.tsx`:
- Around line 100-122: The overlay branch (when variant === 'overlay') never
shows upload errors even though onDrop sets an error state; update the JSX
returned by the overlay branch (inside the element created from
getRootProps()/getInputProps()) to conditionally render the existing error state
(e.g., error) alongside the drop instructions when isDragActive is true or below
them when not active, and include a short retry hint or action (e.g., "Upload
failed: {error} — try again") so users see the failure and can retry; touch the
component rendering inside the overlay div that contains UploadIcon and the
accept text (reference: variant, getRootProps, getInputProps, isDragActive,
enableDocx, onDrop, error).

In `@src/lib/client/dexie.ts`:
- Around line 828-848: The current getDocumentRecentlyOpenedMap uses
db[PDF_TABLE].toArray(), db[EPUB_TABLE].toArray(), and db[HTML_TABLE].toArray(),
which loads full document payloads into memory; change the implementation to
only fetch id and cacheAccessedAt (avoid full ArrayBuffer/HTML payloads). For
each table (PDF_TABLE, EPUB_TABLE, HTML_TABLE) replace the toArray() calls with
a lean iteration or keyed fetch: obtain the primary keys (e.g.,
table.toCollection().keys() or table.primaryKeys()), then use
table.bulkGet(keys) or table.get(key, ['cacheAccessedAt']) to retrieve only
cacheAccessedAt for each id, and feed those id/timestamp pairs into the same
write(...) logic in getDocumentRecentlyOpenedMap so the recents map is built
without loading full cached documents.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b08b98b8-847a-40ce-9a62-38533d82ada8

📥 Commits

Reviewing files that changed from the base of the PR and between 218e248 and 5a68421.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (38)
  • package.json
  • src/app/(app)/app/page.tsx
  • src/app/(app)/layout.tsx
  • src/components/HomeContent.tsx
  • src/components/SettingsModal.tsx
  • src/components/auth/UserMenu.tsx
  • src/components/doclist/CreateFolderDialog.tsx
  • src/components/doclist/DocumentFolder.tsx
  • src/components/doclist/DocumentList.tsx
  • src/components/doclist/DocumentListItem.tsx
  • src/components/doclist/DocumentListSkeleton.tsx
  • src/components/doclist/DocumentPreview.tsx
  • src/components/doclist/SortControls.tsx
  • src/components/doclist/dnd/DocumentDndProvider.tsx
  • src/components/doclist/dnd/DocumentSelectionContext.tsx
  • src/components/doclist/dnd/dndTypes.ts
  • src/components/doclist/formatSize.ts
  • src/components/doclist/views/DocumentTile.tsx
  • src/components/doclist/views/GalleryView.tsx
  • src/components/doclist/views/IconsView.tsx
  • src/components/doclist/views/ListView.tsx
  • src/components/doclist/views/iconsGrid.ts
  • src/components/doclist/window/FinderSidebar.tsx
  • src/components/doclist/window/FinderStatusBar.tsx
  • src/components/doclist/window/FinderToolbar.tsx
  • src/components/doclist/window/FinderWindow.tsx
  • src/components/doclist/window/finderIcons.tsx
  • src/components/documents/DocumentUploader.tsx
  • src/components/icons/Icons.tsx
  • src/components/reader/SegmentsSidebar.tsx
  • src/lib/client/cache/previews.ts
  • src/lib/client/dexie.ts
  • src/types/documents.ts
  • tests/accessibility.spec.ts
  • tests/delete.spec.ts
  • tests/folders.spec.ts
  • tests/helpers.ts
  • tests/upload.spec.ts
💤 Files with no reviewable changes (4)
  • src/components/doclist/DocumentFolder.tsx
  • src/components/doclist/SortControls.tsx
  • tests/delete.spec.ts
  • src/components/doclist/DocumentListItem.tsx

Comment thread src/components/auth/UserMenu.tsx
Comment thread src/components/doclist/dnd/dndTypes.ts
Comment thread src/components/doclist/DocumentList.tsx
Comment thread src/components/doclist/DocumentList.tsx
Comment thread src/components/doclist/formatSize.ts
Comment thread src/components/doclist/window/finderIcons.tsx Outdated
Comment thread src/components/doclist/window/FinderStatusBar.tsx Outdated
Comment thread src/components/doclist/window/FinderWindow.tsx
Comment thread src/components/documents/DocumentUploader.tsx
Comment thread src/lib/client/dexie.ts
…drop robustness

Introduce a document identity key combining type and id for consistent
identification across document operations, including selection, drag-and-drop,
and folder management. Refactor drag item structures to use identity objects
instead of plain ids, preventing cross-type collisions and improving merge
accuracy. Update Dexie recently opened map to use identity keys. Enhance
document size formatting for small files and improve error feedback in the
uploader. Clean up redundant props and standardize icon SVG handling.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant