Skip to content

Implement split view browsing controls #31

Description

@Andresshamis

Meridian Explorer automation, posting through @Andresshamis.

Priority: P2
Type: feature / accessibility / testing / architecture
Ready status: ready

Problem statement

Meridian has split-view data models and persistence-boundary handling, but users cannot create, view, use, or close a split browsing layout. The command-bar action enum still includes splitActiveTab, yet the action is intentionally unavailable and the browser content area renders only one active WKWebView at a time.

Why it matters for Meridian

Split view browsing is part of Meridian's product scope and an important sidebar-first workflow: users should be able to compare pages without leaving the current space. Leaving only dormant split-view models creates misleading architecture coverage without an actual browser capability.

Evidence

  • Sources/MeridianCore/Models/SplitViewLayout.swift defines split-view layout metadata, and BrowserTab.splitViewID plus BrowserSessionSnapshot.splitViews persist the shape.
  • Sources/MeridianCore/Services/SessionPersistenceBoundary.swift filters invalid/private split views, so persistence already accounts for split metadata.
  • Sources/MeridianCore/Stores/BrowserStore.swift exposes splitViews but has no public API to create, select, update, or close a split layout; performBrowserAction(.splitActiveTab) returns false and the user message is Split view is not available yet.
  • Sources/MeridianCore/Views/BrowserWindowView.swift owns a single WebViewState, and Sources/MeridianCore/Views/Browser/BrowserContentView.swift renders a single active WebViewHost or StartPageView; splitViews is not used in the view layer.
  • Sources/MeridianCore/Services/CommandRouter.swift defines .splitActiveTab, but allActionSuggestions does not include a split-view suggestion and availability filtering hard-disables it.
  • Docs/FeatureChecklist.md lists split-view models as implemented and Split view UI as not yet implemented.
  • Issue Wire command bar browser actions #26 and merged PR Wire command bar browser actions #28 intentionally deferred split-view action activation; searches found no open dedicated split-view issue beyond that closed command-bar slice.

Affected files/components

  • Sources/MeridianCore/Models/SplitViewLayout.swift
  • Sources/MeridianCore/Models/BrowserTab.swift
  • Sources/MeridianCore/Stores/BrowserStore.swift
  • Sources/MeridianCore/Views/BrowserWindowView.swift
  • Sources/MeridianCore/Views/Browser/BrowserContentView.swift
  • Sources/MeridianCore/WebKit/WebViewState.swift
  • Sources/MeridianCore/WebKit/WebViewHost.swift
  • Sources/MeridianCore/Services/CommandRouter.swift
  • Sources/MeridianCore/Models/CommandBarResult.swift
  • Tests/MeridianBrowserTests/BrowserStoreTests.swift
  • Tests/MeridianBrowserTests/CommandRouterTests.swift
  • Tests/MeridianBrowserTests/SessionPersistenceBoundaryTests.swift
  • Docs/FeatureChecklist.md
  • Docs/TestPlan.md

Expected behavior

A user can split the active tab into a two-pane browsing layout within the current space, interact with either pane, keep each pane's WebKit navigation state separate, and return tabs to normal single-pane browsing without losing tab metadata or violating profile/private browsing boundaries.

Proposed direction

Implement a narrow first split-view slice for two horizontal panes. Add store-level APIs to create a split from the selected tab, add or select the companion tab, assign both tabs to a SplitViewLayout, select the active pane/tab, and close/unsplit safely. Update the content view to render two WebViewHost panes, each with its own WebViewState, while keeping WebKit integration behind the existing boundary. Wire a visible control and the command-bar splitActiveTab action only when an active tab can be split.

Acceptance criteria

  • A selected regular/pinned/favorite tab can enter a two-pane split layout with a companion tab in the same space and profile.
  • Split creation updates splitViews, both tabs' splitViewID, selected tab/pane state, and session persistence through the existing persistence boundary.
  • The browser content area renders both panes side by side with separate WebViewState instances and no cross-pane back/forward/reload leakage.
  • Users can focus/select either pane and run back, forward, reload/stop, close tab, and command-bar actions against the focused pane.
  • Users can close or unsplit a split layout; remaining tabs keep valid section/folder membership and no stale splitViewID remains.
  • Private/ephemeral profile split metadata remains excluded from durable persistence through SessionPersistenceBoundary.
  • Split commands/suggestions are unavailable when there is no active tab or when the active tab cannot be split, with only generic non-sensitive messaging.
  • Docs/checklist distinguish implemented first-slice split view behavior from future enhancements such as drag-resizing, vertical orientation, and more than two panes.

Dependencies/blockers

Suggested tests

  • BrowserStoreTests for creating a split from the selected tab, assigning a companion tab, preserving same-space/same-profile membership, selecting panes, closing one pane, and unsplitting.
  • Persistence tests proving public split layouts round-trip and private/ephemeral split metadata is filtered before disk writes.
  • CommandRouterTests for split-view aliases/results and unavailable-action behavior.
  • View-level tests or follow-up UI tests proving the focused pane receives command-bar and toolbar actions.
  • Regression tests for closing a split tab from Essentials/Pinned/regular/folder contexts without duplicate tab IDs or stale split IDs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions