From ee79d720ecc11641b9cc3cbf95fc7a4bc09bf5eb Mon Sep 17 00:00:00 2001 From: tumillanino Date: Fri, 31 Oct 2025 22:59:56 +1100 Subject: [PATCH] updated styling and installation steps --- tui/steps/confirm.go | 43 +++++++++++++++--------- tui/steps/disk_sel.go | 22 ++++++++++--- tui/steps/encryption.go | 1 - tui/steps/hostname.go | 30 +++++++++++------ tui/steps/install.go | 30 +++++++++++++---- tui/steps/user.go | 72 ++++++++++++++++++++++++++++++----------- tui/steps/welcome.go | 1 - 7 files changed, 144 insertions(+), 55 deletions(-) diff --git a/tui/steps/confirm.go b/tui/steps/confirm.go index 4d1ce58..5d08b9b 100644 --- a/tui/steps/confirm.go +++ b/tui/steps/confirm.go @@ -3,6 +3,7 @@ package steps import ( "fmt" "miasma-installer/tui/styles" + "strings" tea "github.com/charmbracelet/bubbletea" ) @@ -52,20 +53,32 @@ func (m ConfirmModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m ConfirmModel) View() string { - s := styles.TitleStyle.Render("Confirm Installation") - s += "\n\n" - s += "Please review your installation settings:\n\n" - s += fmt.Sprintf(" Disk: %s\n", m.Disk) - s += fmt.Sprintf(" Encryption: %s\n", map[bool]string{true: "Enabled (LUKS2)", false: "Disabled"}[m.EnableLUKS]) - s += fmt.Sprintf(" Hostname: %s\n", m.Hostname) - s += fmt.Sprintf(" Username: %s\n", m.Username) - s += fmt.Sprintf(" Filesystem: btrfs\n") - s += fmt.Sprintf(" Desktop: Cosmic Desktop\n") - s += fmt.Sprintf(" Kernel: linux-hardened\n") - s += fmt.Sprintf(" Bootloader: systemd-boot (UEFI)\n") - s += "\n" - s += styles.HelpStyle.Render("WARNING: This will ERASE ALL DATA on ") + m.Disk + "\n\n" - s += styles.HelpStyle.Render("[y] Proceed with installation [n] Cancel") + var content strings.Builder - return styles.MainStyle.Render(s) + content.WriteString(styles.TitleStyle.Render("✓ Confirm Installation")) + content.WriteString("\n\n") + + content.WriteString("Review your installation settings:\n\n") + + settings := []string{ + styles.RenderKeyValue("Disk", m.Disk), + styles.RenderKeyValue("Encryption", map[bool]string{true: "Enabled (LUKS2)", false: "Disabled"}[m.EnableLUKS]), + styles.RenderKeyValue("Hostname", m.Hostname), + styles.RenderKeyValue("Username", m.Username), + styles.RenderKeyValue("Filesystem", "btrfs"), + styles.RenderKeyValue("Desktop", "Cosmic Desktop"), + styles.RenderKeyValue("Kernel", "linux-hardened"), + styles.RenderKeyValue("Bootloader", "systemd-boot (UEFI)"), + } + + content.WriteString(styles.BoxStyle.Render(strings.Join(settings, "\n"))) + content.WriteString("\n\n") + + warning := fmt.Sprintf("⚠️ WARNING: This will ERASE ALL DATA on %s", m.Disk) + content.WriteString(styles.WarningBoxStyle.Render(warning)) + content.WriteString("\n\n") + + content.WriteString(styles.RenderHelp("y", "Proceed with installation", "n", "Cancel")) + + return styles.AppStyle.Render(content.String()) } diff --git a/tui/steps/disk_sel.go b/tui/steps/disk_sel.go index 287c182..3189d86 100644 --- a/tui/steps/disk_sel.go +++ b/tui/steps/disk_sel.go @@ -157,13 +157,27 @@ func (m DiskSelModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m DiskSelModel) View() string { + var content strings.Builder + if m.loading { - return styles.MainStyle.Render(styles.TitleStyle.Render("Scanning disks...")) + content.WriteString(styles.TitleStyle.Render("💿 Scanning Disks...")) + content.WriteString("\n\n") + content.WriteString(styles.SpinnerStyle.Render("● Detecting available storage devices...")) + return styles.AppStyle.Render(content.String()) } - s := m.list.View() - s += "\n" + styles.HelpStyle.Render("Use ↑/↓ to navigate, [Enter] to select disk.") - return s + content.WriteString(styles.TitleStyle.Render("💿 Select Installation Disk")) + content.WriteString("\n\n") + + warning := "⚠️ All data on the selected disk will be erased!" + content.WriteString(styles.WarningBoxStyle.Render(warning)) + content.WriteString("\n\n") + + content.WriteString(m.list.View()) + content.WriteString("\n\n") + content.WriteString(styles.RenderHelp("↑/↓", "Navigate", "Enter", "Select")) + + return styles.AppStyle.Render(content.String()) } func formatBytes(bytes uint64) string { diff --git a/tui/steps/encryption.go b/tui/steps/encryption.go index 31300c7..393fbeb 100644 --- a/tui/steps/encryption.go +++ b/tui/steps/encryption.go @@ -6,7 +6,6 @@ import ( "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" ) type EncryptionModel struct { diff --git a/tui/steps/hostname.go b/tui/steps/hostname.go index d3bd44d..23e9894 100644 --- a/tui/steps/hostname.go +++ b/tui/steps/hostname.go @@ -2,15 +2,16 @@ package steps import ( "miasma-installer/tui/styles" + "strings" "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" ) type HostnameModel struct { - Hostname string - input textinput.Model - Finished bool + Hostname string + input textinput.Model + Finished bool } func NewHostnameModel() HostnameModel { @@ -18,6 +19,7 @@ func NewHostnameModel() HostnameModel { ti.Placeholder = "miasma" ti.Focus() ti.CharLimit = 63 + ti.Width = 40 return HostnameModel{ input: ti, @@ -51,11 +53,21 @@ func (m HostnameModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m HostnameModel) View() string { - s := styles.TitleStyle.Render("System Hostname") - s += "\n\n" - s += "Enter a hostname for your system:\n\n" - s += m.input.View() + "\n\n" - s += styles.HelpStyle.Render("[Enter] Continue") + var content strings.Builder - return styles.MainStyle.Render(s) + content.WriteString(styles.TitleStyle.Render("💻 System Hostname")) + content.WriteString("\n\n") + + info := "Choose a name for your computer.\nThis will be used to identify your system on the network." + content.WriteString(styles.InfoBoxStyle.Render(info)) + content.WriteString("\n\n") + + content.WriteString(styles.LabelStyle.Render("Hostname:")) + content.WriteString("\n") + content.WriteString(styles.FocusedInputStyle.Render(m.input.View())) + content.WriteString("\n\n") + + content.WriteString(styles.RenderHelp("Enter", "Continue")) + + return styles.AppStyle.Render(content.String()) } diff --git a/tui/steps/install.go b/tui/steps/install.go index cb01712..6c91b35 100644 --- a/tui/steps/install.go +++ b/tui/steps/install.go @@ -421,19 +421,37 @@ func (m InstallModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m InstallModel) View() string { - s := styles.TitleStyle.Render("Installing Miasma OS") - s += "\n\n" - s += fmt.Sprintf("Step %d/%d: %s\n\n", m.currentStep, m.totalSteps, m.status) + var content strings.Builder + + content.WriteString(styles.TitleStyle.Render("⚙️ Installing Miasma OS")) + content.WriteString("\n\n") + + progress := fmt.Sprintf("Step %d/%d", m.currentStep, m.totalSteps) + content.WriteString(styles.ProgressTextStyle.Render(progress)) + content.WriteString("\n") + + bar := strings.Repeat("█", m.currentStep) + strings.Repeat("░", m.totalSteps-m.currentStep) + content.WriteString(styles.ProgressBarStyle.Render(bar)) + content.WriteString("\n\n") + + content.WriteString(styles.SpinnerStyle.Render("● ") + m.status) + content.WriteString("\n\n") if m.err != nil { - s += styles.HelpStyle.Render(fmt.Sprintf("Error: %v\n", m.err)) + errMsg := fmt.Sprintf("✗ Error: %v", m.err) + content.WriteString(styles.ErrorBoxStyle.Render(errMsg)) + content.WriteString("\n\n") + content.WriteString(styles.HelpStyle.Render("Press Ctrl+C to exit")) } if m.Finished && m.err == nil { - s += "\n" + styles.HelpStyle.Render("Installation successful! You can now reboot.\nPress Ctrl+C to exit") + success := "✓ Installation successful!\n\nYou can now reboot your system." + content.WriteString(styles.BoxStyle.Render(success)) + content.WriteString("\n\n") + content.WriteString(styles.RenderHelp("Ctrl+C", "Exit")) } - return styles.MainStyle.Render(s) + return styles.AppStyle.Render(content.String()) } func readLines(path string) ([]string, error) { diff --git a/tui/steps/user.go b/tui/steps/user.go index 77601a1..730937b 100644 --- a/tui/steps/user.go +++ b/tui/steps/user.go @@ -2,19 +2,20 @@ package steps import ( "miasma-installer/tui/styles" + "strings" "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" ) type UserModel struct { - Username string - Password string - usernameInput textinput.Model - passwordInput textinput.Model - confirmInput textinput.Model - focusIndex int - Finished bool + Username string + Password string + usernameInput textinput.Model + passwordInput textinput.Model + confirmInput textinput.Model + focusIndex int + Finished bool } func NewUserModel() UserModel { @@ -22,14 +23,17 @@ func NewUserModel() UserModel { ui.Placeholder = "username" ui.Focus() ui.CharLimit = 32 + ui.Width = 40 pi := textinput.New() pi.Placeholder = "password" pi.EchoMode = textinput.EchoPassword + pi.Width = 40 ci := textinput.New() ci.Placeholder = "confirm password" ci.EchoMode = textinput.EchoPassword + ci.Width = 40 return UserModel{ usernameInput: ui, @@ -103,23 +107,53 @@ func (m UserModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m UserModel) View() string { - s := styles.TitleStyle.Render("User Account") - s += "\n\n" - s += "Create your user account:\n\n" - s += "Username:\n" - s += m.usernameInput.View() + "\n\n" - s += "Password:\n" - s += m.passwordInput.View() + "\n\n" - s += "Confirm Password:\n" - s += m.confirmInput.View() + "\n\n" + var content strings.Builder + + content.WriteString(styles.TitleStyle.Render("👤 User Account")) + content.WriteString("\n\n") + + info := "Create your user account.\nThis user will have sudo privileges." + content.WriteString(styles.InfoBoxStyle.Render(info)) + content.WriteString("\n\n") + + content.WriteString(styles.LabelStyle.Render("Username:")) + content.WriteString("\n") + usernameStyle := styles.InputStyle + if m.focusIndex == 0 { + usernameStyle = styles.FocusedInputStyle + } + content.WriteString(usernameStyle.Render(m.usernameInput.View())) + content.WriteString("\n\n") + + content.WriteString(styles.LabelStyle.Render("Password:")) + content.WriteString("\n") + passwordStyle := styles.InputStyle + if m.focusIndex == 1 { + passwordStyle = styles.FocusedInputStyle + } + content.WriteString(passwordStyle.Render(m.passwordInput.View())) + content.WriteString("\n\n") + + content.WriteString(styles.LabelStyle.Render("Confirm Password:")) + content.WriteString("\n") + confirmStyle := styles.InputStyle + if m.focusIndex == 2 { + confirmStyle = styles.FocusedInputStyle + } + content.WriteString(confirmStyle.Render(m.confirmInput.View())) + content.WriteString("\n\n") if m.passwordInput.Value() != "" && m.confirmInput.Value() != "" { if m.passwordInput.Value() != m.confirmInput.Value() { - s += styles.HelpStyle.Render("Passwords do not match\n") + content.WriteString(styles.ErrorStyle.Render("✗ Passwords do not match")) + content.WriteString("\n\n") + } else { + content.WriteString(styles.SuccessStyle.Render("✓ Passwords match")) + content.WriteString("\n\n") } } - s += styles.HelpStyle.Render("[Tab] Switch fields [Enter] Continue") + content.WriteString(styles.RenderHelp("Tab", "Switch fields", "Enter", "Continue")) - return styles.MainStyle.Render(s) + return styles.AppStyle.Render(content.String()) } diff --git a/tui/steps/welcome.go b/tui/steps/welcome.go index 78f9543..7d8442a 100644 --- a/tui/steps/welcome.go +++ b/tui/steps/welcome.go @@ -5,7 +5,6 @@ import ( "strings" tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" ) type WelcomeModel struct {