diff --git a/docs/superpowers/specs/2026-04-15-zotero-collection-import-design.md b/docs/superpowers/specs/2026-04-15-zotero-collection-import-design.md index 6da4ee2..e59a97a 100644 --- a/docs/superpowers/specs/2026-04-15-zotero-collection-import-design.md +++ b/docs/superpowers/specs/2026-04-15-zotero-collection-import-design.md @@ -2,30 +2,29 @@ ## Overview -This design replaces the current crowded import area with a lighter flow: +This design revises the current import flow into a true full-screen modal experience: -- the main page keeps project, cards, and writing views visible -- the import UI moves into a modal opened from a single `导入文献` button +- the main page keeps project, cards, and writing views visible until import starts +- clicking `导入文献` opens a full-screen modal layer that visually occupies the whole viewport -The modal visualizes the user's current Zotero collection hierarchy, lets the user browse collections, displays the literature under the selected collection and all descendants, remembers cross-collection checkbox state for the current browser session, and batch-imports selected items into the current project. +The import modal visualizes the current Zotero collection hierarchy, lets the user browse collections, displays only the directly contained literature for the selected collection, remembers cross-collection checkbox state for the current browser session, and batch-imports the selected items into the current project. This work is intentionally scoped to the import surface only. The project card panel and writing panel remain in place. ## Goals -- Replace the current import widgets with one `导入文献` button that opens an import modal -- Visualize Zotero collections as a tree inside the modal -- When a collection is selected, show the literature under that collection and all descendant collections +- Replace the current import widgets with one `导入文献` button that opens a full-screen modal +- Visualize Zotero collections as a tree on the left side of the full-screen modal +- When a collection is selected, show only the items directly contained by that collection - Support checkbox-based multi-selection across collection switches - Remember previous selection state while the page remains open, even if the modal is closed and reopened -- Support bulk actions: - - select all items from the current collection plus descendants +- Support top-bar actions: - clear all selected items - import selected items into the current project - Keep the item list compact by default: - - show checkbox and title only - - show abstract only after hover delay -- Preserve the existing project panel, card panel, and writing panel structure + - show checkbox, title, and year only + - show abstract only after hover delay or explicit details trigger +- Preserve the existing project panel, card panel, and writing panel structure outside the modal ## Non-Goals @@ -35,6 +34,7 @@ This work is intentionally scoped to the import surface only. The project card p - Persisting import selections across browser restarts or across different users - Replacing the bridge-based current-selection import flow at the API level - Showing abstract text inline for every row by default +- Collection-level bulk selection such as “select all current collection and descendants” The bridge-based import endpoint may remain available, but it is no longer the main UI path. @@ -61,17 +61,17 @@ The current pair of sections: will be removed and replaced with: - one `导入文献` button on the main page -- one `Import From Zotero` modal +- one full-screen `Import From Zotero` modal ## User Flow 1. The user selects a project or leaves the page without selecting one yet 2. The user clicks `导入文献` -3. The modal opens -4. The user browses the Zotero collection tree +3. A full-screen modal opens +4. The user browses the Zotero collection tree on the left 5. The user clicks one collection -6. The UI loads all literature from that collection and all descendants -7. The user checks items to import +6. The UI loads only the items directly contained by that collection +7. The user checks individual items to import 8. The user may switch to a different collection and continue selecting 9. Previously selected items remain selected 10. The user clicks `导入所选到当前项目` @@ -81,7 +81,7 @@ will be removed and replaced with: ## Layout -The page stays three-column. +The page stays three-column until the import modal opens. ### Main Page @@ -91,29 +91,32 @@ The left panel contains: 2. `项目列表` 3. `导入文献` -The collection tree and collection item list are no longer rendered inline on the main page. +The collection tree and collection item list are not rendered inline on the main page. -### Import Modal +### Full-Screen Modal -The modal has three internal regions: +The modal fills the viewport and has three internal regions: -1. modal header +1. top toolbar 2. modal body -3. sticky action bar +3. full-screen overlay/background layer -#### Modal Header +#### Top Toolbar -- title -- current project name or an explicit "未选择项目" state +- `返回主页面` +- current project name or explicit `未选择项目` - selected count -- close button +- `清空选择` +- `导入所选` + +This toolbar remains visible while the collection tree and item list scroll. #### Modal Body -- desktop: two-column layout +- desktop: fixed two-column layout - left: collection tree - right: collection item list -- narrow screens: automatically stack into top and bottom sections +- narrow screens: may stack or collapse the tree, but the desktop target is explicitly left-tree / right-list #### Collection Tree @@ -121,36 +124,28 @@ The modal has three internal regions: - current collection highlighted - each node shows: - collection name - - descendant-aware item count + - item count for that collection #### Collection Item List -- shows items from the current collection and all descendant collections +- shows only items directly contained in the selected collection - each row contains: - checkbox - title -- year, item type, and abstract are not shown inline by default + - year +- abstract is not shown inline - rows already selected in other collections remain checked when shown again -#### Sticky Action Bar - -- selected count -- `全选当前目录及子目录` -- `清空选择` -- `导入所选到当前项目` - -The action bar remains visible while scrolling within the modal. - ## Interaction Semantics ### Modal Open And Close -Clicking `导入文献` opens the modal. +Clicking `导入文献` opens the full-screen modal. The modal can be closed by: -- clicking the close button -- clicking the overlay +- clicking the explicit return button +- clicking the overlay if that behavior is preserved - pressing `Esc` Closing the modal does not clear: @@ -166,7 +161,7 @@ Reopening the modal restores the previous browsing and selection state for the c Clicking a collection: - sets it as the active collection -- loads all items under that collection plus descendants +- loads only items directly contained by that collection - does not clear already selected items ### Checkbox State @@ -179,14 +174,6 @@ This means: - re-entering a collection restores prior checkbox state - the selected count reflects the union of all selected items across the session -### Select-All Behavior - -`全选当前目录及子目录` means: - -- take the currently displayed item set -- merge all of those item keys into the global selected set -- keep existing selections from other collections intact - ### Clear Behavior `清空选择` means: @@ -213,7 +200,7 @@ The item list stays compact by default. ### Desktop -- hovering an item row starts a 3 second timer +- hovering the title area of an item row starts a 3 second timer - if the pointer is still on the row after 3 seconds, an abstract preview popover appears - if the abstract is empty, no popover appears - moving the pointer away before 3 seconds cancels the timer @@ -248,6 +235,7 @@ The page should maintain these state keys: - `expandedCollectionKeys` - `selectedItemKeys` - `visibleCollectionItems` +- `selectedItemMeta` - `hoveredItemKey` - `hoverTimerId` - `previewItemKey` @@ -259,6 +247,7 @@ The page should maintain these state keys: - `expandedCollectionKeys` changes when nodes are opened or closed - `selectedItemKeys` persists across collection switches and modal reopen during the current browser session - `visibleCollectionItems` updates whenever the active collection changes +- `selectedItemMeta` stores minimal metadata for already selected items - `hoveredItemKey`, `hoverTimerId`, and `previewItemKey` control delayed abstract preview `selectedItemKeys` is the source of truth for checkbox rendering and batch import. @@ -284,9 +273,9 @@ Each node must include: ### 2. Collection Items -`GET /api/zotero/collections/{collection_key}/items?include_descendants=true` +`GET /api/zotero/collections/{collection_key}/items?include_descendants=false` -Returns all regular Zotero items under the selected collection. In V1 of this feature, the UI will always request `include_descendants=true`. +Returns only regular Zotero items directly contained by the selected collection. Each returned item must include: @@ -325,7 +314,6 @@ Required reader capabilities: - build normalized collection tree data - compute direct item counts per collection -- compute descendant-aware item counts per collection - list all regular items under a collection with optional descendant inclusion The reader should continue to ignore attachment, note, and annotation rows as import roots. @@ -363,13 +351,13 @@ The reader should continue to ignore attachment, note, and annotation rows as im ### Reader Tests - build collection tree from fixture Zotero data -- compute descendant-aware item counts -- list collection items with descendant inclusion +- compute direct item counts +- list collection items without descendant inclusion ### API Tests - `GET /api/zotero/collections/tree` -- `GET /api/zotero/collections/{collection_key}/items?include_descendants=true` +- `GET /api/zotero/collections/{collection_key}/items?include_descendants=false` - `POST /api/projects/{project_id}/imports/item-keys` ### UI Tests @@ -383,36 +371,41 @@ The modal must include: - collection tree container - collection item list container - selected count area -- select-all button - clear-selection button - import-selected button UI behavior must cover: -- modal can open without a selected project +- full-screen modal opens from the trigger button - import action is disabled when no project is selected - closing and reopening the modal preserves selected items during the session - import success closes the modal and refreshes cards - abstract preview appears only after the hover delay on desktop +- item rows display title and year by default, not abstract text ## Constraints And Tradeoffs -### Why Modal Instead Of Left-Panel Inline Import +### Why Full-Screen Modal Instead Of A Centered Dialog -The inline importer works functionally but makes the main page too crowded. A modal keeps import as a focused subtask and preserves the readability of the project, cards, and writing columns. +The user explicitly wants the import experience to feel like a whole-page task, not a cramped dialog anchored inside the left side of the UI. A full-screen modal preserves modal semantics while matching that expectation visually. -### Why Tree + Side List Instead Of Tree-Mixed Items +### Why Collection Tree + Direct Item List The user explicitly chose: -- collection tree on one side -- item list shown after selecting a collection +- collection tree on the left +- item list on the right +- only direct items for the selected collection -This keeps scanning manageable for large libraries and avoids turning the tree itself into an overloaded mixed node structure. +This keeps the browsing model simple: collection chooses the scope, list chooses the individual papers. -### Why Title-Only Rows By Default +### Why No Collection-Level Bulk Select -The user explicitly wanted a lighter list. Showing only the title in the default list keeps density under control, while delayed preview preserves access to abstracts when needed. +The user explicitly wants to choose papers one by one, not by collection-level bulk action. The collection tree filters the list; it does not act as a selection shortcut. + +### Why Title + Year By Default + +The user explicitly wanted a lighter list than the current dense layout. Showing title and year by default preserves scanning context while leaving abstracts to delayed preview. ### Why Session-Scoped Selection Memory @@ -428,11 +421,11 @@ This feature is complete when: - the old `导入当前选中` and `后备导入` UI sections are gone - the main page shows a `导入文献` button instead of an inline importer -- clicking the button opens a modal with collection tree and descendant-aware item list +- clicking the button opens a full-screen modal with collection tree and direct-item list - selecting items survives collection switches and modal reopen during the session -- the user can select all items from a collection plus descendants - the user can clear all current selections - the user can batch-import the selected items into the active project - the import button is disabled when no project is selected - the project card area refreshes after a successful import - abstract preview appears only through the delayed preview interaction, not inline by default +- the item list shows title and year by default, not descendant-wide result sets or collection-level bulk select actions