first draft of miasma installer
This commit is contained in:
70
tui/model.go
Normal file
70
tui/model.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"miasma-installer/tui/steps"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
type State int
|
||||
|
||||
const (
|
||||
StateWelcome State = iota
|
||||
StateDiskSelection
|
||||
StateInstalling
|
||||
StateFinished
|
||||
)
|
||||
|
||||
type RootModel struct {
|
||||
State State
|
||||
CurrentModel tea.Model
|
||||
Width int
|
||||
Height int
|
||||
}
|
||||
|
||||
func NewModel() RootModel {
|
||||
return RootModel{
|
||||
State: StateWelcome,
|
||||
CurrentModel: steps.NewWelcomeModel(),
|
||||
}
|
||||
}
|
||||
|
||||
func (m RootModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cmd tea.Cmd
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
if msg.String() == "ctrl+c" {
|
||||
return m, tea.Quit
|
||||
}
|
||||
case tea.WindowSizeMsg:
|
||||
m.Width = msg.Width
|
||||
m.Height = msg.Height
|
||||
}
|
||||
|
||||
m.CurrentModel, cmd = m.CurrentModel.Update(msg)
|
||||
|
||||
switch m.CurrentModel.(type) {
|
||||
case steps.WelcomeModel:
|
||||
if m.CurrentModel.(steps.WelcomeModel).Finished {
|
||||
m.State = StateDiskSelection
|
||||
m.CurrentModel = steps.NewDiskSelModel(m.Width, m.Height)
|
||||
return m, m.CurrentModel.Init()
|
||||
}
|
||||
|
||||
case steps.DiskSelModel:
|
||||
if m.CurrentModel.(steps.DiskSelModel).Finished {
|
||||
// need to update this to pass actual selected disk model to the installer
|
||||
selectedDisk := m.CurrentModel.(steps.DiskSelModel).SelectedDisk
|
||||
m.State = StateInstalling
|
||||
m.CurrentModel = steps.NewInstallModel(selectedDisk)
|
||||
return m, m.CurrentModel.Init()
|
||||
}
|
||||
// logic for StateInstalling -> StateFinished will go here
|
||||
}
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
func (m RootModel) View() string {
|
||||
return m.CurrentModel.View()
|
||||
}
|
||||
94
tui/steps/disk_sel.go
Normal file
94
tui/steps/disk_sel.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package steps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"miasma-installer/tui/styles"
|
||||
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
type Disk struct {
|
||||
name, description string
|
||||
}
|
||||
|
||||
func (i Disk) FilterValue() string { return i.name }
|
||||
func (i Disk) Title() string { return i.name }
|
||||
func (i Disk) Description() string { return i.description }
|
||||
|
||||
type ItemDelegate struct{}
|
||||
|
||||
func (i ItemDelegate) Height() int { return 1 }
|
||||
func (i ItemDelegate) Width() int { return 0 }
|
||||
func (i ItemDelegate) Update(msg tea.Msg, m list.Model) tea.Cmd { return nil }
|
||||
func (i ItemDelegate) Render(w io.Writer, m list.Model, index int, item list.Item) {
|
||||
i, ok := item.(Disk)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
s := fmt.Sprintf("%d. %s - %s", index+1, i.Title(), i.Description())
|
||||
|
||||
// focus styles
|
||||
if index == m.Index() {
|
||||
s = styles.ActiveItemStyle.Render("> " + s)
|
||||
} else {
|
||||
s = styles.InactiveItemStyle.Render(" " + s)
|
||||
}
|
||||
fmt.Fprint(w, s)
|
||||
}
|
||||
|
||||
type DiskSelModel struct {
|
||||
list list.Model
|
||||
Finished bool
|
||||
SelectedDisk string
|
||||
}
|
||||
|
||||
func NewDiskSelModel(width, height int) DiskSelModel {
|
||||
// This is a placeholder - I need to update this to a tea.Cmd to scan the system for drives
|
||||
disks := []list.Item{
|
||||
Disk{name: "/dev/sda", description: "500GB Samsung NVME"},
|
||||
Disk{name: "/dev/sdb", description: "1TB Baracuda HDD"},
|
||||
Disk{name: "/dev/loop0", description: "2GB Fanxiang SSD"},
|
||||
}
|
||||
|
||||
l := list.New(disks, itemDelegate{}, width, height-5)
|
||||
l.Title = styles.TitleStyle.Render("Select Installation Disk")
|
||||
l.SetShowStatusBar(false)
|
||||
l.SetFilterEnabled(false)
|
||||
l.Styles.Title = styles.TitleStyle
|
||||
l.KeyMap.Unbind()
|
||||
|
||||
return DiskSelModel{list: l}
|
||||
}
|
||||
|
||||
func (m DiskSelModel) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m DiskSelModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if m.Finished {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
if msg.String() == "enter" {
|
||||
if item, ok := m.list.SelectedItem().(Disk); ok {
|
||||
m.SelectedDisk = item.name
|
||||
m.Finished = true
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
var cmd tea.Cmd
|
||||
m.list, cmd = m.list.Update(msg)
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
func (m DiskSelModel) View() string {
|
||||
s := m.list.View()
|
||||
s += "\n" + styles.HelpStyle.Render("Use ↑/↓ to navigate, [Enter] to select disk.")
|
||||
return s
|
||||
}
|
||||
0
tui/steps/install.go
Normal file
0
tui/steps/install.go
Normal file
46
tui/steps/welcome.go
Normal file
46
tui/steps/welcome.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package steps
|
||||
|
||||
import (
|
||||
"miasma-installer/tui/styles"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
type WelcomeModel struct {
|
||||
Finished bool
|
||||
}
|
||||
|
||||
func NewWelcomeModel() WelcomeModel {
|
||||
return WelcomeModel{Finished: false}
|
||||
}
|
||||
|
||||
func (m WelcomeModel) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m WelcomeModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if m.Finished {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "enter":
|
||||
m.Finished = true
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m WelcomeModel) View() string {
|
||||
s := styles.TitleStyle.Render("Welcome to the Miasma OS Installer")
|
||||
s += "\n\n"
|
||||
s += "This program will guide you through installing Miasma OS. \n"
|
||||
s += "Please ensure that you have backed up any important data before proceding"
|
||||
s += "\n\n"
|
||||
s += styles.HelpStyle.Render("Press [Enter] to continue")
|
||||
s += styles.HelpStyle.Render("Press [Ctrl+C] to exit")
|
||||
|
||||
return styles.MainStyle.Render(s)
|
||||
}
|
||||
25
tui/styles/styles.go
Normal file
25
tui/styles/styles.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package styles
|
||||
|
||||
import "github.com/charmbracelet/lipgloss"
|
||||
|
||||
var (
|
||||
MainStyle = lipgloss.NewStyle().
|
||||
Border(lipgloss.RoundedBorder()).
|
||||
BorderForeground(lipgloss.Color("#7fb4ca")).
|
||||
Padding(1, 2)
|
||||
|
||||
HelpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241"))
|
||||
|
||||
TitleStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("#7fb4ca")).
|
||||
Align(lipgloss.Center).
|
||||
Bold(true).
|
||||
PaddingBottom(1)
|
||||
|
||||
ActiveItemStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("#87a987")).
|
||||
Bold(true)
|
||||
|
||||
InactiveItemStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("240"))
|
||||
)
|
||||
Reference in New Issue
Block a user