Skip to content

Commit b1ef4af

Browse files
committed
fix(tui): paint ! caveat lines amber instead of bold red
The "! " notes -- the unpriced/$-estimate hint that trails nearly every overview on subscription sources, the unknown-model note, the $0.00 explainer -- all shouted in bold red, the color of errors. They now use the amber warn tier (matching the toast palette); red is reserved for the error toast and the B-scale token heat cue. The five duplicated prefix-styling blocks collapse into one line_attr helper, which also gives every pane the dim "· " caption style.
1 parent ca21764 commit b1ef4af

1 file changed

Lines changed: 22 additions & 28 deletions

File tree

src/opentab/tui/renderer.py

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,18 @@ def unpriced_hint(self) -> str:
759759
return "! estimates — subscription tokens at API list prices"
760760
return "! $0.00 = subscription tokens — press $ to estimate"
761761

762+
def line_attr(self, line: str) -> int:
763+
# Shared prefix styling for the text panes: "# " titles (accent), "! "
764+
# caveats (amber -- attention without alarm; red is for errors and the
765+
# error toast only), "· " explainer captions (dim).
766+
if line.startswith("# "):
767+
return curses.color_pair(4) | curses.A_BOLD
768+
if line.startswith("! "):
769+
return curses.color_pair(2)
770+
if line.startswith("· "):
771+
return curses.color_pair(1)
772+
return curses.A_NORMAL
773+
762774
def money_attr(self, cost_text: str) -> int:
763775
# "$0.00" means zero or unpriced (tokens with no local price); muted grey so
764776
# it recedes behind real spend. "<$0.01" is a real cost and stays green.
@@ -1110,12 +1122,9 @@ def draw_project_detail(
11101122
visible = h - 4
11111123
self.app.scroll = max(0, min(self.app.scroll, max(0, len(lines) - visible)))
11121124
for offset, line in enumerate(lines[self.scroll : self.scroll + visible]):
1113-
attr = (
1114-
curses.color_pair(4) | curses.A_BOLD if line.startswith("# ") else curses.A_NORMAL
1125+
self.write_rich(
1126+
stdscr, y + 3 + offset, x + 2, shorten(line, w - 4), self.line_attr(line)
11151127
)
1116-
if line.startswith("! "):
1117-
attr = curses.color_pair(5) | curses.A_BOLD
1118-
self.write_rich(stdscr, y + 3 + offset, x + 2, shorten(line, w - 4), attr)
11191128

11201129
def draw_year_detail(
11211130
self, stdscr: curses.window, y: int, x: int, h: int, w: int, active: bool = True
@@ -1156,12 +1165,9 @@ def draw_year_detail(
11561165
visible = h - 4
11571166
self.app.scroll = max(0, min(self.app.scroll, max(0, len(lines) - visible)))
11581167
for offset, line in enumerate(lines[self.scroll : self.scroll + visible]):
1159-
attr = (
1160-
curses.color_pair(4) | curses.A_BOLD if line.startswith("# ") else curses.A_NORMAL
1168+
self.write_rich(
1169+
stdscr, y + 3 + offset, x + 2, shorten(line, w - 4), self.line_attr(line)
11611170
)
1162-
if line.startswith("! "):
1163-
attr = curses.color_pair(5) | curses.A_BOLD
1164-
self.write_rich(stdscr, y + 3 + offset, x + 2, shorten(line, w - 4), attr)
11651171

11661172
def draw_month_detail(
11671173
self, stdscr: curses.window, y: int, x: int, h: int, w: int, active: bool = True
@@ -1196,12 +1202,9 @@ def draw_month_detail(
11961202
visible = h - 4
11971203
self.app.scroll = max(0, min(self.app.scroll, max(0, len(lines) - visible)))
11981204
for offset, line in enumerate(lines[self.scroll : self.scroll + visible]):
1199-
attr = (
1200-
curses.color_pair(4) | curses.A_BOLD if line.startswith("# ") else curses.A_NORMAL
1205+
self.write_rich(
1206+
stdscr, y + 3 + offset, x + 2, shorten(line, w - 4), self.line_attr(line)
12011207
)
1202-
if line.startswith("! "):
1203-
attr = curses.color_pair(5) | curses.A_BOLD
1204-
self.write_rich(stdscr, y + 3 + offset, x + 2, shorten(line, w - 4), attr)
12051208

12061209
def draw_day_list(
12071210
self, stdscr: curses.window, y: int, x: int, h: int, w: int, active: bool = True
@@ -1290,12 +1293,9 @@ def draw_day_detail(
12901293
visible = h - 4
12911294
self.app.scroll = max(0, min(self.app.scroll, max(0, len(lines) - visible)))
12921295
for offset, line in enumerate(lines[self.scroll : self.scroll + visible]):
1293-
attr = (
1294-
curses.color_pair(4) | curses.A_BOLD if line.startswith("# ") else curses.A_NORMAL
1296+
self.write_rich(
1297+
stdscr, y + 3 + offset, x + 2, shorten(line, w - 4), self.line_attr(line)
12951298
)
1296-
if line.startswith("! "):
1297-
attr = curses.color_pair(5) | curses.A_BOLD
1298-
self.write_rich(stdscr, y + 3 + offset, x + 2, shorten(line, w - 4), attr)
12991299

13001300
def draw_workflow_list(self, stdscr: curses.window, y: int, x: int, h: int, w: int) -> None:
13011301
day = self.active_day
@@ -1361,14 +1361,8 @@ def draw_detail(self, stdscr: curses.window, y: int, x: int, h: int, w: int) ->
13611361
self.app.scroll = max(0, min(self.app.scroll, max(0, len(lines) - visible)))
13621362
drawn = lines[self.scroll : self.scroll + visible]
13631363
for offset, line in enumerate(drawn):
1364-
attr = (
1365-
curses.color_pair(4) | curses.A_BOLD if line.startswith("# ") else curses.A_NORMAL
1366-
)
1367-
if line.startswith("! "): # a real caveat (pricing, missing data): loud
1368-
attr = curses.color_pair(5) | curses.A_BOLD
1369-
elif line.startswith("· "): # an explainer caption: quiet, never red
1370-
attr = curses.color_pair(1)
1371-
elif line.startswith(("▸ ", "▾ ")): # Turns tab: a user-prompt group header
1364+
attr = self.line_attr(line)
1365+
if line.startswith(("▸ ", "▾ ")): # Turns tab: a user-prompt group header
13721366
attr = curses.color_pair(6) | curses.A_BOLD
13731367
elif line.startswith(" │"): # Turns tab: an unfolded prompt's full text
13741368
attr = curses.color_pair(1)

0 commit comments

Comments
 (0)