# 2026-04-16 Import Window Responsive Design ## Goal Make the floating import window adapt to the current browser viewport automatically so the user does not need to manually resize it after changing browser zoom or window size. The floating window shell remains: - draggable - minimizable - maximizable - closable The import content remains the restored collection importer: - left pane: Zotero collection tree - right pane: collection items ## User-Approved Behavior ### Window sizing policy - Each time the import window opens, it recalculates its size and position from the current viewport. - Previously saved manual width, height, and position are not reused on reopen. - The window opens centered in the viewport. - The default size is viewport-relative, using a large but bounded footprint. Recommended sizing rule: - width: about `88vw` - height: about `82vh` - clamp width and height to safe min/max values so content remains usable on smaller screens ### Resize and zoom behavior - Browser zoom changes are treated the same as viewport changes. - On `resize`, if the window is in normal mode, its dimensions and position are adjusted to remain visible within the viewport. - If the window is maximized, existing maximize behavior remains authoritative. - If the window is minimized, existing minimize behavior remains authoritative. ### Layout adaptation - Wide viewport: keep the current two-pane horizontal layout. - Narrow viewport: switch the import window body to a vertical stack. - In stacked mode: - top pane: collections - bottom pane: collection items This avoids crushed side-by-side panes and avoids requiring horizontal scrolling. ## Implementation Design ### State model Keep the current floating-window state structure, but change how normal-mode geometry is derived: - persisted maximize/minimize flags can remain - persisted normal-mode width/height/left/top are no longer the source of truth on reopen - on open, recompute width, height, left, and top from the current viewport ### New geometry helpers Add small helpers in the template script: - `computeResponsiveWindowRect()` - derives width/height/left/top from `window.innerWidth` and `window.innerHeight` - clamps to minimum and maximum bounds - returns a centered rect - `applyResponsiveWindowRect()` - applies the computed rect to the floating window when in normal mode - `syncWindowToViewport()` - runs on resize - keeps the window inside the visible viewport - does nothing destructive when minimized or maximized ### Layout switching Use CSS plus a narrow-width breakpoint for `.window-body`: - default: `grid-template-columns: 22rem minmax(0, 1fr)` - narrow mode: `grid-template-columns: 1fr` The existing `.window-pane.collections` separator changes from right border to bottom border in stacked mode. ### Interaction rules - Opening the window always recomputes the normal-mode rect. - Manual dragging still works during the current open session. - If the viewport changes while the window is open, normal mode is re-constrained to the viewport. - Closing and reopening discards the session’s manual geometry and recomputes from the viewport again. ## Testing Add or update UI tests to verify: - the responsive helper logic is present in the inline script - opening the window uses viewport-based sizing instead of reopening from stale manual geometry - the template contains the narrow-layout CSS for stacked panes - the inline script remains valid JavaScript Manual verification target: - open import window at normal zoom - change browser zoom or viewport size - close and reopen - confirm the window opens centered and proportionate to the new viewport - confirm narrow viewport stacks collections above items ## Risks and Mitigations ### Risk: resize fights user drag Mitigation: - only recompute automatically on open - on live resize, constrain only enough to keep the window visible ### Risk: minimized/maximized modes get overwritten Mitigation: - gate responsive normal-mode logic behind checks for non-minimized and non-maximized state ### Risk: small screens become unusable Mitigation: - stack panes vertically below the chosen breakpoint - clamp dimensions and leave a small viewport margin