file_picker.go

v0.5.1
Doc Versions Source
1
package tui
2
3
import (
4
	"fmt"
5
	"os"
6
	"strings"
7
8
	"github.com/charmbracelet/bubbles/filepicker"
9
	tea "github.com/charmbracelet/bubbletea"
10
	"github.com/charmbracelet/lipgloss"
11
)
12
13
func (m Model) showZipFilePicker() (tea.Model, tea.Cmd) {
14
	fp := filepicker.New()
15
	fp.AllowedTypes = []string{".zip"}
16
	fp.ShowHidden = false
17
	fp.ShowSize = true
18
	fp.ShowPermissions = true
19
	fp.DirAllowed = false
20
	fp.FileAllowed = true
21
	fp.AutoHeight = false
22
	fp.Height = 20
23
	fp.Cursor = "▸"
24
	fp.Styles.Cursor = lipgloss.NewStyle().Foreground(lipgloss.Color("170")).Bold(true)
25
	fp.Styles.Selected = lipgloss.NewStyle().Foreground(lipgloss.Color("170")).Bold(true)
26
	fp.Styles.Directory = lipgloss.NewStyle().Foreground(lipgloss.Color("33")).Bold(true)
27
	fp.Styles.Symlink = lipgloss.NewStyle().Foreground(lipgloss.Color("36"))
28
	fp.Styles.File = lipgloss.NewStyle().Foreground(lipgloss.Color("255"))
29
	fp.Styles.DisabledFile = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
30
	fp.Styles.DisabledCursor = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
31
	fp.Styles.DisabledSelected = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
32
	fp.Styles.Permission = lipgloss.NewStyle().Foreground(lipgloss.Color("244"))
33
	fp.Styles.FileSize = lipgloss.NewStyle().Foreground(lipgloss.Color("244")).Width(7).Align(lipgloss.Right)
34
	home, _ := os.UserHomeDir()
35
	if home != "" {
36
		fp.CurrentDirectory = home
37
	} else {
38
		fp.CurrentDirectory, _ = os.Getwd()
39
	}
40
	m.filePicker = fp
41
	m.phase = phaseFilePicker
42
	return m, m.filePicker.Init()
43
}
44
45
func (m Model) updateFilePicker(msg tea.Msg) (tea.Model, tea.Cmd) {
46
	switch msg := msg.(type) {
47
	case tea.KeyMsg:
48
		if msg.String() == "ctrl+c" {
49
			m.quitting = true
50
			return m, tea.Quit
51
		}
52
		if msg.String() == "q" {
53
			m.phase = phaseSelect
54
			return m, nil
55
		}
56
	}
57
58
	var cmd tea.Cmd
59
	m.filePicker, cmd = m.filePicker.Update(msg)
60
61
	if didSelect, path := m.filePicker.DidSelectFile(msg); didSelect {
62
		models, err := m.loadVKProxyModelsFromPath(path)
63
		if err != nil {
64
			m.modelsErr = err
65
			m.phase = phaseSelect
66
			return m, nil
67
		}
68
		return m.showVKProxyModels(models)
69
	}
70
71
	return m, cmd
72
}
73
74
func (m Model) viewFilePicker() string {
75
	var b strings.Builder
76
	b.WriteString(logoStyle.Render(logo))
77
	b.WriteString("\n\n")
78
	b.WriteString(promptStyle.Render(" Select claude-code-config.zip"))
79
	b.WriteString("\n\n")
80
81
	// Shorten path: replace home dir with ~.
82
	dir := m.filePicker.CurrentDirectory
83
	if home, _ := os.UserHomeDir(); home != "" {
84
		if dir == home {
85
			dir = "~"
86
		} else if strings.HasPrefix(dir, home+"/") {
87
			dir = "~" + dir[len(home):]
88
		}
89
	}
90
91
	panelW := 64
92
	pathHeader := hintStyle.Render(fmt.Sprintf(" 📁 %s", dir))
93
94
	border := lipgloss.RoundedBorder()
95
	panel := lipgloss.NewStyle().
96
		Border(border).
97
		BorderForeground(lipgloss.Color("170")).
98
		Padding(0, 1).
99
		Width(panelW).
100
		Render(pathHeader + "\n" + strings.Repeat("─", panelW-4) + "\n" + m.filePicker.View())
101
102
	b.WriteString(panel)
103
	b.WriteString("\n")
104
	b.WriteString(hintStyle.Render(" ↑/↓/pgup/pgdn navigate • enter/→ open • ←/esc back • q cancel"))
105
106
	content := b.String()
107
	if m.width > 0 && m.height > 0 {
108
		return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, content)
109
	}
110
	return content
111
}
112

Source Files