@graphit/cli 0.1.18 → 0.1.19
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/package.json +1 -1
- package/skills/graphit/SKILL.md +3 -1
- package/skills/graphit/cursor/graphit-presentations.mdc +56 -0
- package/skills/graphit/cursor/graphit-sql-reference.mdc +2 -0
- package/skills/graphit/references/graphit-style.md +11 -0
- package/skills/graphit/references/presentations.md +143 -0
- package/skills/graphit/references/sql-reference.md +2 -0
package/package.json
CHANGED
package/skills/graphit/SKILL.md
CHANGED
|
@@ -43,7 +43,7 @@ Your HTML must NEVER contain:
|
|
|
43
43
|
- `<img src="https://...">` - no external images
|
|
44
44
|
|
|
45
45
|
If you use ANY `src=` or `href=` pointing to a URL, the dashboard will be blank.
|
|
46
|
-
All CSS in `<style>`, all JS in `<script>`, all fonts from system stack. The iframe has a built-in runtime (`graphit.chart`, `graphit.table`, `graphit.kpi`) for standard visualizations - use it instead of importing libraries.
|
|
46
|
+
All CSS in `<style>`, all JS in `<script>`, all fonts from system stack. The iframe has a built-in runtime (`graphit.chart`, `graphit.table`, `graphit.kpi`, `graphit.presentation`) for standard visualizations - use it instead of importing libraries.
|
|
47
47
|
|
|
48
48
|
### 2. ALWAYS query through data sources
|
|
49
49
|
NEVER query the warehouse directly when a cached data source covers the table. Data sources return in ~100ms. Warehouse queries take ~10s and cost Snowflake credits.
|
|
@@ -322,6 +322,7 @@ The iframe also provides optional convenience helpers if you want quick standard
|
|
|
322
322
|
| `graphit.chart(el, {type, data, x, y, ...})` | Bar, line, area, donut, scatter, stacked-bar, heatmap, funnel, gauge, sparkline |
|
|
323
323
|
| `graphit.table(el, {data, columns?, maxRows?})` | Styled HTML table. `columns` is a `string[]` of data keys (NOT objects), defaults to `Object.keys(data[0])` |
|
|
324
324
|
| `graphit.kpi(el, {value, label?, format?})` | KPI card with optional delta |
|
|
325
|
+
| `graphit.presentation(el)` | Full-screen slide deck. Returns builder: `.slide({bg, layout, html})` then `.start()`. See `presentations.md` |
|
|
325
326
|
|
|
326
327
|
These are shortcuts, not requirements. Use them when a standard chart is all you need. Hand-roll when you want full control over the visualization.
|
|
327
328
|
|
|
@@ -378,3 +379,4 @@ Detailed knowledge lives in `references/`. Consult the relevant file when you ne
|
|
|
378
379
|
| `graphit-style.md` | Building the HTML. Design principles, typography scale, color system with usage rules, layout patterns (page structure, KPI cards, data tables). |
|
|
379
380
|
| `chart-patterns.md` | Custom chart implementations. Inline SVG/CSS code for: scatter/bubble, heatmap, funnel, gauge, sparkline, stacked bar, and the shared tooltip pattern. |
|
|
380
381
|
| `governance.md` | Query governance. Reference syntax, trust tiers, enforceable rules, override flow, governance commands. |
|
|
382
|
+
| `presentations.md` | Slide deck presentations. Builder API, layouts (center/split/full), backgrounds, navigation, live data inside slides. |
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
alwaysApply: false
|
|
3
|
+
description: "Graphit: Build full-screen slide deck presentations inside canvas dashboards using graphit.presentation(). Builder pattern with layouts, backgrounds, and keyboard navigation."
|
|
4
|
+
globs: []
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Presentations
|
|
8
|
+
|
|
9
|
+
Build slide deck presentations inside Graphit canvas dashboards using `graphit.presentation()`.
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
var deck = graphit.presentation('#my-deck');
|
|
15
|
+
deck.slide({ bg: 'dark', layout: 'center', html: '<h1>Title</h1>' });
|
|
16
|
+
deck.slide({ bg: 'white', layout: 'split', html: '<div>Left</div><div>Right</div>' });
|
|
17
|
+
deck.slide({ bg: 'paper', layout: 'full', html: '<div id="charts">...</div>' });
|
|
18
|
+
var ctrl = deck.start();
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Slide Config
|
|
22
|
+
|
|
23
|
+
| Field | Type | Default | Description |
|
|
24
|
+
|-------|------|---------|-------------|
|
|
25
|
+
| `layout` | `'center'` / `'split'` / `'full'` | `'center'` | Content arrangement |
|
|
26
|
+
| `bg` | `'paper'` / `'white'` / `'dark'` / `'teal'` / hex | `'paper'` | Fixed background |
|
|
27
|
+
| `html` | `string` | `''` | Raw HTML content |
|
|
28
|
+
|
|
29
|
+
## Layouts
|
|
30
|
+
|
|
31
|
+
- **center**: Centered horizontally/vertically. Title slides, CTAs.
|
|
32
|
+
- **split**: First two child elements become left/right panels. Text + image.
|
|
33
|
+
- **full**: Top-to-bottom flow. Tables, grids, live data.
|
|
34
|
+
|
|
35
|
+
## Backgrounds (fixed, not theme-aware)
|
|
36
|
+
|
|
37
|
+
| Name | Background | Text |
|
|
38
|
+
|------|-----------|------|
|
|
39
|
+
| `paper` | `#F7F6F2` | `#222224` |
|
|
40
|
+
| `white` | `#FFFFFF` | `#222224` |
|
|
41
|
+
| `dark` | `#222224` | `#F7F6F2` |
|
|
42
|
+
| `teal` | `#4DB6AC` | `#FFFFFF` |
|
|
43
|
+
|
|
44
|
+
## Navigation
|
|
45
|
+
|
|
46
|
+
Arrow keys, spacebar, Home/End. Prev/Next buttons bottom-right with slide counter.
|
|
47
|
+
|
|
48
|
+
## Live data works inside slides
|
|
49
|
+
|
|
50
|
+
`graphit.resolve()` + `graphit.chart/table/kpi` work inside slides. Entity wrapping (`data-graphit-*`) works normally.
|
|
51
|
+
|
|
52
|
+
## Anti-Patterns
|
|
53
|
+
|
|
54
|
+
- Don't use external fonts/images (CSP blocks). Embed as base64 or use system fonts.
|
|
55
|
+
- Don't put scrollable content on slides. Split into multiple slides.
|
|
56
|
+
- One `graphit.presentation()` per dashboard.
|
|
@@ -128,12 +128,14 @@ Canvas `graphit.resolve()` queries that follow these shapes serve from a semanti
|
|
|
128
128
|
- Literal dates (`>= '2026-01-01'`), never `CURRENT_DATE` expressions
|
|
129
129
|
- GROUP BY column names or ordinals; ORDER BY / LIMIT allowed (outer only)
|
|
130
130
|
- CTEs are fine when the CTE body follows the same rules
|
|
131
|
+
- Top-N rank queries: project the sort metric in SELECT (`SELECT dim, SUM(metric) AS rv ... ORDER BY rv DESC LIMIT N`), not only in ORDER BY
|
|
131
132
|
|
|
132
133
|
**Shapes that skip the cache** (fall back to normal execution, still correct):
|
|
133
134
|
- `COUNT(DISTINCT x)`, window functions, HAVING, QUALIFY
|
|
134
135
|
- OR / NOT in WHERE
|
|
135
136
|
- Ratio metrics (`SUM(a)/NULLIF(SUM(b),0)`) - compute client-side or use two resolves
|
|
136
137
|
- `CURRENT_DATE`-relative predicates
|
|
138
|
+
- Top-N with aggregate only in ORDER BY (`SELECT dim FROM t GROUP BY dim ORDER BY SUM(metric) DESC LIMIT N` - no decomposable aggregate in SELECT)
|
|
137
139
|
|
|
138
140
|
## Data Source Routing
|
|
139
141
|
|
|
@@ -37,6 +37,17 @@ NEVER use hardcoded hex colors. Use CSS custom properties that automatically ada
|
|
|
37
37
|
- **Warning:** `var(--graphit-warning)`
|
|
38
38
|
- **Danger / bad:** `var(--graphit-error)`
|
|
39
39
|
|
|
40
|
+
### Custom Colors
|
|
41
|
+
|
|
42
|
+
When the user explicitly requests specific colors or a custom color theme, ask for both light and dark mode variants. Write explicit CSS with `.dark` class overrides so the dashboard adapts to both modes:
|
|
43
|
+
|
|
44
|
+
```css
|
|
45
|
+
.revenue-card { background: #001f3f; color: #ffffff; }
|
|
46
|
+
.dark .revenue-card { background: #0a3d6b; color: #e0e0e0; }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
NEVER hardcode a structural color (background, color, border-color) without a `.dark` counterpart. Data/chart series colors (bar fills, line strokes) are exempt - they work in both modes.
|
|
50
|
+
|
|
40
51
|
### Multi-Series
|
|
41
52
|
Use `var(--graphit-accent)` as the primary series. For additional series, choose muted complementary colors that work on both light and dark backgrounds.
|
|
42
53
|
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Presentations
|
|
2
|
+
|
|
3
|
+
Build full-screen slide deck presentations inside Graphit canvas dashboards using `graphit.presentation()`.
|
|
4
|
+
|
|
5
|
+
## API
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
var deck = graphit.presentation('#my-deck');
|
|
9
|
+
|
|
10
|
+
deck.slide({ bg: 'dark', layout: 'center', html: '<h1>Title</h1><p>Subtitle</p>' });
|
|
11
|
+
deck.slide({ bg: 'white', layout: 'split', html: '<div>Left panel</div><div>Right panel</div>' });
|
|
12
|
+
deck.slide({ bg: 'paper', layout: 'full', html: '<div id="charts">...</div>' });
|
|
13
|
+
|
|
14
|
+
var ctrl = deck.start();
|
|
15
|
+
// ctrl.go(3) - jump to slide 4
|
|
16
|
+
// ctrl.total - number of slides
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`graphit.presentation(el)` returns a **builder**. Call `.slide()` to add slides (chainable), then `.start()` to render and wire navigation. `start()` returns a controller with `go(n)` and `total`.
|
|
20
|
+
|
|
21
|
+
## Slide Config
|
|
22
|
+
|
|
23
|
+
| Field | Type | Default | Description |
|
|
24
|
+
|-------|------|---------|-------------|
|
|
25
|
+
| `layout` | `'center'` / `'split'` / `'full'` | `'center'` | How content is arranged inside the slide |
|
|
26
|
+
| `bg` | `'paper'` / `'white'` / `'dark'` / `'teal'` / hex | `'paper'` | Fixed background color (not theme-aware) |
|
|
27
|
+
| `html` | `string` | `''` | Raw HTML content for the slide |
|
|
28
|
+
|
|
29
|
+
## Layouts
|
|
30
|
+
|
|
31
|
+
### `center` (default)
|
|
32
|
+
Content is centered horizontally and vertically. Use for title slides, quotes, big stats, CTAs.
|
|
33
|
+
|
|
34
|
+
### `split`
|
|
35
|
+
The first two child elements in `html` become left and right panels (50/50 flex). Use for text + image, comparison, side-by-side content. On mobile (<700px), panels stack vertically.
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
deck.slide({
|
|
39
|
+
layout: 'split',
|
|
40
|
+
bg: 'white',
|
|
41
|
+
html: '<div><h2>Left Title</h2><p>Text content</p></div><div><img src="data:..."></div>'
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `full`
|
|
46
|
+
Content flows top-to-bottom with generous padding. Use for tables, grids, live data dashboards, complex layouts that need the full slide width.
|
|
47
|
+
|
|
48
|
+
## Background Themes
|
|
49
|
+
|
|
50
|
+
Backgrounds are **fixed colors** - they do not change with the app's light/dark mode. A dark slide stays dark. Content inside CAN use `var(--graphit-*)` tokens.
|
|
51
|
+
|
|
52
|
+
| Name | Background | Text Color |
|
|
53
|
+
|------|-----------|------------|
|
|
54
|
+
| `paper` | `#F7F6F2` (warm cream) | `#222224` (charcoal) |
|
|
55
|
+
| `white` | `#FFFFFF` | `#222224` |
|
|
56
|
+
| `dark` | `#222224` (charcoal) | `#F7F6F2` (cream) |
|
|
57
|
+
| `teal` | `#4DB6AC` (brand teal) | `#FFFFFF` |
|
|
58
|
+
| hex string | Custom (e.g. `#1a1a2e`) | Inherited from content HTML |
|
|
59
|
+
|
|
60
|
+
## Navigation
|
|
61
|
+
|
|
62
|
+
The slide deck includes built-in navigation:
|
|
63
|
+
- **Arrow keys**: Left/Right to navigate (guarded - skips when focus is on input/textarea)
|
|
64
|
+
- **Spacebar**: Next slide
|
|
65
|
+
- **Home/End**: First/last slide
|
|
66
|
+
- **Prev/Next buttons**: Bottom-right corner with slide counter
|
|
67
|
+
|
|
68
|
+
## Live Data Inside Slides
|
|
69
|
+
|
|
70
|
+
`graphit.resolve()` and `graphit.chart/table/kpi` work inside slides. All resolve calls fire on page load (cached queries are fast). Charts render into their target elements regardless of which slide is visible.
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
// Slide with live entities
|
|
74
|
+
deck.slide({
|
|
75
|
+
layout: 'full',
|
|
76
|
+
bg: 'white',
|
|
77
|
+
html: `
|
|
78
|
+
<h2>Live Data</h2>
|
|
79
|
+
<div data-graphit-id="spend-chart" data-graphit-label="Ad Spend"
|
|
80
|
+
data-graphit-kb="metric:TOTAL_AD_SPEND,table:MARKETING_UA"
|
|
81
|
+
data-graphit-sql="SELECT MEDIA_SOURCE, SUM(APPSFLYER_COST) AS spend FROM MARKETING_UA_DS GROUP BY 1 ORDER BY spend DESC LIMIT 6"
|
|
82
|
+
data-graphit-ds="ds_abc123">
|
|
83
|
+
<div id="chart1" class="gh-loading">
|
|
84
|
+
<div class="gh-loading-overlay"><svg class="gh-loading-spin" width="24" height="24" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="10" stroke="#e5e5e5" stroke-width="2.5"/><path d="M12 2a10 10 0 0 1 10 10" stroke="#4DB6AC" stroke-width="2.5" stroke-linecap="round"/></svg></div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
`
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// After deck.start(), fire resolve calls
|
|
91
|
+
deck.start();
|
|
92
|
+
|
|
93
|
+
graphit.resolve({
|
|
94
|
+
sql: "SELECT MEDIA_SOURCE, SUM(APPSFLYER_COST) AS spend FROM MARKETING_UA_DS GROUP BY 1 ORDER BY spend DESC LIMIT 6",
|
|
95
|
+
dataSourceId: "ds_abc123",
|
|
96
|
+
target: "#chart1"
|
|
97
|
+
}).then(function(r) {
|
|
98
|
+
graphit.chart("#chart1", { type: "bar", data: r.data, x: "MEDIA_SOURCE", y: "spend", valueFormat: "currency" });
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Entity Wrapping
|
|
103
|
+
|
|
104
|
+
Every data element inside slides should have full `data-graphit-*` entity wrapping, same as regular dashboards. The entity provenance panel, @ mentions, and click-to-inspect all work inside slides.
|
|
105
|
+
|
|
106
|
+
## Example: Complete Pitch Deck
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
var deck = graphit.presentation('#deck');
|
|
110
|
+
|
|
111
|
+
deck.slide({
|
|
112
|
+
bg: 'paper',
|
|
113
|
+
layout: 'center',
|
|
114
|
+
html: '<h1 style="font-size:6rem;font-weight:300">Company Update</h1><p style="font-size:1.5rem;color:#6B7280;margin-top:16px">Q2 2026</p>'
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
deck.slide({
|
|
118
|
+
bg: 'dark',
|
|
119
|
+
layout: 'split',
|
|
120
|
+
html: '<div style="color:#F7F6F2"><h2 style="font-size:3rem">The Problem</h2><p style="font-size:1.25rem;opacity:0.7;margin-top:16px">Analysts spend 80% of their time assembling dashboards instead of finding insights.</p></div><div style="display:flex;align-items:center;justify-content:center"><img src="data:image/webp;base64,..." style="max-height:60vh;border-radius:16px"></div>'
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
deck.slide({
|
|
124
|
+
bg: 'white',
|
|
125
|
+
layout: 'full',
|
|
126
|
+
html: '<h2 style="font-size:2.5rem;margin-bottom:24px">Key Metrics</h2><div style="display:grid;grid-template-columns:repeat(3,1fr);gap:16px">...</div>'
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
deck.slide({
|
|
130
|
+
bg: 'teal',
|
|
131
|
+
layout: 'center',
|
|
132
|
+
html: '<h2 style="font-size:4rem;color:#fff">Thank You</h2><p style="font-size:1.25rem;color:rgba(255,255,255,0.7);margin-top:16px">company.com</p>'
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
deck.start();
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Anti-Patterns
|
|
139
|
+
|
|
140
|
+
- **Don't put too much content on one slide.** If it scrolls, split into multiple slides.
|
|
141
|
+
- **Don't use external fonts via @import or link.** The iframe CSP blocks them. Embed as base64 @font-face or use system fonts.
|
|
142
|
+
- **Don't use external images.** Use data URIs (base64) or inline SVG.
|
|
143
|
+
- **Don't nest presentations.** One `graphit.presentation()` per dashboard.
|
|
@@ -122,12 +122,14 @@ Canvas `graphit.resolve()` queries that follow these shapes serve from a semanti
|
|
|
122
122
|
- Literal dates (`>= '2026-01-01'`), never `CURRENT_DATE` expressions
|
|
123
123
|
- GROUP BY column names or ordinals; ORDER BY / LIMIT allowed (outer only)
|
|
124
124
|
- CTEs are fine when the CTE body follows the same rules
|
|
125
|
+
- Top-N rank queries: project the sort metric in SELECT (`SELECT dim, SUM(metric) AS rv ... ORDER BY rv DESC LIMIT N`), not only in ORDER BY
|
|
125
126
|
|
|
126
127
|
**Shapes that skip the cache** (fall back to normal execution, still correct):
|
|
127
128
|
- `COUNT(DISTINCT x)`, window functions, HAVING, QUALIFY
|
|
128
129
|
- OR / NOT in WHERE
|
|
129
130
|
- Ratio metrics (`SUM(a)/NULLIF(SUM(b),0)`) - compute client-side or use two resolves
|
|
130
131
|
- `CURRENT_DATE`-relative predicates
|
|
132
|
+
- Top-N with aggregate only in ORDER BY (`SELECT dim FROM t GROUP BY dim ORDER BY SUM(metric) DESC LIMIT N` - no decomposable aggregate in SELECT)
|
|
131
133
|
|
|
132
134
|
## Data Source Routing
|
|
133
135
|
|