204 lines
4.0 KiB
Go
204 lines
4.0 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
|
|
"github.com/charmbracelet/bubbles/list"
|
|
"github.com/charmbracelet/bubbles/table"
|
|
"github.com/charmbracelet/bubbles/textarea"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
type mainModel struct {
|
|
width, height int
|
|
focused int
|
|
|
|
viewStyle lipgloss.Style
|
|
editorStyle lipgloss.Style
|
|
pickerStyle lipgloss.Style
|
|
|
|
table table.Model
|
|
editor textarea.Model
|
|
picker list.Model
|
|
}
|
|
|
|
var (
|
|
defaultStyle = lipgloss.NewStyle().
|
|
Align(lipgloss.Center).
|
|
BorderStyle(lipgloss.NormalBorder())
|
|
)
|
|
|
|
type item struct {
|
|
title, desc string
|
|
}
|
|
|
|
func (i item) Title() string { return i.title }
|
|
func (i item) Description() string { return i.desc }
|
|
func (i item) FilterValue() string { return i.title }
|
|
|
|
func newMainModerl() mainModel {
|
|
ed := textarea.New()
|
|
ed.Placeholder = "Try \"SELECT * FROM ?;\""
|
|
|
|
ed.ShowLineNumbers = false
|
|
ed.Focus()
|
|
|
|
columns := []table.Column{
|
|
{Title: "id", Width: 4},
|
|
{Title: "name", Width: 4},
|
|
{Title: "family_name", Width: 4},
|
|
}
|
|
|
|
rows := []table.Row{
|
|
{"0", "Conrad", "Adenauer"},
|
|
{"1", "Anna", "Aachen"},
|
|
{"2", "Karli", "Columbus"},
|
|
{"3", "Max", "Mustermann"},
|
|
{"4", "Bernd", "Brot"},
|
|
}
|
|
|
|
ta := table.New(
|
|
table.WithColumns(columns),
|
|
table.WithRows(rows),
|
|
)
|
|
|
|
items := []list.Item{
|
|
item{
|
|
title: "user",
|
|
desc: "users table",
|
|
},
|
|
item{
|
|
title: "job",
|
|
desc: "jobs table",
|
|
},
|
|
item{
|
|
title: "user_has_job",
|
|
desc: "user has a job",
|
|
},
|
|
}
|
|
|
|
li := list.New(items, list.NewDefaultDelegate(), 0, 0)
|
|
li.Title = "Table Picker"
|
|
|
|
return mainModel{
|
|
focused: 0,
|
|
viewStyle: defaultStyle,
|
|
editorStyle: defaultStyle,
|
|
pickerStyle: defaultStyle.BorderStyle(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("67")),
|
|
editor: ed,
|
|
table: ta,
|
|
picker: li,
|
|
}
|
|
}
|
|
|
|
func (m mainModel) Init() tea.Cmd {
|
|
return nil
|
|
}
|
|
|
|
func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
var (
|
|
edCmd tea.Cmd
|
|
taCmd tea.Cmd
|
|
liCmd tea.Cmd
|
|
)
|
|
|
|
switch msg := msg.(type) {
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
case "ctrl+c", "q":
|
|
return m, tea.Quit
|
|
case "tab":
|
|
if m.table.Focused() {
|
|
m.table.Blur()
|
|
m.editor.Focus()
|
|
} else {
|
|
m.editor.Blur()
|
|
m.table.Focus()
|
|
}
|
|
case "ctrl+e":
|
|
if m.focused == 1 {
|
|
m.focused = 0
|
|
} else {
|
|
m.focused = 1
|
|
}
|
|
}
|
|
case tea.WindowSizeMsg:
|
|
m = m.updateStyles(msg.Width, msg.Height)
|
|
}
|
|
|
|
m.editor, edCmd = m.editor.Update(msg)
|
|
m.table, taCmd = m.table.Update(msg)
|
|
if m.focused == 1 {
|
|
m.picker, liCmd = m.picker.Update(msg)
|
|
}
|
|
|
|
return m, tea.Batch(edCmd, taCmd, liCmd)
|
|
}
|
|
|
|
func (m mainModel) updateStyles(width, height int) mainModel {
|
|
h, v := defaultStyle.GetFrameSize()
|
|
|
|
topHeight := (height * 3 / 4) - h
|
|
editorHeight := (height * 1 / 4) - h
|
|
|
|
m.editorStyle = defaultStyle.
|
|
Width(width - v).
|
|
Height(editorHeight)
|
|
|
|
m.viewStyle = defaultStyle.
|
|
Width(width - v).
|
|
Height(topHeight)
|
|
|
|
m.editor.SetWidth(m.editorStyle.GetWidth())
|
|
m.editor.SetHeight(m.editorStyle.GetHeight())
|
|
|
|
m.table.SetWidth(m.viewStyle.GetWidth())
|
|
m.table.SetHeight(m.viewStyle.GetHeight())
|
|
|
|
columns := m.table.Columns()
|
|
colLen := len(columns)
|
|
colWidth := m.table.Width() / colLen
|
|
for i := range columns {
|
|
columns[i].Width = colWidth
|
|
}
|
|
m.table.SetColumns(columns)
|
|
|
|
m.pickerStyle = m.pickerStyle.
|
|
Width((width * 7 / 10) - v).
|
|
Height((height * 7 / 10) - h)
|
|
m.picker.SetSize(m.pickerStyle.GetWidth(), m.pickerStyle.GetHeight())
|
|
|
|
m.width = width
|
|
m.height = height
|
|
return m
|
|
}
|
|
|
|
func (m mainModel) View() string {
|
|
|
|
view := m.viewStyle.
|
|
Render(m.table.View())
|
|
|
|
editor := m.editorStyle.
|
|
Render(m.editor.View())
|
|
|
|
main := lipgloss.JoinVertical(lipgloss.Top, view, editor)
|
|
_ = main
|
|
|
|
if m.focused == 1 {
|
|
x := (m.width / 2) - m.picker.Width()/2
|
|
y := (m.height / 2) - m.picker.Height()/2
|
|
|
|
return PlaceOverlay(x, y, m.pickerStyle.Render(m.picker.View()), main, false)
|
|
}
|
|
|
|
return main
|
|
}
|
|
|
|
func main() {
|
|
p := tea.NewProgram(newMainModerl(), tea.WithAltScreen())
|
|
if _, err := p.Run(); err != nil {
|
|
log.Fatalf("could not start program: %v\n", err)
|
|
}
|
|
}
|