diff --git a/internal/output/plain_format.go b/internal/output/plain_format.go index daecb73..251b325 100644 --- a/internal/output/plain_format.go +++ b/internal/output/plain_format.go @@ -49,9 +49,9 @@ func formatStatusLine(e ContainerStatusEvent) (string, bool) { return "Waiting for LocalStack to be ready...", true case "ready": if e.Detail != "" { - return fmt.Sprintf("LocalStack ready (%s)", e.Detail), true + return fmt.Sprintf("%s LocalStack ready (%s)", SuccessMarkerText(), e.Detail), true } - return "LocalStack ready", true + return SuccessMarkerText() + " LocalStack ready", true default: if e.Detail != "" { return fmt.Sprintf("LocalStack: %s (%s)", e.Phase, e.Detail), true @@ -116,7 +116,7 @@ func formatAuthEvent(e AuthEvent) string { func formatMessageEvent(e MessageEvent) string { switch e.Severity { case SeveritySuccess: - return "> Success: " + e.Text + return SuccessMarkerText() + " " + e.Text case SeverityNote: return "> Note: " + e.Text case SeverityWarning: @@ -151,7 +151,7 @@ func formatErrorEvent(e ErrorEvent) string { func formatInstanceInfo(e InstanceInfoEvent) string { var sb strings.Builder - sb.WriteString("✓ " + e.EmulatorName + " is running (" + e.Host + ")") + sb.WriteString(SuccessMarkerText() + " " + e.EmulatorName + " is running (" + e.Host + ")") var meta []string if e.Uptime > 0 { meta = append(meta, "UPTIME: "+formatUptime(e.Uptime)) diff --git a/internal/output/plain_format_test.go b/internal/output/plain_format_test.go index 42168c5..9124fa3 100644 --- a/internal/output/plain_format_test.go +++ b/internal/output/plain_format_test.go @@ -24,7 +24,7 @@ func TestFormatEventLine(t *testing.T) { { name: "message event success", event: MessageEvent{Severity: SeveritySuccess, Text: "done"}, - want: "> Success: done", + want: SuccessMarkerText() + " done", wantOK: true, }, { @@ -60,7 +60,7 @@ func TestFormatEventLine(t *testing.T) { { name: "status ready with detail", event: ContainerStatusEvent{Phase: "ready", Container: "localstack-aws", Detail: "abc123"}, - want: "LocalStack ready (abc123)", + want: SuccessMarkerText() + " LocalStack ready (abc123)", wantOK: true, }, { diff --git a/internal/output/plain_sink_test.go b/internal/output/plain_sink_test.go index 38dcf8c..ee9a275 100644 --- a/internal/output/plain_sink_test.go +++ b/internal/output/plain_sink_test.go @@ -61,12 +61,12 @@ func TestPlainSink_EmitsStatusEvent(t *testing.T) { { name: "ready phase with detail", event: ContainerStatusEvent{Phase: "ready", Container: "localstack-aws", Detail: "abc123"}, - expected: "LocalStack ready (abc123)\n", + expected: fmt.Sprintf("%s LocalStack ready (abc123)\n", SuccessMarkerText()), }, { name: "ready phase without detail", event: ContainerStatusEvent{Phase: "ready", Container: "localstack-aws"}, - expected: "LocalStack ready\n", + expected: fmt.Sprintf("%s LocalStack ready\n", SuccessMarkerText()), }, { name: "unknown phase with detail", diff --git a/internal/output/style.go b/internal/output/style.go new file mode 100644 index 0000000..33e1f39 --- /dev/null +++ b/internal/output/style.go @@ -0,0 +1,7 @@ +package output + +const SuccessColorHex = "#B7C95C" + +func SuccessMarkerText() string { + return "✔︎" +} diff --git a/internal/ui/app.go b/internal/ui/app.go index 9804ed5..740fb30 100644 --- a/internal/ui/app.go +++ b/internal/ui/app.go @@ -182,6 +182,9 @@ func (a App) Update(msg tea.Msg) (tea.Model, tea.Cmd) { a.pullProgress = a.pullProgress.Hide() } if line, ok := output.FormatEventLine(msg); ok { + if msg.Phase == "ready" { + line = strings.Replace(line, output.SuccessMarkerText(), styles.Success.Render(output.SuccessMarkerText()), 1) + } a.lines = appendLine(a.lines, styledLine{text: line}) } return a, nil diff --git a/internal/ui/app_test.go b/internal/ui/app_test.go index 0949fa2..06a3d20 100644 --- a/internal/ui/app_test.go +++ b/internal/ui/app_test.go @@ -176,7 +176,7 @@ func TestAppMessageEventRendering(t *testing.T) { if len(app.lines) != 1 { t.Fatalf("expected 1 line, got %d", len(app.lines)) } - if !strings.Contains(app.lines[0].text, "Success:") || !strings.Contains(app.lines[0].text, "Done") { + if !strings.Contains(app.lines[0].text, output.SuccessMarkerText()) || !strings.Contains(app.lines[0].text, "Done") { t.Fatalf("expected rendered success message, got: %q", app.lines[0].text) } } diff --git a/internal/ui/components/message.go b/internal/ui/components/message.go index 1b60b6a..f2d36ab 100644 --- a/internal/ui/components/message.go +++ b/internal/ui/components/message.go @@ -45,7 +45,8 @@ func messagePrefix(e output.MessageEvent) (string, string) { prefix := styles.Secondary.Render("> ") switch e.Severity { case output.SeveritySuccess: - return "> Success:", prefix + styles.Success.Render("Success:") + checkmark := output.SuccessMarkerText() + return checkmark, styles.Success.Render(checkmark) case output.SeverityNote: return "> Note:", prefix + styles.Note.Render("Note:") case output.SeverityWarning: diff --git a/internal/ui/styles/styles.go b/internal/ui/styles/styles.go index 792ffb7..30be467 100644 --- a/internal/ui/styles/styles.go +++ b/internal/ui/styles/styles.go @@ -1,6 +1,9 @@ package styles -import "github.com/charmbracelet/lipgloss" +import ( + "github.com/charmbracelet/lipgloss" + "github.com/localstack/lstk/internal/output" +) const ( NimboDarkColor = "#3F51C7" @@ -39,7 +42,7 @@ var ( // Message severity styles Success = lipgloss.NewStyle(). - Foreground(lipgloss.Color("42")) + Foreground(lipgloss.Color(output.SuccessColorHex)) Note = lipgloss.NewStyle(). Foreground(lipgloss.Color("33"))