termcast 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/dist/build.d.ts.map +1 -1
  2. package/dist/build.js +8 -7
  3. package/dist/build.js.map +1 -1
  4. package/dist/cli.js +0 -40
  5. package/dist/cli.js.map +1 -1
  6. package/dist/components/bar-graph.d.ts +23 -8
  7. package/dist/components/bar-graph.d.ts.map +1 -1
  8. package/dist/components/bar-graph.js +84 -40
  9. package/dist/components/bar-graph.js.map +1 -1
  10. package/dist/components/dotted-line-graph.d.ts +86 -0
  11. package/dist/components/dotted-line-graph.d.ts.map +1 -0
  12. package/dist/components/dotted-line-graph.js +260 -0
  13. package/dist/components/dotted-line-graph.js.map +1 -0
  14. package/dist/components/extension-preferences.d.ts.map +1 -1
  15. package/dist/components/extension-preferences.js +1 -10
  16. package/dist/components/extension-preferences.js.map +1 -1
  17. package/dist/components/graph.d.ts.map +1 -1
  18. package/dist/components/graph.js +7 -1
  19. package/dist/components/graph.js.map +1 -1
  20. package/dist/components/histogram.d.ts +42 -0
  21. package/dist/components/histogram.d.ts.map +1 -0
  22. package/dist/components/histogram.js +115 -0
  23. package/dist/components/histogram.js.map +1 -0
  24. package/dist/components/horizontal-bar-graph.d.ts +47 -0
  25. package/dist/components/horizontal-bar-graph.d.ts.map +1 -0
  26. package/dist/components/horizontal-bar-graph.js +137 -0
  27. package/dist/components/horizontal-bar-graph.js.map +1 -0
  28. package/dist/components/list.d.ts +2 -0
  29. package/dist/components/list.d.ts.map +1 -1
  30. package/dist/components/list.js +10 -10
  31. package/dist/components/list.js.map +1 -1
  32. package/dist/examples/bar-graph-weekly.js +2 -2
  33. package/dist/examples/bar-graph-weekly.js.map +1 -1
  34. package/dist/examples/charts-showcase-barchart.d.ts +2 -0
  35. package/dist/examples/charts-showcase-barchart.d.ts.map +1 -0
  36. package/dist/examples/charts-showcase-barchart.js +10 -0
  37. package/dist/examples/charts-showcase-barchart.js.map +1 -0
  38. package/dist/examples/charts-showcase-bargraph.d.ts +2 -0
  39. package/dist/examples/charts-showcase-bargraph.d.ts.map +1 -0
  40. package/dist/examples/charts-showcase-bargraph.js +60 -0
  41. package/dist/examples/charts-showcase-bargraph.js.map +1 -0
  42. package/dist/examples/charts-showcase-candle.d.ts +2 -0
  43. package/dist/examples/charts-showcase-candle.d.ts.map +1 -0
  44. package/dist/examples/charts-showcase-candle.js +30 -0
  45. package/dist/examples/charts-showcase-candle.js.map +1 -0
  46. package/dist/examples/charts-showcase-graph.d.ts +2 -0
  47. package/dist/examples/charts-showcase-graph.d.ts.map +1 -0
  48. package/dist/examples/charts-showcase-graph.js +33 -0
  49. package/dist/examples/charts-showcase-graph.js.map +1 -0
  50. package/dist/examples/charts-showcase-heatmap.d.ts +2 -0
  51. package/dist/examples/charts-showcase-heatmap.d.ts.map +1 -0
  52. package/dist/examples/charts-showcase-heatmap.js +36 -0
  53. package/dist/examples/charts-showcase-heatmap.js.map +1 -0
  54. package/dist/examples/charts-showcase-mixed.d.ts +2 -0
  55. package/dist/examples/charts-showcase-mixed.d.ts.map +1 -0
  56. package/dist/examples/charts-showcase-mixed.js +30 -0
  57. package/dist/examples/charts-showcase-mixed.js.map +1 -0
  58. package/dist/examples/charts-showcase-progress.d.ts +2 -0
  59. package/dist/examples/charts-showcase-progress.d.ts.map +1 -0
  60. package/dist/examples/charts-showcase-progress.js +10 -0
  61. package/dist/examples/charts-showcase-progress.js.map +1 -0
  62. package/dist/examples/graph-multi-series.js +1 -1
  63. package/dist/examples/graph-multi-series.js.map +1 -1
  64. package/dist/examples/horizontal-bar-graph-weekly.d.ts +2 -0
  65. package/dist/examples/horizontal-bar-graph-weekly.d.ts.map +1 -0
  66. package/dist/examples/horizontal-bar-graph-weekly.js +67 -0
  67. package/dist/examples/horizontal-bar-graph-weekly.js.map +1 -0
  68. package/dist/examples/simple-dotted-line-graph.d.ts +2 -0
  69. package/dist/examples/simple-dotted-line-graph.d.ts.map +1 -0
  70. package/dist/examples/simple-dotted-line-graph.js +39 -0
  71. package/dist/examples/simple-dotted-line-graph.js.map +1 -0
  72. package/dist/examples/simple-histogram.d.ts +2 -0
  73. package/dist/examples/simple-histogram.d.ts.map +1 -0
  74. package/dist/examples/simple-histogram.js +47 -0
  75. package/dist/examples/simple-histogram.js.map +1 -0
  76. package/dist/index.d.ts +6 -0
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +6 -0
  79. package/dist/index.js.map +1 -1
  80. package/dist/platform/node/sqlite.d.ts +6 -5
  81. package/dist/platform/node/sqlite.d.ts.map +1 -1
  82. package/dist/platform/node/sqlite.js +30 -14
  83. package/dist/platform/node/sqlite.js.map +1 -1
  84. package/dist/theme.d.ts.map +1 -1
  85. package/dist/theme.js +11 -9
  86. package/dist/theme.js.map +1 -1
  87. package/dist/utils/run-command.d.ts.map +1 -1
  88. package/dist/utils/run-command.js +8 -19
  89. package/dist/utils/run-command.js.map +1 -1
  90. package/dist/utils.d.ts +1 -19
  91. package/dist/utils.d.ts.map +1 -1
  92. package/dist/utils.js +1 -100
  93. package/dist/utils.js.map +1 -1
  94. package/package.json +6 -8
  95. package/src/build.tsx +11 -10
  96. package/src/cli.tsx +3 -40
  97. package/src/compile.vitest.tsx +3 -3
  98. package/src/components/bar-graph.tsx +217 -111
  99. package/src/components/dotted-line-graph.tsx +407 -0
  100. package/src/components/extension-preferences.tsx +2 -12
  101. package/src/components/graph.tsx +5 -1
  102. package/src/components/histogram.tsx +228 -0
  103. package/src/components/horizontal-bar-graph.tsx +279 -0
  104. package/src/components/list.tsx +20 -15
  105. package/src/examples/action-shortcut.vitest.tsx +17 -17
  106. package/src/examples/bar-graph-weekly.tsx +2 -2
  107. package/src/examples/bar-graph-weekly.vitest.tsx +63 -62
  108. package/src/examples/charts-showcase-bargraph.tsx +103 -0
  109. package/src/examples/detail-metadata-showcase.vitest.tsx +12 -12
  110. package/src/examples/form-basic.vitest.tsx +11 -11
  111. package/src/examples/form-dropdown.vitest.tsx +11 -11
  112. package/src/examples/form-scroll.vitest.tsx +1 -1
  113. package/src/examples/form-tagpicker.vitest.tsx +11 -11
  114. package/src/examples/github.vitest.tsx +22 -22
  115. package/src/examples/graph-bar-chart.vitest.tsx +8 -8
  116. package/src/examples/graph-multi-series.tsx +1 -1
  117. package/src/examples/graph-row.vitest.tsx +14 -14
  118. package/src/examples/graph-styles.vitest.tsx +77 -77
  119. package/src/examples/horizontal-bar-graph-weekly.tsx +138 -0
  120. package/src/examples/horizontal-bar-graph-weekly.vitest.tsx +164 -0
  121. package/src/examples/list-detail-metadata.vitest.tsx +4 -4
  122. package/src/examples/list-with-detail.vitest.tsx +46 -46
  123. package/src/examples/simple-candle-chart.vitest.tsx +8 -8
  124. package/src/examples/simple-dotted-line-graph.tsx +53 -0
  125. package/src/examples/simple-dotted-line-graph.vitest.tsx +62 -0
  126. package/src/examples/simple-grid.vitest.tsx +4 -4
  127. package/src/examples/simple-heatmap.vitest.tsx +9 -9
  128. package/src/examples/simple-histogram.tsx +90 -0
  129. package/src/examples/simple-navigation.vitest.tsx +4 -4
  130. package/src/examples/swift-extension.vitest.tsx +3 -3
  131. package/src/extensions/dev.vitest.tsx +8 -8
  132. package/src/index.tsx +21 -0
  133. package/src/platform/node/sqlite.ts +29 -13
  134. package/src/theme.tsx +11 -10
  135. package/src/utils/run-command.tsx +10 -19
  136. package/src/utils.tsx +0 -163
  137. package/src/examples/store.tsx +0 -4
  138. package/src/examples/store.vitest.tsx +0 -78
  139. package/src/extensions/home.tsx +0 -227
  140. package/src/extensions/store.tsx +0 -375
