Skip to content

feat: split preview UX improvements and empty state redesign#9

Closed
mozulator wants to merge 1 commit intohalilc4:devfrom
mozulator:feature/split-preview-ux-and-empty-state
Closed

feat: split preview UX improvements and empty state redesign#9
mozulator wants to merge 1 commit intohalilc4:devfrom
mozulator:feature/split-preview-ux-and-empty-state

Conversation

@mozulator
Copy link
Collaborator

Summary

  • Drag-to-resize handles on the split preview — drag borders between panes to adjust ratios (snaps to 10% increments)
  • Ratio preservation when splitting or adding panes — no more equal-reset, the new pane gets half of the target pane's share
  • Selection preserved during resize — clicking a resize handle no longer accidentally selects/deselects panes
  • Preview fills available space — flex layout stretches the split preview to use the full settings page height instead of being capped at 200px
  • Optional pane name — new name field on the pane model and editor, displayed prominently in the preview
  • Redesigned pane display — centered hierarchy showing name > profile > path > command with full paths (no more truncation)
  • Percentage labels — each pane shows its effective width : height dimensions
  • Empty state redesign — new landing screen with icon, title, description, and a "Create Workspace" CTA button when no workspaces exist
  • Dropdown positioning fixes — icon and color picker dropdowns align properly
  • Solid background fallback for dropdown panels

Files changed

File Changes
src/models/workspace.model.ts Added optional name field to WorkspacePane
src/components/splitPreview.component.* Resize handles, drag logic, pane content redesign, percentage labels
src/components/workspaceEditor.component.* Ratio change/resize-end bindings, flex stretch layout, dropdown fixes
src/components/workspaceList.component.* Empty state redesign, full-height layout, tab bar conditional visibility
src/components/paneEditor.component.pug Name input field
src/styles/_mixins.scss Solid background fallback for dropdown-panel mixin
package-lock.json Version sync to 0.2.0

Test plan

  • Create a new workspace and verify the empty state CTA works
  • Add multiple panes and drag resize handles to adjust ratios
  • Verify ratios are preserved when splitting/adding panes
  • Verify pane selection is not affected by resizing
  • Test pane name field in the pane editor
  • Verify percentage labels show correct dimensions
  • Check dropdown positioning for icon and color pickers
  • Test with nested splits (horizontal inside vertical and vice versa)

🤖 Generated with Claude Code

Split preview:
- Add drag-to-resize handles between panes (snaps to 10% increments)
- Preserve ratios when splitting/adding panes (no more equal-reset)
- Preserve selection during resize (wasResizing guard pattern)
- Preview stretches to fill available space (flex layout, no max-height)
- Add optional pane name field (model + pane editor)
- Redesign pane display: centered hierarchy (name > profile > path > command)
- Show full paths with word-break instead of truncation
- Show percentage dimension labels on panes (width : height)

Empty state:
- Redesign landing screen with icon, title, description, and CTA button
- Hide tab bar when no workspaces exist
- Full-height layout fills entire settings page

Other:
- Fix dropdown positioning (icon picker, color picker)
- Add solid background fallback for dropdown panels
- Sync package-lock.json version to 0.2.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Owner

@halilc4 halilc4 left a comment

Choose a reason for hiding this comment

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

Solid PR overall — the drag-to-resize and ratio preservation are well-thought-out. Left 6 inline comments for discussion. Looking forward to the debate!

Review by Igor's Claude 🤖

"name": "tabby-tabbyspaces",
"version": "0.1.0",
"version": "0.2.0",
"lockfileVersion": 3,
Copy link
Owner

Choose a reason for hiding this comment

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

#1 — Version mismatch

This sets version to 0.2.0, but main is already at 0.2.1 (bumped in commit fbeae96). This will cause a merge conflict.

Not a blocker — just needs a rebase or version bump before merge.

Copy link
Owner

Choose a reason for hiding this comment

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

Fixed via rebase on dev. Version now matches 0.2.4.

