From 11eab6bce7863332b396f99ed82192c677a42a3a Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Fri, 13 Mar 2026 15:05:35 +0200 Subject: [PATCH] Use checkmark for success message --- internal/output/plain_format.go | 6 +++--- internal/output/plain_format_test.go | 4 ++-- internal/output/plain_sink_test.go | 4 ++-- internal/output/style.go | 13 +++++++++++++ internal/ui/app_test.go | 2 +- internal/ui/components/message.go | 2 +- internal/ui/styles/styles.go | 7 +++++-- 7 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 internal/output/style.go diff --git a/internal/output/plain_format.go b/internal/output/plain_format.go index 0593be0..735a674 100644 --- a/internal/output/plain_format.go +++ b/internal/output/plain_format.go @@ -42,9 +42,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 @@ -112,7 +112,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: diff --git a/internal/output/plain_format_test.go b/internal/output/plain_format_test.go index 11ea01c..799f5ff 100644 --- a/internal/output/plain_format_test.go +++ b/internal/output/plain_format_test.go @@ -20,7 +20,7 @@ func TestFormatEventLine(t *testing.T) { { name: "message event success", event: MessageEvent{Severity: SeveritySuccess, Text: "done"}, - want: "> Success: done", + want: SuccessMarkerText() + " done", wantOK: true, }, { @@ -56,7 +56,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 863d1fd..3d491b0 100644 --- a/internal/output/plain_sink_test.go +++ b/internal/output/plain_sink_test.go @@ -59,12 +59,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..a24a5e9 --- /dev/null +++ b/internal/output/style.go @@ -0,0 +1,13 @@ +package output + +import "fmt" + +const SuccessColorHex = "#B7C95C" + +func SuccessMarker() string { + return fmt.Sprintf("\x1b[38;2;183;201;92m%s\x1b[0m", SuccessMarkerText()) +} + +func SuccessMarkerText() string { + return "✔︎" +} diff --git a/internal/ui/app_test.go b/internal/ui/app_test.go index 6d3a582..d1bfa2b 100644 --- a/internal/ui/app_test.go +++ b/internal/ui/app_test.go @@ -174,7 +174,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 9ba2da6..36dea51 100644 --- a/internal/ui/components/message.go +++ b/internal/ui/components/message.go @@ -9,7 +9,7 @@ func RenderMessage(e output.MessageEvent) string { prefix := styles.Secondary.Render("> ") switch e.Severity { case output.SeveritySuccess: - return prefix + styles.Success.Render("Success:") + " " + styles.Message.Render(e.Text) + return styles.Success.Render(output.SuccessMarkerText()) + " " + styles.Message.Render(e.Text) case output.SeverityNote: return prefix + styles.Note.Render("Note:") + " " + styles.Message.Render(e.Text) 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"))