termcast 1.3.48 → 1.3.50
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.
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +12 -0
- package/dist/build.js.map +1 -1
- package/dist/cli.js +5 -40
- package/dist/cli.js.map +1 -1
- package/dist/colors.d.ts +7 -7
- package/dist/colors.js +7 -7
- package/dist/compile.d.ts +6 -1
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +45 -26
- package/dist/compile.js.map +1 -1
- package/dist/components/actions.js +1 -1
- package/dist/components/actions.js.map +1 -1
- package/dist/components/bar-chart.d.ts +38 -0
- package/dist/components/bar-chart.d.ts.map +1 -0
- package/dist/components/bar-chart.js +158 -0
- package/dist/components/bar-chart.js.map +1 -0
- package/dist/components/bar-graph.d.ts +41 -0
- package/dist/components/bar-graph.d.ts.map +1 -0
- package/dist/components/bar-graph.js +95 -0
- package/dist/components/bar-graph.js.map +1 -0
- package/dist/components/detail.d.ts.map +1 -1
- package/dist/components/detail.js +5 -7
- package/dist/components/detail.js.map +1 -1
- package/dist/components/footer.d.ts.map +1 -1
- package/dist/components/footer.js +8 -9
- package/dist/components/footer.js.map +1 -1
- package/dist/components/form/date-picker.d.ts.map +1 -1
- package/dist/components/form/date-picker.js +7 -1
- package/dist/components/form/date-picker.js.map +1 -1
- package/dist/components/form/dropdown.d.ts.map +1 -1
- package/dist/components/form/dropdown.js +10 -2
- package/dist/components/form/dropdown.js.map +1 -1
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +4 -5
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/form/use-form-navigation.d.ts.map +1 -1
- package/dist/components/form/use-form-navigation.js +6 -0
- package/dist/components/form/use-form-navigation.js.map +1 -1
- package/dist/components/graph.d.ts +111 -0
- package/dist/components/graph.d.ts.map +1 -0
- package/dist/components/graph.js +392 -0
- package/dist/components/graph.js.map +1 -0
- package/dist/components/icon.js +5 -5
- package/dist/components/icon.js.map +1 -1
- package/dist/components/list.d.ts +53 -5
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +125 -71
- package/dist/components/list.js.map +1 -1
- package/dist/components/loading-bar.js +3 -3
- package/dist/components/loading-bar.js.map +1 -1
- package/dist/components/loading-text.d.ts +1 -1
- package/dist/components/loading-text.d.ts.map +1 -1
- package/dist/components/loading-text.js +3 -1
- package/dist/components/loading-text.js.map +1 -1
- package/dist/components/metadata.js +2 -2
- package/dist/components/metadata.js.map +1 -1
- package/dist/components/row.d.ts +10 -0
- package/dist/components/row.d.ts.map +1 -0
- package/dist/components/row.js +12 -0
- package/dist/components/row.js.map +1 -0
- package/dist/components/table.d.ts +57 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/table.js +365 -0
- package/dist/components/table.js.map +1 -0
- package/dist/descendants.js +13 -13
- package/dist/descendants.js.map +1 -1
- package/dist/examples/bar-graph-weekly.d.ts +2 -0
- package/dist/examples/bar-graph-weekly.d.ts.map +1 -0
- package/dist/examples/bar-graph-weekly.js +95 -0
- package/dist/examples/bar-graph-weekly.js.map +1 -0
- package/dist/examples/components-weird-places.d.ts +2 -0
- package/dist/examples/components-weird-places.d.ts.map +1 -0
- package/dist/examples/components-weird-places.js +46 -0
- package/dist/examples/components-weird-places.js.map +1 -0
- package/dist/examples/graph-bar-chart.d.ts +2 -0
- package/dist/examples/graph-bar-chart.d.ts.map +1 -0
- package/dist/examples/graph-bar-chart.js +270 -0
- package/dist/examples/graph-bar-chart.js.map +1 -0
- package/dist/examples/graph-multi-series.d.ts +2 -0
- package/dist/examples/graph-multi-series.d.ts.map +1 -0
- package/dist/examples/graph-multi-series.js +23 -0
- package/dist/examples/graph-multi-series.js.map +1 -0
- package/dist/examples/graph-polymarket.d.ts +2 -0
- package/dist/examples/graph-polymarket.d.ts.map +1 -0
- package/dist/examples/graph-polymarket.js +109 -0
- package/dist/examples/graph-polymarket.js.map +1 -0
- package/dist/examples/graph-row.d.ts +2 -0
- package/dist/examples/graph-row.d.ts.map +1 -0
- package/dist/examples/graph-row.js +226 -0
- package/dist/examples/graph-row.js.map +1 -0
- package/dist/examples/graph-styles.d.ts +2 -0
- package/dist/examples/graph-styles.d.ts.map +1 -0
- package/dist/examples/graph-styles.js +316 -0
- package/dist/examples/graph-styles.js.map +1 -0
- package/dist/examples/list-accessory-table.d.ts +2 -0
- package/dist/examples/list-accessory-table.d.ts.map +1 -0
- package/dist/examples/list-accessory-table.js +46 -0
- package/dist/examples/list-accessory-table.js.map +1 -0
- package/dist/examples/list-item-accessories.d.ts +2 -0
- package/dist/examples/list-item-accessories.d.ts.map +1 -0
- package/dist/examples/list-item-accessories.js +27 -0
- package/dist/examples/list-item-accessories.js.map +1 -0
- package/dist/examples/list-no-actions.d.ts +2 -0
- package/dist/examples/list-no-actions.d.ts.map +1 -0
- package/dist/examples/list-no-actions.js +7 -0
- package/dist/examples/list-no-actions.js.map +1 -0
- package/dist/examples/simple-detail-table.d.ts +2 -0
- package/dist/examples/simple-detail-table.d.ts.map +1 -0
- package/dist/examples/simple-detail-table.js +45 -0
- package/dist/examples/simple-detail-table.js.map +1 -0
- package/dist/examples/simple-graph.d.ts +2 -0
- package/dist/examples/simple-graph.d.ts.map +1 -0
- package/dist/examples/simple-graph.js +32 -0
- package/dist/examples/simple-graph.js.map +1 -0
- package/dist/examples/simple-table-wrap.d.ts +2 -0
- package/dist/examples/simple-table-wrap.d.ts.map +1 -0
- package/dist/examples/simple-table-wrap.js +37 -0
- package/dist/examples/simple-table-wrap.js.map +1 -0
- package/dist/examples/table-edge-cases.d.ts +2 -0
- package/dist/examples/table-edge-cases.d.ts.map +1 -0
- package/dist/examples/table-edge-cases.js +70 -0
- package/dist/examples/table-edge-cases.js.map +1 -0
- package/dist/examples/table-flex-grow.d.ts +2 -0
- package/dist/examples/table-flex-grow.d.ts.map +1 -0
- package/dist/examples/table-flex-grow.js +18 -0
- package/dist/examples/table-flex-grow.js.map +1 -0
- package/dist/extensions/dev.d.ts.map +1 -1
- package/dist/extensions/dev.js +5 -1
- package/dist/extensions/dev.js.map +1 -1
- package/dist/globals.d.ts +1 -0
- package/dist/globals.d.ts.map +1 -1
- package/dist/globals.js +2 -0
- package/dist/globals.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/date-picker-widget.d.ts.map +1 -1
- package/dist/internal/date-picker-widget.js +4 -0
- package/dist/internal/date-picker-widget.js.map +1 -1
- package/dist/internal/providers.d.ts.map +1 -1
- package/dist/internal/providers.js +1 -3
- package/dist/internal/providers.js.map +1 -1
- package/dist/markdown-utils.d.ts +22 -1
- package/dist/markdown-utils.d.ts.map +1 -1
- package/dist/markdown-utils.js +66 -1
- package/dist/markdown-utils.js.map +1 -1
- package/dist/opentui.d.ts +4 -0
- package/dist/opentui.d.ts.map +1 -0
- package/dist/opentui.js +3 -0
- package/dist/opentui.js.map +1 -0
- package/dist/release.d.ts +2 -1
- package/dist/release.d.ts.map +1 -1
- package/dist/release.js +2 -1
- package/dist/release.js.map +1 -1
- package/dist/state.d.ts +1 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +1 -1
- package/dist/state.js.map +1 -1
- package/dist/theme.d.ts +1 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +13 -0
- package/dist/theme.js.map +1 -1
- package/dist/themes/nerv.json +227 -0
- package/dist/themes/termcast.json +72 -71
- package/dist/themes.d.ts +2 -1
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js +7 -5
- package/dist/themes.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +3 -0
- package/dist/utils.js.map +1 -1
- package/package.json +13 -5
- package/src/build.tsx +13 -0
- package/src/cli.tsx +5 -49
- package/src/colors.tsx +7 -7
- package/src/compile.tsx +52 -29
- package/src/components/actions.tsx +1 -1
- package/src/components/bar-chart.tsx +271 -0
- package/src/components/bar-graph.tsx +214 -0
- package/src/components/detail.tsx +7 -8
- package/src/components/footer.tsx +14 -15
- package/src/components/form/date-picker.tsx +9 -0
- package/src/components/form/dropdown.tsx +13 -3
- package/src/components/form/index.tsx +4 -6
- package/src/components/form/use-form-navigation.tsx +6 -0
- package/src/components/graph.tsx +506 -0
- package/src/components/icon.tsx +5 -5
- package/src/components/list.tsx +210 -102
- package/src/components/loading-bar.tsx +3 -3
- package/src/components/loading-text.tsx +4 -2
- package/src/components/metadata.tsx +2 -2
- package/src/components/row.tsx +31 -0
- package/src/components/table.tsx +511 -0
- package/src/descendants.tsx +13 -13
- package/src/examples/action-shortcut.vitest.tsx +1 -1
- package/src/examples/actions-context.vitest.tsx +1 -1
- package/src/examples/bar-graph-weekly.tsx +264 -0
- package/src/examples/bar-graph-weekly.vitest.tsx +275 -0
- package/src/examples/detail-metadata-showcase.vitest.tsx +8 -8
- package/src/examples/form-basic.vitest.tsx +239 -0
- package/src/examples/form-dropdown.vitest.tsx +29 -29
- package/src/examples/form-tagpicker.vitest.tsx +27 -27
- package/src/examples/github.vitest.tsx +4 -4
- package/src/examples/graph-bar-chart.tsx +408 -0
- package/src/examples/graph-bar-chart.vitest.tsx +283 -0
- package/src/examples/graph-multi-series.tsx +36 -0
- package/src/examples/graph-multi-series.vitest.tsx +89 -0
- package/src/examples/graph-polymarket.tsx +182 -0
- package/src/examples/graph-polymarket.vitest.tsx +130 -0
- package/src/examples/graph-row.tsx +347 -0
- package/src/examples/graph-row.vitest.tsx +295 -0
- package/src/examples/graph-styles.tsx +457 -0
- package/src/examples/graph-styles.vitest.tsx +322 -0
- package/src/examples/list-accessory-table.tsx +77 -0
- package/src/examples/list-detail-metadata.vitest.tsx +21 -21
- package/src/examples/list-dropdown-default.vitest.tsx +12 -12
- package/src/examples/list-item-accessories.tsx +106 -0
- package/src/examples/list-item-accessories.vitest.tsx +115 -0
- package/src/examples/list-no-actions.tsx +18 -0
- package/src/examples/list-no-actions.vitest.tsx +97 -0
- package/src/examples/list-spacing-mode.vitest.tsx +6 -6
- package/src/examples/list-with-detail.vitest.tsx +92 -92
- package/src/examples/list-with-dropdown.vitest.tsx +49 -6
- package/src/examples/list-with-sections.vitest.tsx +61 -56
- package/src/examples/simple-detail-markdown.vitest.tsx +21 -17
- package/src/examples/simple-detail-table.tsx +65 -0
- package/src/examples/simple-detail-table.vitest.tsx +200 -0
- package/src/examples/simple-graph.tsx +51 -0
- package/src/examples/simple-graph.vitest.tsx +124 -0
- package/src/examples/simple-grid.vitest.tsx +3 -3
- package/src/examples/simple-list-search.vitest.tsx +65 -0
- package/src/examples/simple-navigation.vitest.tsx +3 -3
- package/src/examples/simple-table-wrap.tsx +55 -0
- package/src/examples/simple-table-wrap.vitest.tsx +91 -0
- package/src/examples/store.vitest.tsx +1 -1
- package/src/examples/table-edge-cases.tsx +72 -0
- package/src/examples/table-edge-cases.vitest.tsx +307 -0
- package/src/examples/table-flex-grow.tsx +53 -0
- package/src/examples/table-flex-grow.vitest.tsx +124 -0
- package/src/extensions/dev.tsx +7 -1
- package/src/globals.ts +3 -0
- package/src/index.tsx +31 -0
- package/src/internal/date-picker-widget.tsx +4 -0
- package/src/internal/providers.tsx +1 -4
- package/src/markdown-utils.tsx +82 -1
- package/src/opentui.tsx +5 -0
- package/src/release.tsx +3 -0
- package/src/state.tsx +2 -1
- package/src/theme.tsx +14 -0
- package/src/themes/nerv.json +231 -0
- package/src/themes/termcast.json +75 -71
- package/src/themes.ts +8 -5
- package/src/utils.tsx +4 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Example: Graph with multiple series - stock price and moving average.
|
|
2
|
+
// Demonstrates multi-series rendering with different colors.
|
|
3
|
+
|
|
4
|
+
import { Detail, Graph, Color } from 'termcast'
|
|
5
|
+
import { renderWithProviders } from '../utils'
|
|
6
|
+
|
|
7
|
+
// 20 days of price data
|
|
8
|
+
const prices = [
|
|
9
|
+
150, 155, 148, 162, 158, 165, 170, 168, 175, 180,
|
|
10
|
+
178, 185, 190, 188, 195, 192, 198, 202, 200, 208,
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
// Simple moving average (5-day window)
|
|
14
|
+
const sma: number[] = prices.map((_, i) => {
|
|
15
|
+
if (i < 4) return prices[i]!
|
|
16
|
+
const window = prices.slice(i - 4, i + 1)
|
|
17
|
+
return window.reduce((sum, v) => sum + v, 0) / window.length
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const xLabels = ['Day 1', 'Day 5', 'Day 10', 'Day 15', 'Day 20']
|
|
21
|
+
|
|
22
|
+
function GraphMultiSeries() {
|
|
23
|
+
return (
|
|
24
|
+
<Detail
|
|
25
|
+
markdown="# Multi-Series Chart"
|
|
26
|
+
metadata={
|
|
27
|
+
<Graph height={12} xLabels={xLabels} yTicks={5}>
|
|
28
|
+
<Graph.Line data={prices} color={Color.Orange} title="Price" />
|
|
29
|
+
<Graph.Line data={sma} color={Color.Blue} title="SMA(5)" />
|
|
30
|
+
</Graph>
|
|
31
|
+
}
|
|
32
|
+
/>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
renderWithProviders(<GraphMultiSeries />)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { test, expect, afterEach, beforeEach } from 'vitest'
|
|
2
|
+
import { launchTerminal, Session } from 'tuistory/src'
|
|
3
|
+
|
|
4
|
+
let session: Session
|
|
5
|
+
|
|
6
|
+
beforeEach(async () => {
|
|
7
|
+
session = await launchTerminal({
|
|
8
|
+
command: 'bun',
|
|
9
|
+
args: ['src/examples/graph-multi-series.tsx'],
|
|
10
|
+
cols: 70,
|
|
11
|
+
rows: 24,
|
|
12
|
+
})
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
session?.close()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('multi-series graph renders both lines', async () => {
|
|
20
|
+
const text = await session.text({
|
|
21
|
+
waitFor: (text) => {
|
|
22
|
+
return text.includes('Multi-Series') && text.includes('│')
|
|
23
|
+
},
|
|
24
|
+
timeout: 10000,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
expect(text).toMatchInlineSnapshot(`
|
|
28
|
+
"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
Multi-Series Chart
|
|
34
|
+
211.0│ ⣠
|
|
35
|
+
│ ⢀⣠⣄⣀ ⣠⣾⣿
|
|
36
|
+
│ ⢀⡀ ⢀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿
|
|
37
|
+
194.5│ ⢀⣀⡀ ⣠⣴⣿⣿⣷⣦⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
38
|
+
│ ⢀⣤⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
39
|
+
│ ⣀⣤⣀ ⣠⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
40
|
+
178.0│ ⢀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
41
|
+
│ ⢀⣤⣶⣤⣄⣠⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
42
|
+
161.5│ ⣀ ⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
43
|
+
│ ⣼⣿⣿⣶⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
44
|
+
│⣀⣤⣶⣷⣤⡀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
45
|
+
145.0│⣿⣿⣿⣿⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
46
|
+
Day 1 Day 5 Day 10 Day 15 Day 20
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
esc go back ^k actions
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
"
|
|
53
|
+
`)
|
|
54
|
+
|
|
55
|
+
// Should contain braille characters
|
|
56
|
+
expect(text).toMatch(/[\u2800-\u28FF]/)
|
|
57
|
+
// Y-axis separator
|
|
58
|
+
expect(text).toContain('│')
|
|
59
|
+
// Title
|
|
60
|
+
expect(text).toContain('Multi-Series')
|
|
61
|
+
// X-axis labels
|
|
62
|
+
expect(text).toContain('Day 1')
|
|
63
|
+
expect(text).toContain('Day 20')
|
|
64
|
+
}, 30000)
|
|
65
|
+
|
|
66
|
+
test('multi-series uses different colors per series', async () => {
|
|
67
|
+
const text = await session.text({
|
|
68
|
+
waitFor: (text) => {
|
|
69
|
+
return text.includes('Multi-Series') && text.includes('│')
|
|
70
|
+
},
|
|
71
|
+
timeout: 10000,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Check that orange-colored braille chars exist (price series uses Color.Orange = #FF9F43)
|
|
75
|
+
const orangeText = await session.text({
|
|
76
|
+
only: { foreground: '#ff9f43' },
|
|
77
|
+
timeout: 5000,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// Check that blue-colored braille chars exist (SMA series uses Color.Blue = #5CB8FF)
|
|
81
|
+
const blueText = await session.text({
|
|
82
|
+
only: { foreground: '#5cb8ff' },
|
|
83
|
+
timeout: 5000,
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// Both series should produce braille output
|
|
87
|
+
expect(orangeText).toMatch(/[\u2800-\u28FF]/)
|
|
88
|
+
expect(blueText).toMatch(/[\u2800-\u28FF]/)
|
|
89
|
+
}, 30000)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Example: Polymarket-style prediction market UI.
|
|
2
|
+
// List of markets with odds graphs in the side detail panel.
|
|
3
|
+
// Each market shows a probability line chart over time.
|
|
4
|
+
|
|
5
|
+
import React from 'react'
|
|
6
|
+
import { Action, ActionPanel, List, Color, Graph } from 'termcast'
|
|
7
|
+
import { renderWithProviders } from '../utils'
|
|
8
|
+
|
|
9
|
+
interface Market {
|
|
10
|
+
id: string
|
|
11
|
+
title: string
|
|
12
|
+
category: string
|
|
13
|
+
currentOdds: number // 0-100 percentage for "Yes"
|
|
14
|
+
volume: string
|
|
15
|
+
endDate: string
|
|
16
|
+
// 30 data points of odds history (0-100)
|
|
17
|
+
oddsHistory: number[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Generate slightly noisy trend data
|
|
21
|
+
function generateOdds({ start, end, volatility = 5 }: { start: number; end: number; volatility?: number }): number[] {
|
|
22
|
+
const points = 30
|
|
23
|
+
const result: number[] = []
|
|
24
|
+
let current = start
|
|
25
|
+
const step = (end - start) / (points - 1)
|
|
26
|
+
for (let i = 0; i < points; i++) {
|
|
27
|
+
const noise = (Math.sin(i * 1.7) + Math.cos(i * 0.8)) * volatility
|
|
28
|
+
current = start + step * i + noise
|
|
29
|
+
result.push(Math.max(1, Math.min(99, Math.round(current * 10) / 10)))
|
|
30
|
+
}
|
|
31
|
+
// Ensure last point matches target
|
|
32
|
+
result[points - 1] = end
|
|
33
|
+
return result
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const markets: Market[] = [
|
|
37
|
+
{
|
|
38
|
+
id: 'btc-100k',
|
|
39
|
+
title: 'Bitcoin above $100k by EOY',
|
|
40
|
+
category: 'Crypto',
|
|
41
|
+
currentOdds: 72,
|
|
42
|
+
volume: '$4.2M',
|
|
43
|
+
endDate: 'Dec 31, 2026',
|
|
44
|
+
oddsHistory: generateOdds({ start: 45, end: 72, volatility: 8 }),
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'eth-merge',
|
|
48
|
+
title: 'ETH above $5k by Q2 2026',
|
|
49
|
+
category: 'Crypto',
|
|
50
|
+
currentOdds: 38,
|
|
51
|
+
volume: '$1.8M',
|
|
52
|
+
endDate: 'Jun 30, 2026',
|
|
53
|
+
oddsHistory: generateOdds({ start: 55, end: 38, volatility: 6 }),
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'fed-rate',
|
|
57
|
+
title: 'Fed cuts rates below 4%',
|
|
58
|
+
category: 'Economics',
|
|
59
|
+
currentOdds: 61,
|
|
60
|
+
volume: '$8.1M',
|
|
61
|
+
endDate: 'Dec 31, 2026',
|
|
62
|
+
oddsHistory: generateOdds({ start: 40, end: 61, volatility: 4 }),
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'sp500-6k',
|
|
66
|
+
title: 'S&P 500 reaches 6,000',
|
|
67
|
+
category: 'Markets',
|
|
68
|
+
currentOdds: 55,
|
|
69
|
+
volume: '$3.5M',
|
|
70
|
+
endDate: 'Dec 31, 2026',
|
|
71
|
+
oddsHistory: generateOdds({ start: 35, end: 55, volatility: 7 }),
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'trump-pardon',
|
|
75
|
+
title: 'Presidential pardon for SBF',
|
|
76
|
+
category: 'Politics',
|
|
77
|
+
currentOdds: 8,
|
|
78
|
+
volume: '$920K',
|
|
79
|
+
endDate: 'Jan 20, 2027',
|
|
80
|
+
oddsHistory: generateOdds({ start: 15, end: 8, volatility: 3 }),
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'ai-agi',
|
|
84
|
+
title: 'AGI announced by major lab',
|
|
85
|
+
category: 'Tech',
|
|
86
|
+
currentOdds: 12,
|
|
87
|
+
volume: '$2.1M',
|
|
88
|
+
endDate: 'Dec 31, 2026',
|
|
89
|
+
oddsHistory: generateOdds({ start: 5, end: 12, volatility: 3 }),
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'sol-flip-eth',
|
|
93
|
+
title: 'Solana flips Ethereum market cap',
|
|
94
|
+
category: 'Crypto',
|
|
95
|
+
currentOdds: 18,
|
|
96
|
+
volume: '$1.4M',
|
|
97
|
+
endDate: 'Dec 31, 2026',
|
|
98
|
+
oddsHistory: generateOdds({ start: 8, end: 18, volatility: 5 }),
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: 'recession-2026',
|
|
102
|
+
title: 'US enters recession in 2026',
|
|
103
|
+
category: 'Economics',
|
|
104
|
+
currentOdds: 28,
|
|
105
|
+
volume: '$5.7M',
|
|
106
|
+
endDate: 'Dec 31, 2026',
|
|
107
|
+
oddsHistory: generateOdds({ start: 20, end: 28, volatility: 4 }),
|
|
108
|
+
},
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
const xLabels = ['30d', '20d', '10d', 'Now']
|
|
112
|
+
|
|
113
|
+
function oddsColor(odds: number): Color.ColorLike {
|
|
114
|
+
if (odds >= 65) return Color.Green
|
|
115
|
+
if (odds >= 40) return Color.Yellow
|
|
116
|
+
return Color.Red
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function PolymarketExample() {
|
|
120
|
+
return (
|
|
121
|
+
<List
|
|
122
|
+
navigationTitle="Polymarket"
|
|
123
|
+
searchBarPlaceholder="Search markets..."
|
|
124
|
+
isShowingDetail={true}
|
|
125
|
+
>
|
|
126
|
+
<List.Section title="Trending Markets">
|
|
127
|
+
{markets.map((market) => {
|
|
128
|
+
return (
|
|
129
|
+
<List.Item
|
|
130
|
+
key={market.id}
|
|
131
|
+
id={market.id}
|
|
132
|
+
title={market.title}
|
|
133
|
+
subtitle={market.category}
|
|
134
|
+
accessories={[
|
|
135
|
+
{ text: { value: `${market.currentOdds}%`, color: oddsColor(market.currentOdds) } },
|
|
136
|
+
]}
|
|
137
|
+
detail={
|
|
138
|
+
<List.Item.Detail
|
|
139
|
+
metadata={
|
|
140
|
+
<List.Item.Detail.Metadata>
|
|
141
|
+
<Graph
|
|
142
|
+
height={8}
|
|
143
|
+
xLabels={xLabels}
|
|
144
|
+
yRange={[0, 100]}
|
|
145
|
+
yTicks={3}
|
|
146
|
+
variant="area"
|
|
147
|
+
yFormat={(v) => `${v.toFixed(0)}%`}
|
|
148
|
+
>
|
|
149
|
+
<Graph.Line
|
|
150
|
+
data={market.oddsHistory}
|
|
151
|
+
color={oddsColor(market.currentOdds)}
|
|
152
|
+
title="Yes"
|
|
153
|
+
/>
|
|
154
|
+
</Graph>
|
|
155
|
+
<List.Item.Detail.Metadata.Label
|
|
156
|
+
title="Odds"
|
|
157
|
+
text={{ value: `${market.currentOdds}% Yes`, color: oddsColor(market.currentOdds) }}
|
|
158
|
+
/>
|
|
159
|
+
<List.Item.Detail.Metadata.Label title="Volume" text={market.volume} />
|
|
160
|
+
<List.Item.Detail.Metadata.Label title="Ends" text={market.endDate} />
|
|
161
|
+
<List.Item.Detail.Metadata.Separator />
|
|
162
|
+
<List.Item.Detail.Metadata.Label title="Probability (30d)" />
|
|
163
|
+
|
|
164
|
+
</List.Item.Detail.Metadata>
|
|
165
|
+
}
|
|
166
|
+
/>
|
|
167
|
+
}
|
|
168
|
+
actions={
|
|
169
|
+
<ActionPanel>
|
|
170
|
+
<Action title="Buy Yes" onAction={() => {}} />
|
|
171
|
+
<Action title="Buy No" onAction={() => {}} />
|
|
172
|
+
</ActionPanel>
|
|
173
|
+
}
|
|
174
|
+
/>
|
|
175
|
+
)
|
|
176
|
+
})}
|
|
177
|
+
</List.Section>
|
|
178
|
+
</List>
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
renderWithProviders(<PolymarketExample />)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { test, expect, afterEach, beforeEach } from 'vitest'
|
|
2
|
+
import { launchTerminal, Session } from 'tuistory/src'
|
|
3
|
+
|
|
4
|
+
let session: Session
|
|
5
|
+
|
|
6
|
+
beforeEach(async () => {
|
|
7
|
+
session = await launchTerminal({
|
|
8
|
+
command: 'bun',
|
|
9
|
+
args: ['src/examples/graph-polymarket.tsx'],
|
|
10
|
+
cols: 100,
|
|
11
|
+
rows: 30,
|
|
12
|
+
})
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
session?.close()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('polymarket list with graph detail renders correctly', async () => {
|
|
20
|
+
const text = await session.text({
|
|
21
|
+
waitFor: (text) => {
|
|
22
|
+
return text.includes('Polymarket') && text.includes('│') && text.includes('Bitcoin')
|
|
23
|
+
},
|
|
24
|
+
timeout: 10000,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
expect(text).toMatchInlineSnapshot(`
|
|
28
|
+
"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
Polymarket ───────────────────────────────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
> Search markets...
|
|
34
|
+
|
|
35
|
+
Trending Markets │ 100%│
|
|
36
|
+
›Bitcoin above $100k by EOY Crypto │ │ ⣠⣀
|
|
37
|
+
ETH above $5k by Q2 2026 Crypto │ │ ⢠⣀ ⢀⣴⣷⡀ ⣰⣿⣿⣷⣀⣤⣴⣦⢀⣴
|
|
38
|
+
Fed cuts rates below 4% Economics │ │⣠⣴⡀ ⢀ ⢠⣿⣿⣷⡀ ⣀⣤⣀⣀⣾⣿⣿⣿⣶⣴⣿⣿⣶⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
39
|
+
S&P 500 reaches 6,000 Markets │ 50%│⣿⣿⣷⣄⢀⣴⣿⣿⣾⣿⣿⣿⣿⣷⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
40
|
+
Presidential pardon for SBF Politics │ │⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
41
|
+
AGI announced by major lab Tech │ │⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
42
|
+
Solana flips Ethereum market cap Crypto │ 0%│⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
43
|
+
US enters recession in 2026 Economics │ 30d 20d 10d Now
|
|
44
|
+
│
|
|
45
|
+
│ Odds: 72% Yes
|
|
46
|
+
│
|
|
47
|
+
│ Volume: $4.2M
|
|
48
|
+
│
|
|
49
|
+
│ Ends: Dec 31, 2026
|
|
50
|
+
│
|
|
51
|
+
│ ────────────────────────────────────────────
|
|
52
|
+
│
|
|
53
|
+
↵ buy yes ↑↓ navigate ^k actions │ Probability (30d)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
"
|
|
59
|
+
`)
|
|
60
|
+
|
|
61
|
+
// Market list visible
|
|
62
|
+
expect(text).toContain('Bitcoin')
|
|
63
|
+
expect(text).toContain('Polymarket')
|
|
64
|
+
// Detail panel with graph
|
|
65
|
+
expect(text).toContain('│')
|
|
66
|
+
expect(text).toMatch(/[\u2800-\u28FF]/)
|
|
67
|
+
// Metadata labels
|
|
68
|
+
expect(text).toContain('Odds')
|
|
69
|
+
expect(text).toContain('Volume')
|
|
70
|
+
}, 30000)
|
|
71
|
+
|
|
72
|
+
test('navigating to different market updates the graph', async () => {
|
|
73
|
+
await session.text({
|
|
74
|
+
waitFor: (text) => {
|
|
75
|
+
return text.includes('Bitcoin') && text.includes('│')
|
|
76
|
+
},
|
|
77
|
+
timeout: 10000,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// Navigate down to second market (ETH)
|
|
81
|
+
await session.press('down')
|
|
82
|
+
|
|
83
|
+
const text = await session.text({
|
|
84
|
+
waitFor: (text) => {
|
|
85
|
+
return text.includes('›ETH')
|
|
86
|
+
},
|
|
87
|
+
timeout: 5000,
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
expect(text).toMatchInlineSnapshot(`
|
|
91
|
+
"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
Polymarket ───────────────────────────────────────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
> Search markets...
|
|
97
|
+
|
|
98
|
+
Trending Markets │ 100%│
|
|
99
|
+
Bitcoin above $100k by EOY Crypto │ │
|
|
100
|
+
›ETH above $5k by Q2 2026 Crypto │ │ ⣀
|
|
101
|
+
Fed cuts rates below 4% Economics │ │⣿⣿⣆ ⢀⡀ ⣀⣾⣶⣄ ⢀⣤⣦ ⢀⡀
|
|
102
|
+
S&P 500 reaches 6,000 Markets │ 50%│⣿⣿⣿⣷⣴⣾⣿⣿⣿⣿⣿⣿⣿⣦⣤⣶⣷⣦⣤⣿⣿⣿⣷⣤⣀⣤⣤⣀⢀⣴⣿⣿⣧ ⣀⣀⡀ ⢀
|
|
103
|
+
Presidential pardon for SBF Politics │ │⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣴⣿
|
|
104
|
+
AGI announced by major lab Tech │ │⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
105
|
+
Solana flips Ethereum market cap Crypto │ 0%│⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
106
|
+
US enters recession in 2026 Economics │ 30d 20d 10d Now
|
|
107
|
+
│
|
|
108
|
+
│ Odds: 38% Yes
|
|
109
|
+
│
|
|
110
|
+
│ Volume: $1.8M
|
|
111
|
+
│
|
|
112
|
+
│ Ends: Jun 30, 2026
|
|
113
|
+
│
|
|
114
|
+
│ ────────────────────────────────────────────
|
|
115
|
+
│
|
|
116
|
+
↵ buy yes ↑↓ navigate ^k actions │ Probability (30d)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
"
|
|
122
|
+
`)
|
|
123
|
+
|
|
124
|
+
// Second market selected
|
|
125
|
+
expect(text).toContain('›ETH')
|
|
126
|
+
// Detail should update
|
|
127
|
+
expect(text).toContain('Volume')
|
|
128
|
+
// Graph still renders
|
|
129
|
+
expect(text).toMatch(/[\u2800-\u28FF]/)
|
|
130
|
+
}, 30000)
|