feat(ui): remove splash screen and confirm ssh modal (#23)

This commit is contained in:
Adem Baccara
2025-09-05 00:01:45 +01:00
committed by GitHub
parent c1e31290ac
commit c9b874ff76
3 changed files with 7 additions and 129 deletions
+5 -33
View File
@@ -169,7 +169,11 @@ func (t *tui) handleSearchToggle() {
func (t *tui) handleServerConnect() {
if server, ok := t.serverList.GetSelectedServer(); ok {
t.showConnectModal(server)
t.app.Suspend(func() {
_ = t.serverService.SSH(server.Alias)
})
t.refreshServerList()
}
}
@@ -298,38 +302,6 @@ func (t *tui) showSearchBar() {
t.searchVisible = true
}
func (t *tui) showConnectModal(server domain.Server) {
msg := fmt.Sprintf("SSH to %s (%s@%s:%d)\n\nConfirm to start an SSH session .",
server.Alias, server.User, server.Host, server.Port)
modal := tview.NewModal().
SetText(msg).
AddButtons([]string{"Confirm", "Cancel"}).
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
if buttonIndex == 0 {
// Suspend the TUI while running the external ssh command.
t.app.Suspend(func() {
err := t.serverService.SSH(server.Alias)
if err != nil {
// Show a brief status after we resume
t.app.QueueUpdateDraw(func() {
if strings.Contains(strings.ToLower(err.Error()), "timeout") {
t.showStatusTempColor("SSH timeout, returning to list", "#FF6B6B")
} else {
t.showStatusTempColor("SSH failed: "+err.Error(), "#FF6B6B")
}
})
}
})
// Refresh to reflect updated last seen and ssh count
t.refreshServerList()
}
t.handleModalClose()
})
t.app.SetRoot(modal, true)
}
func (t *tui) showDeleteConfirmModal(server domain.Server) {
msg := fmt.Sprintf("Delete server %s (%s@%s:%d)?\n\nThis action cannot be undone.",
server.Alias, server.User, server.Host, server.Port)
-81
View File
@@ -1,81 +0,0 @@
// Copyright 2025.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ui
import (
"strings"
"time"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
// buildSplash creates a splash screen with a spinner; returns primitive and a stop function
func buildSplash(app *tview.Application) (tview.Primitive, func()) {
// Brand styling
title := "[#FFFFFF::b]lazy[-][#55D7FF::b]ssh[-]"
tagline := "[#AAAAAA]Fast server picker TUI • Loading your servers…[-]"
spinnerFrames := []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
text := tview.NewTextView().
SetDynamicColors(true).
SetTextAlign(tview.AlignCenter)
text.SetBorder(true).
SetTitle(" 🚀 lazyssh ").
SetBorderColor(tcell.Color238).
SetTitleColor(tcell.Color250)
// layout to center the card
box := tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(tview.NewBox(), 0, 1, false).
AddItem(text, 9, 0, false).
AddItem(tview.NewBox(), 0, 1, false)
container := tview.NewFlex().SetDirection(tview.FlexColumn).
AddItem(tview.NewBox(), 0, 1, false).
AddItem(box, 0, 2, false).
AddItem(tview.NewBox(), 0, 1, false)
stop := make(chan struct{})
go func() {
i := 0
for {
select {
case <-stop:
return
case <-time.After(90 * time.Millisecond):
frame := spinnerFrames[i%len(spinnerFrames)]
width := 20
filled := i % (width + 1)
prog := strings.Repeat("█", filled) + strings.Repeat("░", width-filled)
// rotate tips every ~12 frames
i++
app.QueueUpdateDraw(func() {
text.SetText(
"\n" +
"[::b]" + title + "[-]\n" +
"\n" + frame + " " + tagline + "\n" +
"\n[#55D7FF]" + prog,
)
})
}
}
}()
stopFunc := func() { close(stop) }
return container, stopFunc
}
+2 -15
View File
@@ -15,8 +15,6 @@
package ui
import (
"time"
"github.com/gdamore/tcell/v2"
"go.uber.org/zap"
@@ -65,7 +63,8 @@ func (t *tui) Run() error {
}
}()
t.app.EnableMouse(true)
t.initializeTheme().buildComponents().buildLayout().bindEvents().loadInitialData().loadSplashScreen()
t.initializeTheme().buildComponents().buildLayout().bindEvents().loadInitialData()
t.app.SetRoot(t.root, true)
t.logger.Infow("starting TUI application", "version", t.version, "commit", t.commit)
if err := t.app.Run(); err != nil {
t.logger.Errorw("application run error", "error", err)
@@ -141,15 +140,3 @@ func (t *tui) updateListTitle() {
t.serverList.SetTitle("Servers — Sort: " + t.sortMode.String())
}
}
func (t *tui) loadSplashScreen() *tui {
splash, stop := buildSplash(t.app)
t.app.SetRoot(splash, true)
time.AfterFunc(SplashScreenDuration, func() {
stop()
t.app.QueueUpdateDraw(func() {
t.app.SetRoot(t.root, true)
})
})
return t
}