Skip to content

Commit ef100de

Browse files
committed
fix(tui): answer card — darker bg-1 surface, symmetric padding
The card used the WebUI's bg-2 card token (#10131A), which is tuned to sit on the WebUI's near-black page base. A terminal's own background is unknown and often neutral gray (VS Code's #1E1E1E), where bg-2 reads loudly blue. One step down EMBER's ladder — bg-1 #0B0D12, the chrome layer — keeps the card a quiet recessed panel on any dark terminal. Vertical framing was asymmetric: glamour's document block prefix added a blank line on top while render() trimmed the trailing ones, so the card carried one line of top padding and none below. The document block prefix/suffix are now stripped in answerGlamourStyle and the card owns the frame: Padding(1,1) — one line above and below, one column each side, identical for finalized (glamour) and streaming (raw) answers.
1 parent 00ad174 commit ef100de

2 files changed

Lines changed: 19 additions & 8 deletions

File tree

‎internal/tui/copyclean_test.go‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func TestAnswerCard(t *testing.T) {
108108
lipgloss.SetColorProfile(termenv.TrueColor)
109109
defer lipgloss.SetColorProfile(termenv.Ascii)
110110
for name, wantESC := range map[string]string{
111-
"ember-dark": "[48;2;16;19;26m", // #10131A
111+
"ember-dark": "[48;2;11;13;18m", // #0B0D12 (EMBER bg-1)
112112
"ember-light": "[48;2;239;236;229m", // #EFECE5
113113
"classic": "[48;2;22;22;30m", // #16161E
114114
"high-contrast": "",
@@ -151,7 +151,7 @@ func TestAnswerCard(t *testing.T) {
151151
t.Error("user turn painted a surface — only the answer carries one")
152152
}
153153
asstOut, _ := m.renderMessage(m.msgs[1], 1, 0)
154-
if !strings.Contains(asstOut, "[48;2;16;19;26m") {
154+
if !strings.Contains(asstOut, "[48;2;11;13;18m") {
155155
t.Errorf("answer card surface missing:\n%q", asstOut)
156156
}
157157
if !strings.Contains(plain(asstOut), "Fixed. The cookie was stale.") {
@@ -174,7 +174,7 @@ func TestSurfaceWeave(t *testing.T) {
174174
defer lipgloss.SetColorProfile(termenv.Ascii)
175175

176176
// weaveSurface is the exact transformation: reset → reset + surface.
177-
bg := "\x1b[48;2;16;19;26m"
177+
bg := "\x1b[48;2;11;13;18m"
178178
woven := weaveSurface("\x1b[38;2;231;233;238mspan1\x1b[0m gap \x1b[38;2;231;233;238;1mspan2\x1b[0m", bg)
179179
want := "\x1b[38;2;231;233;238mspan1\x1b[0m" + bg + " gap \x1b[38;2;231;233;238;1mspan2\x1b[0m" + bg
180180
if woven != want {

‎internal/tui/styles.go‎

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,12 @@ var (
6161
faint: "#6B7280",
6262
bodyText: "#8B95A8",
6363
hairline: "#2E3242",
64-
surface: "#10131A",
65-
grad: [2][3]int{{0xFF, 0xC9, 0x5E}, {0xFF, 0x8A, 0x3D}},
64+
// bg-1, not the WebUI's bg-2 card token: the TUI's "page base" is
65+
// the terminal's own background — often neutral gray — where bg-2
66+
// reads loudly blue. One step down keeps the card a quiet recessed
67+
// panel on any dark terminal.
68+
surface: "#0B0D12",
69+
grad: [2][3]int{{0xFF, 0xC9, 0x5E}, {0xFF, 0x8A, 0x3D}},
6670
}
6771

6872
// emberLight mirrors the WebUI light theme (parchment base, deeper amber
@@ -160,7 +164,9 @@ func paletteByName(name string) palette {
160164
// fine on a bare terminal, but it reads dimmed on the answer card's
161165
// surface. The document text instead takes the palette's full-brightness
162166
// body color; the light theme builds on glamour's light preset so code
163-
// blocks and highlights stay tuned for a light background.
167+
// blocks and highlights stay tuned for a light background. The document's
168+
// block prefix/suffix newlines are stripped: vertical framing belongs to
169+
// the card's symmetric padding alone.
164170
func answerGlamourStyle() ansi.StyleConfig {
165171
name := themeName()
166172
cfg := styles.DarkStyleConfig
@@ -170,6 +176,8 @@ func answerGlamourStyle() ansi.StyleConfig {
170176
// Assign a fresh pointer — the preset is a package-level shared value.
171177
c := string(paletteByName(name).text)
172178
cfg.Document.Color = &c
179+
cfg.Document.BlockPrefix = ""
180+
cfg.Document.BlockSuffix = ""
173181
return cfg
174182
}
175183

@@ -409,9 +417,12 @@ func themeFrom(p palette) theme {
409417
}
410418
}
411419

412-
// surfaceStyle builds the user-turn card style; empty means no surface.
420+
// surfaceStyle builds the answer card style; empty means no surface. The
421+
// padding is symmetric — one line above and below, one column each side —
422+
// because glamour's document newlines are stripped in answerGlamourStyle;
423+
// the frame belongs to the card alone.
413424
func surfaceStyle(c lipgloss.Color) lipgloss.Style {
414-
st := lipgloss.NewStyle().Padding(0, 1)
425+
st := lipgloss.NewStyle().Padding(1, 1)
415426
if c != "" {
416427
st = st.Background(c)
417428
}

0 commit comments

Comments
 (0)