package tui import ( "sort" "github.com/MDietermann/ArduinoArchSetup/internal/config" "github.com/MDietermann/ArduinoArchSetup/internal/module" ) // Theme is a named colorscheme presented in the wizard. Each entry carries // per-tool theme names; Plan 3b uses NvChadTheme, later plans add more. type Theme struct { ID string Name string NvChadTheme string } // BuiltinThemes is the fixed list the wizard shows. Keep in sync with the // themes shipped by Plan 3's theme module. var BuiltinThemes = []Theme{ {ID: "gruvbox", Name: "Gruvbox Dark", NvChadTheme: "gruvbox"}, {ID: "catppuccin", Name: "Catppuccin Mocha", NvChadTheme: "catppuccin"}, {ID: "tokyonight", Name: "Tokyo Night", NvChadTheme: "tokyonight"}, {ID: "nord", Name: "Nord", NvChadTheme: "nord"}, {ID: "dracula", Name: "Dracula", NvChadTheme: "dracula"}, } // ThemeByID returns the Theme with the given ID. The bool is false when no // match is found; callers decide whether to fall back or error. func ThemeByID(themes []Theme, id string) (Theme, bool) { for _, t := range themes { if t.ID == id { return t, true } } return Theme{}, false } // ModuleChoice is one row in the module selector. type ModuleChoice struct { ID string Name string Description string Selected bool } // WizardState is the payload the wizard fills in and the dashboard reads. type WizardState struct { ThemeID string Modules []ModuleChoice Parallelism int // advanced; reserved for a future concurrent engine HaltOnError bool // advanced Confirmed bool // true once the user hits Confirm on the last screen } // NewWizardState builds an initial state from the running config and the // registered modules. Pre-ticks all modules except those disabled in the // overlay, defaults the theme to the first built-in theme. func NewWizardState(cfg config.Config, reg *module.Registry) WizardState { disabled := map[string]bool{} for _, id := range cfg.DisabledModules { disabled[id] = true } mods := reg.All() choices := make([]ModuleChoice, 0, len(mods)) for _, m := range mods { meta := m.Meta() choices = append(choices, ModuleChoice{ ID: meta.ID, Name: meta.Name, Description: meta.Description, Selected: !disabled[meta.ID], }) } sort.Slice(choices, func(i, j int) bool { return choices[i].ID < choices[j].ID }) theme := BuiltinThemes[0].ID if override, ok := cfg.ThemeOverrides["__active"]; ok && override != "" { theme = override } return WizardState{ ThemeID: theme, Modules: choices, Parallelism: 1, } } // SelectedIDs returns only the checked module IDs. func (s WizardState) SelectedIDs() []string { out := make([]string, 0, len(s.Modules)) for _, m := range s.Modules { if m.Selected { out = append(out, m.ID) } } return out }