Skip to content

Commit c5ef34e

Browse files
authored
Merge pull request #253 from datlechin/fix/right-sidebar-animation-jitter
fix: replace .inspector() with custom panel to fix jittery animation
2 parents a2ae441 + 156acb1 commit c5ef34e

3 files changed

Lines changed: 86 additions & 24 deletions

File tree

TablePro/ContentView.swift

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -257,33 +257,40 @@ struct ContentView: View {
257257
.navigationSplitViewColumnWidth(min: 200, ideal: 250, max: 600)
258258
} detail: {
259259
// MARK: - Detail (Main workspace with optional right sidebar)
260-
MainContentView(
261-
connection: currentSession.connection,
262-
payload: payload,
263-
windowTitle: $windowTitle,
264-
tables: sessionTablesBinding,
265-
sidebarState: SharedSidebarState.forConnection(currentSession.connection.id),
266-
pendingTruncates: sessionPendingTruncatesBinding,
267-
pendingDeletes: sessionPendingDeletesBinding,
268-
tableOperationOptions: sessionTableOperationOptionsBinding,
269-
inspectorContext: $inspectorContext,
270-
rightPanelState: rightPanelState,
271-
tabManager: sessionState.tabManager,
272-
changeManager: sessionState.changeManager,
273-
filterStateManager: sessionState.filterStateManager,
274-
toolbarState: sessionState.toolbarState,
275-
coordinator: sessionState.coordinator
276-
)
277-
.inspector(isPresented: Bindable(rightPanelState).isPresented) {
278-
UnifiedRightPanelView(
279-
state: rightPanelState,
280-
inspectorContext: inspectorContext,
260+
HStack(spacing: 0) {
261+
MainContentView(
281262
connection: currentSession.connection,
282-
tables: currentSession.tables
263+
payload: payload,
264+
windowTitle: $windowTitle,
265+
tables: sessionTablesBinding,
266+
sidebarState: SharedSidebarState.forConnection(currentSession.connection.id),
267+
pendingTruncates: sessionPendingTruncatesBinding,
268+
pendingDeletes: sessionPendingDeletesBinding,
269+
tableOperationOptions: sessionTableOperationOptionsBinding,
270+
inspectorContext: $inspectorContext,
271+
rightPanelState: rightPanelState,
272+
tabManager: sessionState.tabManager,
273+
changeManager: sessionState.changeManager,
274+
filterStateManager: sessionState.filterStateManager,
275+
toolbarState: sessionState.toolbarState,
276+
coordinator: sessionState.coordinator
283277
)
284-
.frame(minWidth: 280, maxWidth: 500)
285-
.inspectorColumnWidth(min: 280, ideal: 320, max: 500)
278+
.frame(maxWidth: .infinity)
279+
280+
if rightPanelState.isPresented {
281+
PanelResizeHandle(panelWidth: Bindable(rightPanelState).panelWidth)
282+
Divider()
283+
UnifiedRightPanelView(
284+
state: rightPanelState,
285+
inspectorContext: inspectorContext,
286+
connection: currentSession.connection,
287+
tables: currentSession.tables
288+
)
289+
.frame(width: rightPanelState.panelWidth)
290+
.transition(.move(edge: .trailing))
291+
}
286292
}
293+
.animation(.easeInOut(duration: 0.2), value: rightPanelState.isPresented)
287294
}
288295
.navigationTitle(windowTitle)
289296
.navigationSubtitle(currentSession.connection.name)

TablePro/Models/UI/RightPanelState.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@ import os
1212

1313
@MainActor @Observable final class RightPanelState {
1414
private static let isPresentedKey = "com.TablePro.rightPanel.isPresented"
15+
private static let panelWidthKey = "com.TablePro.rightPanel.width"
1516
private static let isPresentedChangedNotification = Notification.Name("com.TablePro.rightPanel.isPresentedChanged")
1617
private var isSyncing = false
18+
19+
static let minWidth: CGFloat = 280
20+
static let maxWidth: CGFloat = 500
21+
static let defaultWidth: CGFloat = 320
1722
@ObservationIgnored private let _didTeardown = OSAllocatedUnfairLock(initialState: false)
1823

1924
var isPresented: Bool {
@@ -26,6 +31,14 @@ import os
2631
}
2732
}
2833

34+
var panelWidth: CGFloat {
35+
didSet {
36+
let clamped = min(max(panelWidth, Self.minWidth), Self.maxWidth)
37+
if panelWidth != clamped { panelWidth = clamped }
38+
UserDefaults.standard.set(Double(clamped), forKey: Self.panelWidthKey)
39+
}
40+
}
41+
2942
var activeTab: RightPanelTab = .details
3043

3144
// Save closure — set by MainContentCommandActions, called by UnifiedRightPanelView
@@ -43,6 +56,8 @@ import os
4356

4457
init() {
4558
self.isPresented = UserDefaults.standard.bool(forKey: Self.isPresentedKey)
59+
let savedWidth = UserDefaults.standard.double(forKey: Self.panelWidthKey)
60+
self.panelWidth = savedWidth > 0 ? min(max(savedWidth, Self.minWidth), Self.maxWidth) : Self.defaultWidth
4661
NotificationCenter.default.addObserver(
4762
self,
4863
selector: #selector(handleIsPresentedChanged(_:)),
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//
2+
// PanelResizeHandle.swift
3+
// TablePro
4+
//
5+
// Draggable resize handle for the right panel.
6+
//
7+
8+
import SwiftUI
9+
10+
struct PanelResizeHandle: View {
11+
@Binding var panelWidth: CGFloat
12+
13+
@State private var isDragging = false
14+
15+
var body: some View {
16+
Rectangle()
17+
.fill(Color.clear)
18+
.frame(width: 5)
19+
.contentShape(Rectangle())
20+
.onHover { hovering in
21+
if hovering {
22+
NSCursor.resizeLeftRight.push()
23+
} else {
24+
NSCursor.pop()
25+
}
26+
}
27+
.gesture(
28+
DragGesture(minimumDistance: 1)
29+
.onChanged { value in
30+
isDragging = true
31+
// Dragging left increases panel width (handle is on the leading edge)
32+
let newWidth = panelWidth - value.translation.width
33+
panelWidth = min(max(newWidth, RightPanelState.minWidth), RightPanelState.maxWidth)
34+
}
35+
.onEnded { _ in
36+
isDragging = false
37+
}
38+
)
39+
}
40+
}

0 commit comments

Comments
 (0)