@@ -1,5 +1,5 @@
1
1
  // E2E tests for BarGraph vertical stacked bar chart.
2
- // Bar segments are filled with █ chars so they show in text snapshots.
2
+ // Bar segments use chars so they show in text snapshots without filling cells.
3
3
 
4
4
  import { test, expect, afterEach, beforeEach } from 'vitest'
5
5
  import { launchTerminal, Session } from 'tuistory/src'
@@ -22,7 +22,7 @@ afterEach(() => {
22
22
  test('bar graph renders bars, labels, and legend', async () => {
23
23
  const text = await session.text({
24
24
  waitFor: (text) => {
25
- return text.includes('Mon') && text.includes('Sat') && text.includes('Direct')
25
+ return text.includes('Mon') && text.includes('Direct') && text.includes('0.0│')
26
26
  },
27
27
  timeout: 10000,
28
28
  })
@@ -35,17 +35,17 @@ test('bar graph renders bars, labels, and legend', async () => {
35
35
 
36
36
  > Search...
37
37
 
38
- Weekly Traffic 3 channels across 6 d ███
39
- Revenue by Region EMEA / APAC / Amer ███ ███ ███ ███
40
- Server Load CPU / Memory / IO │ ███ ███ ███ ███
41
- Many Columns (20) Overflow test with███ ███ ███ ███ ███
42
- Many Series (8) Legend overflow test │ ███ ███ ███ ███ ███ ███
43
- Long Labels Labels wider than bar co███ ███ ███ ███ ███ ███
44
- Week 1 vs Week 2 Two graphs in a Row │ ███ ███ ███ ███ ███ ███
45
- ███ ███ ███ ███ ███ ███
46
- ███ ███ ███ ███ ███ ███
47
- Mon Tue Wed Thu Fri Sat
48
- ↵ open detail ↑↓ navigate ^k act │ ■ Direct ■ Organic ■ Referral
38
+ Weekl...affic3 channels...oss 6 days 110.0│ ▃▃▃
39
+ Revenu... Regio EMEA / A... Americas │▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
40
+ Server Load CPU / Memory / IO │ 82.5│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
41
+ Many ...s (20)Overflow ...th 20 bars │▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
42
+ Many Series (8) Legend overflow test │ 55.0│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
43
+ Lon...belsLabels wide... bar columns │▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
44
+ Week 1 vs Week 2 Two graphs in a Row │ 27.5│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
45
+ │▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
46
+ 0.0│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
47
+ Mon Tue Wed Thu Fri Sat
48
+ ↵ open detail ↑↓ navigate ^k act │ ■ Direct ■ Organic ■ Referral
49
49
 
50
50
 
51
51
 
@@ -62,20 +62,20 @@ test('bar graph renders bars, labels, and legend', async () => {
62
62
  `)
63
63
 
64
64
  expect(text).toContain('Mon')
65
- expect(text).toContain('Sat')
66
65
  expect(text).toContain('Direct')
67
- expect(text).toContain('')
66
+ expect(text).toContain('0.0│')
67
+ expect(text).toContain('▃')
68
68
  }, 30000)
69
69
 
70
70
  test('many columns (20) clips with overflow hidden', async () => {
71
- await session.text({ waitFor: (t) => t.includes('Many Columns'), timeout: 10000 })
71
+ await session.text({ waitFor: (t) => t.includes('(20)'), timeout: 10000 })
72
72
  // Navigate: Weekly Traffic, Revenue, Server Load, Many Columns = 3 downs
73
73
  session.sendKey('down')
74
74
  session.sendKey('down')
75
75
  session.sendKey('down')
76
76
 
77
77
  await session.text({
78
- waitFor: (t) => t.includes('›Many Columns'),
78
+ waitFor: (t) => t.includes('›Many ...s (20)'),
79
79
  timeout: 10000,
80
80
  })
81
81
  await session.waitIdle()
@@ -83,16 +83,16 @@ test('many columns (20) clips with overflow hidden', async () => {
83
83
 
84
84
  // Bar graph rendering has non-deterministic ANSI highlights, so use toContain checks
85
85
  // instead of inline snapshot for the bars area
86
- expect(text).toContain('›Many Columns')
86
+ expect(text).toContain('›Many ...s (20)')
87
87
  expect(text).toContain('BarGraph Showcase')
88
- expect(text).toContain('███')
88
+ expect(text).toContain('')
89
89
 
90
90
  // Some labels visible, overflow clips the rest
91
- expect(text).toContain('D1')
92
- expect(text).toContain('')
91
+ expect(text).toContain('D')
92
+ expect(text).toContain('')
93
93
  }, 30000)
94
94
 
95
- test('many series (8) legend clips on one line', async () => {
95
+ test('many series (8) bottom legend clips on one row', async () => {
96
96
  await session.text({ waitFor: (t) => t.includes('Many Series'), timeout: 10000 })
97
97
  // Navigate: Weekly, Revenue, Server, Many Columns, Many Series = 4 downs
98
98
  session.sendKey('down')
@@ -113,17 +113,17 @@ test('many series (8) legend clips on one line', async () => {
113
113
 
114
114
  > Search...
115
115
 
116
- Weekly Traffic 3 channels across 6 d███ ███ ███ ███ ███
117
- Revenue by Region EMEA / APAC / Amer ███ ███ ███ ███ ███ ███
118
- Server Load CPU / Memory / IO │ ███ ███ ███ ███ ███ ███
119
- Many Columns (20) Overflow test with███ ███ ███ ███ ███ ███
120
- ›Many Series (8) Legend overflow test │ ███ ███ ███ ███ ███ ███
121
- Long Labels Labels wider than bar co███ ███ ███ ███ ███ ███
122
- Week 1 vs Week 2 Two graphs in a Row │ ███ ███ ███ ███ ███ ███
123
- ███ ███ ███ ███ ███ ███
124
- ███ ███ ███ ███ ███ ███
125
- Mon Tue Wed Thu Fri Sat
126
- ↑↓ navigate ^k actions :vim │ ■ Series 1 ■ Series 2 ■ Series 3
116
+ Weekl...affic3 channels...oss 6 days328.0│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
117
+ Revenu... Regio EMEA / A... Americas │▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
118
+ Server Load CPU / Memory / IO │ 246.0│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
119
+ Many ...s (20)Overflow ...th 20 bars │▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
120
+ ›Many Series (8) Legend overflow test │ 164.0│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
121
+ Lon...belsLabels wide... bar columns │▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
122
+ Week 1 vs Week 2 Two graphs in a Row │ 82.0│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
123
+ │▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
124
+ 0.0│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
125
+ Mon Tue Wed Thu Fri Sat
126
+ ↑↓ navigate ^k actions :vim │ ■ Series 1 ■ Series 2 ■ Series 3
127
127
 
128
128
 
129
129
 
@@ -139,13 +139,14 @@ test('many series (8) legend clips on one line', async () => {
139
139
  "
140
140
  `)
141
141
 
142
- // First series visible in legend
142
+ // Bottom legend is a single clipped row by default.
143
143
  expect(text).toContain('Series 1')
144
- expect(text).toContain('')
144
+ expect(text).toContain('Series 3')
145
+ expect(text).toContain('▃')
145
146
  }, 30000)
146
147
 
147
148
  test('long labels truncated by overflow hidden', async () => {
148
- await session.text({ waitFor: (t) => t.includes('Long Labels'), timeout: 10000 })
149
+ await session.text({ waitFor: (t) => t.includes('Lon...bels'), timeout: 10000 })
149
150
  // Navigate: Weekly, Revenue, Server, Many Columns, Many Series, Long Labels = 5 downs
150
151
  session.sendKey('down')
151
152
  session.sendKey('down')
@@ -154,7 +155,7 @@ test('long labels truncated by overflow hidden', async () => {
154
155
  session.sendKey('down')
155
156
 
156
157
  const text = await session.text({
157
- waitFor: (t) => t.includes('›Long Labels'),
158
+ waitFor: (t) => t.includes('›Lon...bels'),
158
159
  timeout: 10000,
159
160
  })
160
161
 
@@ -166,17 +167,17 @@ test('long labels truncated by overflow hidden', async () => {
166
167
 
167
168
  > Search...
168
169
 
169
- Weekly Traffic 3 channels across 6 d ███
170
- Revenue by Region EMEA / APAC / Amer ███ ███ ███
171
- Server Load CPU / Memory / IO │ ███ ███ ███ ███
172
- Many Columns (20) Overflow test with███ ███ ███ ███
173
- Many Series (8) Legend overflow test │ ███ ███ ███ ███ ███
174
- Long Labels Labels wider than bar co███ ███ ███ ███ ███ ███
175
- Week 1 vs Week 2 Two graphs in a Row │ ███ ███ ███ ███ ███ ███
176
- ███ ███ ███ ███ ███ ███
177
- ███ ███ ███ ███ ███ ███
178
- Mon Tue Wed Thu Fri Sat
179
- ↑↓ navigate ^k actions :vim │ ■ Views ■ Clicks
170
+ Weekl...affic3 channels...oss 6 days 75.0│ ▃▃▃
171
+ Revenu... Regio EMEA / A... Americas │▃▃▃ ▃▃▃ ▃▃▃
172
+ Server Load CPU / Memory / IO │ 56.3│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
173
+ Many ...s (20)Overflow ...th 20 bars │▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
174
+ Many Series (8) Legend overflow test │ 37.5│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
175
+ Lon...belsLabels wide... bar columns │▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
176
+ Week 1 vs Week 2 Two graphs in a Row │ 18.8│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
177
+ │▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
178
+ 0.0│▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃ ▃▃▃
179
+ Monday Thursday
180
+ ↑↓ navigate ^k actions :vim │ ■ Views ■ Clicks
180
181
 
181
182
 
182
183
 
@@ -192,8 +193,8 @@ test('long labels truncated by overflow hidden', async () => {
192
193
  "
193
194
  `)
194
195
 
195
- expect(text).toContain('Long Labels')
196
- expect(text).toContain('')
196
+ expect(text).toContain('›Lon...bels')
197
+ expect(text).toContain('')
197
198
  }, 30000)
198
199
 
199
200
  test('side-by-side bar graphs in a Row', async () => {
@@ -219,17 +220,17 @@ test('side-by-side bar graphs in a Row', async () => {
219
220
 
220
221
  > Search...
221
222
 
222
- Weekly Traffic 3 channels across 6 d
223
- Revenue by Region EMEA / APAC / Amer ███ ███ █ ███
224
- Server Load CPU / Memory / IO │ ███ ███ █ ███ ███
225
- Many Columns (20) Overflow test with███ ███ ███ █ ███ ███ ███ ███
226
- Many Series (8) Legend overflow test │ ███ ███ ███ ███ █ ███ ███ ███ ███
227
- Long Labels Labels wider than bar co███ ███ ███ ███ █ ███ ███ ███ ███
228
- ›Week 1 vs Week 2 Two graphs in a Row │ ███ ███ ███ ███ █ ███ ███ ███ ███
229
- ███ ███ ███ ███ █ ███ ███ ███ ███
230
- ███ ███ ███ ███ █ ███ ███ ███ ███
231
- Mon Tue Wed Thu F Mon Tue Wed Thu
232
- ↵ open detail ↑↓ navigate ^k act │ ■ Direct Organi ■ Direct Organ
223
+ Weekl...affic3 channels...oss 6 days 110.0│ 130.0│
224
+ Revenu... Regio EMEA / A... Americas │▃▃▃ ▃▃▃ │▃▃▃
225
+ Server Load CPU / Memory / IO │ 82.5│▃▃▃ ▃▃▃ 97.5│▃▃▃ ▃▃▃
226
+ Many ...s (20)Overflow ...th 20 bars │▃▃▃ ▃▃▃ ▃▃▃ │▃▃▃ ▃▃▃ ▃▃
227
+ Many Series (8) Legend overflow test │ 55.0│▃▃▃ ▃▃▃ ▃▃▃ 65.0│▃▃▃ ▃▃▃ ▃▃
228
+ Lon...belsLabels wide... bar columns │▃▃▃ ▃▃▃ ▃▃▃ │▃▃▃ ▃▃▃ ▃▃
229
+ ›Week 1 vs Week 2 Two graphs in a Row │ 27.5│▃▃▃ ▃▃▃ ▃▃▃ 32.5│▃▃▃ ▃▃▃ ▃▃
230
+ │▃▃▃ ▃▃▃ ▃▃▃ │▃▃▃ ▃▃▃ ▃▃
231
+ 0.0│▃▃▃ ▃▃▃ ▃▃▃ 0.0│▃▃▃ ▃▃▃ ▃▃
232
+ Mon Tue Wed Mon Tue We
233
+ ↵ open detail ↑↓ navigate ^k act │ ■ Direct Organ ■ Direct Orga
233
234
 
234
235
 
235
236
 
@@ -245,5 +246,5 @@ test('side-by-side bar graphs in a Row', async () => {
245
246
  "
246
247
  `)
247
248
 
248
- expect(text).toContain('Mon')
249
+ expect(text).toContain('Direct')
249
250
  }, 30000)
@@ -0,0 +1,103 @@
1
+ // Showcase: BarGraph vertical stacked bar chart inside a Detail view.
2
+ // Recreates a monthly model spend chart with stacked per-day usage.
3
+
4
+ import { BarGraph, Detail } from 'termcast'
5
+ import { renderWithProviders } from '../utils'
6
+
7
+ const labels = Array.from({ length: 30 }, (_, i) => {
8
+ const day = i + 1
9
+ if (day % 2 === 0) {
10
+ return ''
11
+ }
12
+ return String(day).padStart(2, '0')
13
+ })
14
+
15
+ const emptyMonth = Array.from({ length: 30 }, () => 0)
16
+
17
+ function withSpend(points: Record<number, number>): number[] {
18
+ return emptyMonth.map((_, i) => points[i + 1] || 0)
19
+ }
20
+
21
+ const modelSpend = [
22
+ {
23
+ title: 'deepseek-v4-flash (go)',
24
+ color: '#b5bb69',
25
+ data: withSpend({ 21: 0.6, 25: 1.05, 26: 1.3, 27: 1.9, 28: 0.55, 29: 0.8, 30: 1.1 }),
26
+ },
27
+ {
28
+ title: 'deepseek-v4-pro (go)',
29
+ color: '#8f59b5',
30
+ data: withSpend({ 25: 0.12 }),
31
+ },
32
+ {
33
+ title: 'kimi-k2.6 (go)',
34
+ color: '#64b86a',
35
+ data: withSpend({ 22: 3.25, 23: 1.65, 24: 2.2, 25: 2.05 }),
36
+ },
37
+ {
38
+ title: 'mimo-v2-omni (go)',
39
+ color: '#aaa25f',
40
+ data: withSpend({ 25: 0.12, 26: 0.15 }),
41
+ },
42
+ {
43
+ title: 'mimo-v2-pro (go)',
44
+ color: '#5ba895',
45
+ data: withSpend({ 16: 1.5, 17: 0.75, 21: 2.5 }),
46
+ },
47
+ {
48
+ title: 'minimax-m2.7 (go)',
49
+ color: '#6c6cb8',
50
+ data: withSpend({ 20: 5 }),
51
+ },
52
+ {
53
+ title: 'qwen3.6-plus (go)',
54
+ color: '#b07a5c',
55
+ data: withSpend({ 17: 2.65, 18: 6.55, 19: 3.15 }),
56
+ },
57
+ ]
58
+
59
+ function ChartsShowcaseBarGraph() {
60
+ return (
61
+ <Detail
62
+ navigationTitle="Model Spend"
63
+ markdown="# Model Spend\n\nApril 2026 usage by model and API key."
64
+ metadata={
65
+ <Detail.Metadata>
66
+ <box flexDirection="row" gap={2} paddingBottom={1}>
67
+ <box border borderColor="#2a2a2a" paddingLeft={2} paddingRight={2} height={3} justifyContent="center">
68
+ <text>‹ April 2026 ›</text>
69
+ </box>
70
+ <box border borderColor="#2d5fa8" paddingLeft={2} paddingRight={2} height={3} justifyContent="center">
71
+ <text>All Models⌄</text>
72
+ </box>
73
+ <box border borderColor="#2a2a2a" paddingLeft={2} paddingRight={2} height={3} justifyContent="center">
74
+ <text>All Keys⌄</text>
75
+ </box>
76
+ </box>
77
+ <box border borderColor="#2a2a2a" paddingTop={2} paddingLeft={2} paddingRight={2} paddingBottom={1}>
78
+ <BarGraph
79
+ height={24}
80
+ labels={labels}
81
+ barGap={1}
82
+ yFormat={(value) => `$${value.toFixed(0)}`}
83
+ showLegend
84
+ >
85
+ {modelSpend.map((series) => {
86
+ return (
87
+ <BarGraph.Series
88
+ key={series.title}
89
+ color={series.color}
90
+ data={series.data}
91
+ title={series.title}
92
+ />
93
+ )
94
+ })}
95
+ </BarGraph>
96
+ </box>
97
+ </Detail.Metadata>
98
+ }
99
+ />
100
+ )
101
+ }
102
+
103
+ void renderWithProviders(<ChartsShowcaseBarGraph />)
@@ -50,7 +50,8 @@ test('detail metadata showcase renders markdown and metadata together', async ()
50
50
 
51
51
 
52
52
  This detail view demonstrates markdown content alongside metadata.
53
- ---
53
+ ─────────────────────────────────────────────────────────────────────────────────────────────
54
+
54
55
  Summary
55
56
 
56
57
 
@@ -72,7 +73,8 @@ test('detail metadata showcase renders markdown and metadata together', async ()
72
73
  - Finishing the remaining user migrations
73
74
  - Implementing the new dashboard
74
75
  - Writing integration tests
75
- ---
76
+ ─────────────────────────────────────────────────────────────────────────────────────────────
77
+
76
78
  Last updated: January 20, 2024
77
79
 
78
80
  Basic Information
@@ -158,8 +160,6 @@ test('detail metadata showcase renders markdown and metadata together', async ()
158
160
 
159
161
 
160
162
 
161
-
162
-
163
163
 
164
164
  "
165
165
  `)
@@ -216,7 +216,8 @@ test('detail metadata renders long values in column layout', async () => {
216
216
 
217
217
 
218
218
  This detail view demonstrates markdown content alongside metadata.
219
- ---
219
+ ─────────────────────────────────────────────────────────────────────────────────────────────
220
+
220
221
  Summary
221
222
 
222
223
 
@@ -238,7 +239,8 @@ test('detail metadata renders long values in column layout', async () => {
238
239
  - Finishing the remaining user migrations
239
240
  - Implementing the new dashboard
240
241
  - Writing integration tests
241
- ---
242
+ ─────────────────────────────────────────────────────────────────────────────────────────────
243
+
242
244
  Last updated: January 20, 2024
243
245
 
244
246
  Basic Information
@@ -324,8 +326,6 @@ test('detail metadata renders long values in column layout', async () => {
324
326
 
325
327
 
326
328
 
327
-
328
-
329
329
 
330
330
  "
331
331
  `)
@@ -397,7 +397,8 @@ test('detail metadata renders tag lists with multiple items', async () => {
397
397
 
398
398
 
399
399
  This detail view demonstrates markdown content alongside metadata.
400
- ---
400
+ ─────────────────────────────────────────────────────────────────────────────────────────────
401
+
401
402
  Summary
402
403
 
403
404
 
@@ -419,7 +420,8 @@ test('detail metadata renders tag lists with multiple items', async () => {
419
420
  - Finishing the remaining user migrations
420
421
  - Implementing the new dashboard
421
422
  - Writing integration tests
422
- ---
423
+ ─────────────────────────────────────────────────────────────────────────────────────────────
424
+
423
425
  Last updated: January 20, 2024
424
426
 
425
427
  Basic Information
@@ -505,8 +507,6 @@ test('detail metadata renders tag lists with multiple items', async () => {
505
507
 
506
508
 
507
509
 
508
-
509
-
510
510
 
511
511
  "
512
512
  `)
@@ -221,7 +221,7 @@ test('form date picker selection with space and enter', async () => {
221
221
  ◇ Date of Birth
222
222
 
223
223
  │ ← 2026 →
224
- │ ← April
224
+ │ ← May
225
225
 
226
226
 
227
227
  ctrl ↵ submit tab navigate ^k actions
@@ -279,7 +279,7 @@ test('form date picker selection with space and enter', async () => {
279
279
  ◇ Date of Birth
280
280
 
281
281
  │ ← 2026 →
282
- │ ← April
282
+ │ ← May
283
283
 
284
284
 
285
285
  ctrl ↵ submit tab navigate ^k actions
@@ -338,7 +338,7 @@ test('form date picker selection with space and enter', async () => {
338
338
  ◇ Date of Birth
339
339
 
340
340
  │ ← 2026 →
341
- │ ← April
341
+ │ ← May
342
342
 
343
343
 
344
344
  ctrl ↵ submit tab navigate ^k actions
@@ -413,7 +413,7 @@ test('form dropdown navigation', async () => {
413
413
  ◇ Date of Birth
414
414
 
415
415
  │ ← 2026 →
416
- │ ← April
416
+ │ ← May
417
417
 
418
418
 
419
419
  ctrl ↵ submit tab navigate ^k actions
@@ -471,7 +471,7 @@ test('form dropdown navigation', async () => {
471
471
  ◇ Date of Birth
472
472
 
473
473
  │ ← 2026 →
474
- │ ← April
474
+ │ ← May
475
475
 
476
476
 
477
477
  ctrl ↵ submit tab navigate ^k actions
@@ -531,7 +531,7 @@ test('form dropdown navigation', async () => {
531
531
  ◇ Date of Birth
532
532
 
533
533
  │ ← 2026 →
534
- │ ← April
534
+ │ ← May
535
535
 
536
536
 
537
537
  ctrl ↵ submit tab navigate ^k actions
@@ -589,7 +589,7 @@ test('form dropdown navigation', async () => {
589
589
  ◇ Date of Birth
590
590
 
591
591
  │ ← 2026 →
592
- │ ← April
592
+ │ ← May
593
593
 
594
594
 
595
595
  ctrl ↵ submit tab navigate ^k actions
@@ -674,10 +674,9 @@ test('form scrolls with mouse wheel', async () => {
674
674
  "
675
675
 
676
676
 
677
-
678
677
 
679
- This demonstrates all available form input types. Use arrow ▀
680
- │ keys or Tab to navigate between fields.
678
+
679
+ │ keys or Tab to navigate between fields.
681
680
 
682
681
  ◇ Username
683
682
  │ Enter your username
@@ -687,6 +686,7 @@ test('form scrolls with mouse wheel', async () => {
687
686
  ◇ Password
688
687
  │ Enter secure password
689
688
 
689
+ │ Must be at least 8 characters
690
690
 
691
691
 
692
692
  ctrl ↵ submit tab navigate ^k actions
@@ -763,7 +763,7 @@ test('arrow down from checkbox to dropdown lands on first item', async () => {
763
763
  ◇ Date of Birth
764
764
 
765
765
  │ ← 2026 →
766
- │ ← April
766
+ │ ← May
767
767
 
768
768
 
769
769
  ctrl ↵ submit tab navigate ^k actions
@@ -102,7 +102,7 @@ test('form dropdown shows inline options', async () => {
102
102
 
103
103
 
104
104
 
105
- Dropdown Component Demo █
105
+ ▪︎ Dropdown Component Demo █
106
106
  │ Test dropdown with sections, multiple selection, and more █
107
107
  │ features █
108
108
  │ █
@@ -162,7 +162,7 @@ test('form dropdown shows inline options', async () => {
162
162
 
163
163
 
164
164
 
165
- Dropdown Component Demo █
165
+ ▪︎ Dropdown Component Demo █
166
166
  │ Test dropdown with sections, multiple selection, and more █
167
167
  │ features █
168
168
  │ █
@@ -219,7 +219,7 @@ test('form dropdown shows inline options', async () => {
219
219
 
220
220
 
221
221
 
222
- Dropdown Component Demo █
222
+ ▪︎ Dropdown Component Demo █
223
223
  │ Test dropdown with sections, multiple selection, and more █
224
224
  │ features █
225
225
  │ █
@@ -344,7 +344,7 @@ test('form dropdown keyboard navigation', async () => {
344
344
 
345
345
 
346
346
 
347
- Dropdown Component Demo █
347
+ ▪︎ Dropdown Component Demo █
348
348
  │ Test dropdown with sections, multiple selection, and more █
349
349
  │ features █
350
350
  │ █
@@ -401,7 +401,7 @@ test('form dropdown keyboard navigation', async () => {
401
401
 
402
402
 
403
403
 
404
- Dropdown Component Demo █
404
+ ▪︎ Dropdown Component Demo █
405
405
  │ Test dropdown with sections, multiple selection, and more █
406
406
  │ features █
407
407
  │ █
@@ -458,7 +458,7 @@ test('form dropdown keyboard navigation', async () => {
458
458
 
459
459
 
460
460
 
461
- Dropdown Component Demo █
461
+ ▪︎ Dropdown Component Demo █
462
462
  │ Test dropdown with sections, multiple selection, and more █
463
463
  │ features █
464
464
  │ █
@@ -515,7 +515,7 @@ test('form dropdown keyboard navigation', async () => {
515
515
 
516
516
 
517
517
 
518
- Dropdown Component Demo █
518
+ ▪︎ Dropdown Component Demo █
519
519
  │ Test dropdown with sections, multiple selection, and more █
520
520
  │ features █
521
521
  │ █
@@ -580,7 +580,7 @@ test('form dropdown with default value', async () => {
580
580
 
581
581
 
582
582
 
583
- Dropdown Component Demo █
583
+ ▪︎ Dropdown Component Demo █
584
584
  │ Test dropdown with sections, multiple selection, and more █
585
585
  │ features █
586
586
  │ █
@@ -637,7 +637,7 @@ test('form dropdown with default value', async () => {
637
637
 
638
638
 
639
639
 
640
- Dropdown Component Demo █
640
+ ▪︎ Dropdown Component Demo █
641
641
  │ Test dropdown with sections, multiple selection, and more █
642
642
  │ features █
643
643
  │ █
@@ -708,7 +708,7 @@ test('selecting second-to-last visible item should not scroll', async () => {
708
708
 
709
709
 
710
710
 
711
- Dropdown Component Demo █
711
+ ▪︎ Dropdown Component Demo █
712
712
  │ Test dropdown with sections, multiple selection, and more █
713
713
  │ features █
714
714
  │ █
@@ -765,7 +765,7 @@ test('selecting second-to-last visible item should not scroll', async () => {
765
765
 
766
766
 
767
767
 
768
- Dropdown Component Demo █
768
+ ▪︎ Dropdown Component Demo █
769
769
  │ Test dropdown with sections, multiple selection, and more █
770
770
  │ features █
771
771
  │ █
@@ -53,7 +53,7 @@ test(
53
53
 
54
54
 
55
55
 
56
- Form Scroll Test ▀
56
+ ▪︎ Form Scroll Test ▀
57
57
  │ Test scrolling behavior when navigating with Tab
58
58
 
59
59
  ◆ Field 1