fix: SFTP default to Local pane + fixed border height
- Default active pane changed from Remote to Local on SFTP init - renderPane now takes maxH parameter for fixed border height - paneStyle.Height(maxH) prevents border from shrinking/growing on scroll - Stacked mode: maxH = t.height - 6; Side-by-side: t.height - 5
This commit is contained in:
@@ -33,6 +33,10 @@
|
|||||||
- Added pane indicator bar: `[Local] Remote` with active pane highlighted
|
- Added pane indicator bar: `[Local] Remote` with active pane highlighted
|
||||||
- Side-by-side mode (≥50 cols) unchanged — both panes remain visible
|
- Side-by-side mode (≥50 cols) unchanged — both panes remain visible
|
||||||
- Tab key now visually switches between panes on narrow terminals
|
- Tab key now visually switches between panes on narrow terminals
|
||||||
|
- Default active pane: Local (was Remote)
|
||||||
|
- Border height fix: pane uses fixed `Height(maxH)` — border no longer shrinks/grows when scrolling
|
||||||
|
- `renderPane` now takes `maxH` parameter to control content area height
|
||||||
|
- Stacked: `maxH = t.height - 6`; Side-by-side: `maxH = t.height - 5`
|
||||||
- Breakpoints: compact (<60), medium (60–100), wide (≥100)
|
- Breakpoints: compact (<60), medium (60–100), wide (≥100)
|
||||||
|
|
||||||
## v1.0.0 (2025-01-30)
|
## v1.0.0 (2025-01-30)
|
||||||
|
|||||||
+4
-1
@@ -68,7 +68,10 @@
|
|||||||
✅ Stacked mode (<50 cols): render cuma ACTIVE pane (bukan 2 pane)
|
✅ Stacked mode (<50 cols): render cuma ACTIVE pane (bukan 2 pane)
|
||||||
✅ Pane indicator bar: `[Local] Remote` — active disorot hijau (StatusBarStyle)
|
✅ Pane indicator bar: `[Local] Remote` — active disorot hijau (StatusBarStyle)
|
||||||
✅ Side-by-side mode (>=50 cols): tidak diubah, tetap 2 pane
|
✅ Side-by-side mode (>=50 cols): tidak diubah, tetap 2 pane
|
||||||
✅ `maxDisplay` tidak diubah (cuma 1 pane, full height)
|
✅ Default active pane: Local (bukan Remote)
|
||||||
|
✅ Border height fix: `renderPane` sekarang terima `maxH` parameter, `paneStyle.Height(maxH)` → border selalu konsisten tingginya, tidak naik-turun sesuai scroll
|
||||||
|
✅ Stacked mode: `maxH = t.height - 6` (title + indicator + border + footer)
|
||||||
|
✅ Side-by-side mode: `maxH = t.height - 5` (title + border + footer)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+21
-10
@@ -79,7 +79,7 @@ func NewSFTPBrowserTab(host *models.Host, dataDir string) *SFTPBrowserTab {
|
|||||||
return &SFTPBrowserTab{
|
return &SFTPBrowserTab{
|
||||||
host: host,
|
host: host,
|
||||||
dataDir: dataDir,
|
dataDir: dataDir,
|
||||||
active: paneRemote,
|
active: paneLocal,
|
||||||
left: sftpPane{
|
left: sftpPane{
|
||||||
cwd: home,
|
cwd: home,
|
||||||
localRoot: home,
|
localRoot: home,
|
||||||
@@ -565,10 +565,16 @@ func (t *SFTPBrowserTab) View() string {
|
|||||||
}
|
}
|
||||||
indicator = lipgloss.JoinHorizontal(lipgloss.Top, indicatorParts[0], SubtitleStyle.Render(" "), indicatorParts[1])
|
indicator = lipgloss.JoinHorizontal(lipgloss.Top, indicatorParts[0], SubtitleStyle.Render(" "), indicatorParts[1])
|
||||||
|
|
||||||
|
// Height: t.height - 1(title) - 1(indicator) - 2(border) - 2(footer) = t.height - 6
|
||||||
|
paneH := t.height - 6
|
||||||
|
if paneH < 5 {
|
||||||
|
paneH = 5
|
||||||
|
}
|
||||||
|
|
||||||
if t.active == paneLocal {
|
if t.active == paneLocal {
|
||||||
leftView = t.renderPane(&t.left, paneLocal, paneW)
|
leftView = t.renderPane(&t.left, paneLocal, paneW, paneH)
|
||||||
} else {
|
} else {
|
||||||
leftView = t.renderPane(&t.right, paneRemote, paneW)
|
leftView = t.renderPane(&t.right, paneRemote, paneW, paneH)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Side by side — reserve 2 chars border per pane
|
// Side by side — reserve 2 chars border per pane
|
||||||
@@ -576,8 +582,13 @@ func (t *SFTPBrowserTab) View() string {
|
|||||||
if halfW < 20 {
|
if halfW < 20 {
|
||||||
halfW = 20
|
halfW = 20
|
||||||
}
|
}
|
||||||
leftView = t.renderPane(&t.left, paneLocal, halfW)
|
// Height: t.height - 1(title) - 2(border) - 2(footer) = t.height - 5
|
||||||
rightView = t.renderPane(&t.right, paneRemote, halfW)
|
paneH := t.height - 5
|
||||||
|
if paneH < 5 {
|
||||||
|
paneH = 5
|
||||||
|
}
|
||||||
|
leftView = t.renderPane(&t.left, paneLocal, halfW, paneH)
|
||||||
|
rightView = t.renderPane(&t.right, paneRemote, halfW, paneH)
|
||||||
}
|
}
|
||||||
|
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
@@ -614,7 +625,7 @@ func (t *SFTPBrowserTab) View() string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *SFTPBrowserTab) renderPane(p *sftpPane, pt paneType, maxW int) string {
|
func (t *SFTPBrowserTab) renderPane(p *sftpPane, pt paneType, maxW, maxH int) string {
|
||||||
isActive := t.active == pt
|
isActive := t.active == pt
|
||||||
|
|
||||||
title := "Local"
|
title := "Local"
|
||||||
@@ -668,9 +679,9 @@ func (t *SFTPBrowserTab) renderPane(p *sftpPane, pt paneType, maxW int) string {
|
|||||||
if len(visible) == 0 {
|
if len(visible) == 0 {
|
||||||
content.WriteString(SubtitleStyle.Render(" (empty)"))
|
content.WriteString(SubtitleStyle.Render(" (empty)"))
|
||||||
} else {
|
} else {
|
||||||
maxDisplay := t.height - 6
|
maxDisplay := maxH - 4
|
||||||
if maxDisplay < 5 {
|
if maxDisplay < 1 {
|
||||||
maxDisplay = 5
|
maxDisplay = 1
|
||||||
}
|
}
|
||||||
start := 0
|
start := 0
|
||||||
if p.selIdx >= maxDisplay {
|
if p.selIdx >= maxDisplay {
|
||||||
@@ -724,7 +735,7 @@ func (t *SFTPBrowserTab) renderPane(p *sftpPane, pt paneType, maxW int) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inner := titleBar + "\n" + content.String()
|
inner := titleBar + "\n" + content.String()
|
||||||
return paneStyle.Width(maxW).Render(inner)
|
return paneStyle.Width(maxW).Height(maxH).Render(inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *SFTPBrowserTab) Close() {
|
func (t *SFTPBrowserTab) Close() {
|
||||||
|
|||||||
Reference in New Issue
Block a user