Class: RailsMarkup::Cli::SetupWizard

Inherits:
Object
  • Object
show all
Includes:
Bubbletea::Model
Defined in:
lib/rails_markup/cli/setup_wizard.rb

Overview

Interactive TUI setup wizard using Bubbletea's Elm architecture. State machine: accent → position → size → fab → screenshots → url → scope → confirm

Constant Summary collapse

STEPS =
%i[accent position size fab screenshots url scope confirm].freeze
STEP_CONFIG =
{
  accent: {
    title: "Toolbar Accent",
    type: :select,
    options: %w[indigo amber blue emerald rose]
  },
  position: {
    title: "Toolbar Position",
    type: :select,
    options: %w[bl br tl tr],
    labels: { "bl" => "Bottom-left", "br" => "Bottom-right", "tl" => "Top-left", "tr" => "Top-right" }
  },
  size: {
    title: "Toolbar Size",
    type: :select,
    options: %w[slim compact default],
    labels: { "slim" => "Slim (32px)", "compact" => "Compact (40px)", "default" => "Default (48px)" }
  },
  fab: {
    title: "Show Floating Button",
    type: :select,
    options: %w[yes no],
    labels: { "yes" => "Yes — show the FAB", "no" => "No — hide the FAB (pins still show)" }
  },
  screenshots: {
    title: "Enable Screenshots",
    type: :select,
    options: %w[yes no],
    labels: { "yes" => "Yes", "no" => "No" }
  },
  url: {
    title: "Production URL",
    type: :text,
    hint: "Optional — press Enter to skip"
  },
  scope: {
    title: "MCP Server Scope",
    type: :select,
    options: %w[local global codex],
    labels: {
      "local"  => "This project only (.mcp.json)",
      "global" => "All projects — Claude Code (~/.claude/settings.json)",
      "codex"  => "All projects — Codex CLI (~/.codex/config.toml)"
    }
  },
  confirm: {
    title: "Confirm Setup",
    type: :confirm
  }
}.freeze
HEADER_STYLE =
Lipgloss::Style.new.bold(true).foreground("#FFFFFF").background("#5C4AE4").padding(0, 1)
HINT_STYLE =
Lipgloss::Style.new.foreground("#6B7280")
CURSOR_STYLE =
Lipgloss::Style.new.bold(true).foreground("#818cf8")
OPTION_STYLE =
Lipgloss::Style.new.foreground("#E2E2E2")

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dir: Dir.pwd) ⇒ SetupWizard

Returns a new instance of SetupWizard.



76
77
78
79
80
81
82
83
# File 'lib/rails_markup/cli/setup_wizard.rb', line 76

def initialize(dir: Dir.pwd)
  @dir = dir
  @step_index = 0
  @cursor = 0
  @choices = {}
  @text_input = ""
  @completed = false
end

Instance Attribute Details

#choicesObject (readonly)

Returns the value of attribute choices.



74
75
76
# File 'lib/rails_markup/cli/setup_wizard.rb', line 74

def choices
  @choices
end

#completedObject (readonly)

Returns the value of attribute completed.



74
75
76
# File 'lib/rails_markup/cli/setup_wizard.rb', line 74

def completed
  @completed
end

Instance Method Details

#initObject



85
86
87
# File 'lib/rails_markup/cli/setup_wizard.rb', line 85

def init
  [self, nil]
end

#update(message) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/rails_markup/cli/setup_wizard.rb', line 89

def update(message)
  case message
  when Bubbletea::KeyMessage
    handle_key(message)
  else
    [self, nil]
  end
end

#viewObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/rails_markup/cli/setup_wizard.rb', line 98

def view
  step = current_step
  config = STEP_CONFIG[step]

  lines = []
  lines << HEADER_STYLE.render(" Rails Markup Setup — Step #{@step_index + 1}/#{STEPS.size} ")
  lines << ""
  lines << "  #{config[:title]}"
  lines << ""

  case config[:type]
  when :select
    config[:options].each_with_index do |opt, i|
      label = config.dig(:labels, opt) || opt
      if i == @cursor
        lines << "  #{CURSOR_STYLE.render("")} #{label}"
      else
        lines << "    #{OPTION_STYLE.render(label)}"
      end
    end
  when :text
    lines << "  #{HINT_STYLE.render(config[:hint])}"
    lines << ""
    lines << "  > #{@text_input}"
  when :confirm
    lines << render_summary
    lines << ""
    lines << "  #{HINT_STYLE.render("Press Enter to write config, Esc to cancel")}"
  end

  lines << ""
  lines << "  #{HINT_STYLE.render("↑/↓ navigate · Enter select · Esc cancel")}" unless step == :confirm

  lines.join("\n")
end