const settingsTabBody = this.elementRef.nativeElement.closest('settings-tab-body') as HTMLElement
if (settingsTabBody) {
settingsTabBody.style.maxWidth = SETTINGS_MAX_WIDTH
settingsTabBody.style.height = '100%'
Copy link
Owner

Choose a reason for hiding this comment

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

#2 — Aggressive DOM hacking

The original hack was a single maxWidth override. This now applies 6 inline styles to 3 different parent elements (settingsTabBody, tabPane, host). Concerns:

  1. These parent elements belong to Tabby's core layout — overriding height: 100% and boxSizing on .tab-pane could affect other settings tabs when switching.
  2. Inline styles are hard to debug and override.
  3. If Tabby updates their settings layout structure, this breaks silently.

I understand why — you need the preview to fill available space. But could this be achieved with less invasive CSS? For example, position: absolute + inset: 0 on our container, or using calc(100vh - header) instead of forcing flex all the way up the tree?

Would love to hear your reasoning on why this approach was necessary.

Copy link
Owner

Choose a reason for hiding this comment

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

Cleaned up. Removed tabPane hack (height/box-sizing) and host.style.* JS overrides — host styles are now in SCSS :host block. Only settingsTabBody.maxWidth + height remain.

Added ngOnDestroy cleanup that saves original style values and restores them when navigating away, so other settings tabs are unaffected. Verified in Tabby — Shell tab renders normally after switching away from TabbySpaces.

// ======================

@mixin dropdown-panel {
background-color: #1e1e1e;
Copy link
Owner

Choose a reason for hiding this comment

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

#3 — Hardcoded fallback color

#1e1e1e is a hardcoded dark color that won't work on light themes. The pattern in this codebase uses $fallback-* SCSS variables for theme fallbacks (see _variables.scss).

Also, background (shorthand) on the next line completely overrides background-color, so this fallback only kicks in if var(--theme-bg-more) is invalid (not just missing — CSS custom property fallback syntax handles missing values). In practice, this line may never actually apply.

Suggestion: Use the existing $fallback-bg-more variable if one exists, or use the CSS var fallback syntax:

background: var(--theme-bg-more, #1e1e1e);

Copy link
Owner

Choose a reason for hiding this comment

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

Extracted $fallback-bg-more: #1e1e1e to _variables.scss alongside the other fallback values. The mixin now uses var(--theme-bg-more, $fallback-bg-more) — standard CSS fallback pattern, so light themes will use their own --theme-bg-more value.

}

const combined = this.split.ratios[k] + this.split.ratios[k + 1]
const mouseRatio = (mousePos - containerStart) / containerSize
Copy link
Owner

Choose a reason for hiding this comment

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

#4 — Resize handle width not accounted for in ratio calculation

containerSize includes the resize handles (6px each via flex: 0 0 6px). So mouseRatio is calculated against the full container width, but ratios only distribute the remaining space after handles.

With 2 panes (1 handle = 6px), the error is negligible. But with 5 panes (4 handles = 24px) in a 400px container, that's a 6% error. The snap-to-10% partially masks this, but the snap boundaries themselves are shifted.

A more precise approach would subtract handle widths:

const handleCount = this.split.children.length - 1
const handleSize = 6 // matches CSS flex-basis
const effectiveSize = containerSize - (handleCount * handleSize)

Not a blocker for typical 2-3 pane layouts, but worth considering for correctness.

Copy link
Owner

Choose a reason for hiding this comment

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

Fixed. Now subtracts handle pixel widths from container size for ratio calculation:

  • effectiveSize = containerSize - handleCount * 6
  • adjustedPos = mousePos - containerStart - (k + 0.5) * HANDLE_SIZE

The (k + 0.5) accounts for k handles before the dragged one plus half the current handle (centering). Tested with 5 panes (4 handles) — ratios snap correctly.

Note: HANDLE_SIZE = 6 is a magic number matching CSS flex: 0 0 6px. Documented with a comment for now.

.pane-path(*ngIf='asPane(child).cwd') {{ asPane(child).cwd }}
.pane-command(*ngIf='asPane(child).startupCommand')
i.fas.fa-terminal
| {{ asPane(child).startupCommand }}
Copy link
Owner

Choose a reason for hiding this comment

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

#5 — Percentage labels could be confusing

The width : height format shows global percentages like 50% : 100% or 25% : 50%. Two concerns:

  1. There's no indication which number is width vs height — users might misread it, especially for vertical splits where the "width" stays 100%.
  2. For deeply nested splits, values like 12% : 33% are technically correct but not intuitive.

Consider adding labels (W: 50% H: 100%) or only showing the dimension that the current split orientation controls (since the other is always inherited from the parent).

Copy link
Owner

Choose a reason for hiding this comment

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

Changed format from 50% : 100% to W:50% H:100% with dedicated .dim-label styling (smaller font, lower opacity) so labels are subtle but clear. Verified on nested splits — shows W:13% H:100% correctly for a pane inside a 25%/50% hierarchy.

}

editPane(pane: WorkspacePane): void {
if (this.wasResizing) return
Copy link
Owner

Choose a reason for hiding this comment

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

#6 — Behavior change: pane click now toggles selection

Previously, clicking a selected pane kept it selected (no-op). Now it deselects and closes the pane editor. This is a UX behavior change not mentioned in the PR description.

I actually think toggle is better UX — but it should be documented in the PR summary since it changes existing behavior. Users who are used to the old behavior might be surprised.

Also, this means there's now no way to re-open the pane editor for an already-selected pane without clicking away first and then clicking back. Was that intentional?

Copy link
Owner

Choose a reason for hiding this comment

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

Implemented smart toggle. Click behavior is now:

  1. Click unselected pane → select + open editor
  2. Click selected pane (editor open) → close editor, selection stays (blue border)
  3. Click selected pane (editor closed) → reopen editor
  4. Click background → deselect + close editor

This keeps the visual selection feedback while allowing the editor to be toggled. Tested all 4 flows via CDP.

@halilc4
Copy link
Owner

halilc4 commented Feb 14, 2026

@mozulator Review comments are up — 6 inline notes on specific lines. Would love to hear your thoughts! 🤖⚔️

halilc4 added a commit that referenced this pull request Feb 16, 2026
- #1: Rebased on dev to resolve version mismatch (0.2.0 → 0.2.4)
- #2: Reduced DOM hacking — removed redundant host/tabPane styles, added ngOnDestroy cleanup
- #3: Replaced hardcoded #1e1e1e with $fallback-bg-more variable and CSS var fallback
- #4: Compensated for resize handle width in ratio calculation
- #5: Added W:/H: labels to pane dimension display
- #6: Smart toggle — click keeps selection, toggles editor visibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@halilc4
Copy link
Owner

halilc4 commented Feb 16, 2026

All 6 review comments have been addressed in commit 1fba946 and merged into dev. Each inline comment has a reply with details.

Summary of fixes:

All fixes verified in Tabby via CDP testing. Closing this PR as the changes have been merged into dev directly (can't push to fork branch).

@halilc4 halilc4 closed this Feb 16, 2026
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.

2 participants