Files
LazyPM/cmd/pm/intro.go
Robin Olsen 3e9a903506 works now
2026-03-18 11:58:31 +01:00

163 lines
3.9 KiB
Go

package main
import (
"strings"
"charm.land/bubbles/v2/key"
"charm.land/bubbletea/v2"
"charm.land/lipgloss/v2"
"github.com/LazyBachelor/LazyPM/internal/models"
"github.com/LazyBachelor/LazyPM/internal/style"
)
const stages = 2
const (
IntroTitle = "Project Management Interface Survey"
IntroductionText = `This survey evaluates how people use different project management interfaces to complete common tasks.
You will complete a short set of task-based exercises and answer a few follow-up questions about the experience.
Your feedback helps us compare interface design and usability.
The survey takes around 15-20 minutes to complete.`
Disclaimer = `Data Collection Notice
• Responses are anonymized before analysis
• We collect task results, questionnaire answers, and interaction events during the survey
• We do not intentionally collect personally identifying information
• You may exit at any time by pressing Esc between tasks or closing the terminal.
• Data is collected continuously during the survey, so exiting early will still contribute valuable insights.`
)
type keyMap struct {
Start key.Binding
Continue key.Binding
Back key.Binding
Quit key.Binding
}
type introModel struct {
stage int
width, height int
userQuit bool
keys keyMap
}
func newIntroModel() introModel {
var keys = keyMap{
Start: key.NewBinding(
key.WithKeys("enter"),
key.WithHelp("enter", "start survey"),
),
Continue: key.NewBinding(
key.WithKeys("space", "j", "l", "down", "right"),
key.WithHelp("space", "continue"),
),
Back: key.NewBinding(
key.WithKeys("b", "k", "h", "backspace", "up", "left"),
key.WithHelp("b", "back"),
),
Quit: key.NewBinding(
key.WithKeys("esc", "ctrl+c", "q"),
key.WithHelp("esc", "quit"),
),
}
return introModel{
stage: 1,
keys: keys,
}
}
func (m introModel) Run() error {
model, err := tea.NewProgram(m).Run()
if err != nil {
return err
}
if im, ok := model.(introModel); ok && im.userQuit {
return models.ErrUserQuit
}
return nil
}
func (m introModel) Init() tea.Cmd {
return nil
}
func (m introModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.SetSize(msg.Width, msg.Height)
case tea.KeyPressMsg:
switch {
case key.Matches(msg, m.keys.Start) && m.stage == stages:
return m, tea.Quit
case key.Matches(msg, m.keys.Continue):
if m.stage < stages {
m.stage++
}
case key.Matches(msg, m.keys.Back):
if m.stage > 1 {
m.stage--
}
return m, nil
case key.Matches(msg, m.keys.Quit):
m.userQuit = true
return m, tea.Quit
}
}
return m, nil
}
func (m introModel) View() tea.View {
if m.width < 55 || m.height < 16 {
content := lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center,
style.TextStyle.Render("Terminal too small."))
v := tea.NewView(content)
v.AltScreen = true
return v
}
var content string
switch m.stage {
case 1:
content = IntroductionText
case 2:
content = Disclaimer
default:
return tea.NewView("")
}
boxWidth := min(m.width-10, 120)
boxStyle := style.BorderStyle.
Margin(1, 0).Padding(2, 4).Width(boxWidth)
var b strings.Builder
b.WriteString(style.TitleStyle.Render(IntroTitle))
b.WriteString("\n")
b.WriteString(boxStyle.Render(style.TextStyle.Render(content)))
b.WriteString("\n")
helpText := "Press " + m.keys.Continue.Help().Key + " to continue • " +
m.keys.Back.Help().Key + " to go back • " + m.keys.Quit.Help().Key + " to quit"
if m.stage == stages {
helpText += "\nPress " + m.keys.Start.Help().Key + " to start the survey"
}
b.WriteString(style.HelpStyle.Render(helpText))
final := lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, b.String())
v := tea.NewView(final)
v.AltScreen = true
return v
}
func (m *introModel) SetSize(width, height int) {
m.width, m.height = width, height
}