eleventy-plugin-uncharted 0.4.1 → 0.4.3

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/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  A CSS-based chart plugin for Eleventy. Renders charts as pure HTML/CSS.
4
4
 
5
+ **[Full Documentation](https://uncharted.docs.seanlunsford.com/)**
6
+
5
7
  ## Installation
6
8
 
7
9
  ```bash
@@ -19,349 +21,22 @@ export default function(eleventyConfig) {
19
21
  }
20
22
  ```
21
23
 
22
- The plugin automatically copies the CSS to your output directory and injects the stylesheet link into pages that contain charts.
23
-
24
- ### Options
25
-
26
- ```javascript
27
- eleventyConfig.addPlugin(uncharted, {
28
- dataDir: '_data', // where to find CSV files (default: '_data')
29
- animate: true, // enable animations globally (default: false)
30
- cssPath: '/css/uncharted.css', // output path for stylesheet (default: '/css/uncharted.css')
31
- injectCss: false, // disable automatic CSS handling (default: true)
32
- downloadData: true, // enable download links globally (default: false)
33
- dataPassthrough: true, // copy CSV files to public path (default: false)
34
- dataPath: '/data/' // public URL path for CSV files (default: '/data/')
35
- });
36
- ```
37
-
38
- If you set `injectCss: false`, you'll need to manually include the stylesheet in your layout:
39
-
40
- ```html
41
- <link rel="stylesheet" href="/css/uncharted.css">
42
- ```
43
-
44
- ## Chart Types
45
-
46
- | Type | Description | Negative Values |
47
- |------|-------------|-----------------|
48
- | `donut` | Pie/donut chart using conic-gradient | No |
49
- | `stacked-bar` | Horizontal bars with stacked segments | No |
50
- | `stacked-column` | Vertical columns with stacked segments | Yes |
51
- | `dot` | Categorical dot chart with Y-axis positioning | Yes |
52
- | `scatter` | XY scatter plot with continuous axes | Yes (X and Y) |
53
-
54
- ## Value Formatting
55
-
56
- Format displayed numbers with thousands separators, compact notation, or currency symbols.
57
- Raw values are preserved for calculations; only display output is affected.
58
-
59
- ### Options
60
-
61
- | Option | Type | Description |
62
- |--------|------|-------------|
63
- | `thousands` | boolean | Add commas: `1000` → `1,000` |
64
- | `compact` | boolean | Use suffixes: `1000` → `1K`, `1000000` → `1M` |
65
- | `decimals` | number | Decimal places (default: 0, or 1 if compact) |
66
- | `currency.symbol` | string | Currency symbol: `$`, `€`, etc. |
67
- | `currency.position` | string | `prefix` (default) or `suffix` |
68
-
69
- ### Examples
70
-
71
- **Thousands separators:**
72
-
73
- ```yaml
74
- format:
75
- thousands: true
76
- # 1234567 → 1,234,567
77
- ```
78
-
79
- **Compact notation:**
80
-
81
- ```yaml
82
- format:
83
- compact: true
84
- # 1500 → 1.5K, 2000000 → 2M
85
- ```
86
-
87
- **Currency:**
88
-
89
- ```yaml
90
- format:
91
- thousands: true
92
- currency:
93
- symbol: "$"
94
- # 1234 → $1,234
95
- ```
96
-
97
- **Scatter charts** support separate X/Y formatting:
98
-
99
- ```yaml
100
- format:
101
- x:
102
- thousands: true
103
- y:
104
- compact: true
105
- currency:
106
- symbol: "$"
107
- ```
108
-
109
- ## Usage
24
+ ## Quick Example
110
25
 
111
- ### Page Frontmatter
112
-
113
- Define charts in your page's frontmatter and reference them with the `chart` shortcode:
26
+ Define a chart in frontmatter and render with the shortcode:
114
27
 
115
28
  ```markdown
116
29
  ---
117
30
  charts:
118
- growth:
119
- type: stacked-bar
120
- title: Platform Growth
121
- subtitle: Models by domain
122
- max: 25
123
- file: charts/platform-growth.csv
124
- ---
125
-
126
- {% chart "growth" %}
127
- ```
128
-
129
- ### Global Data Files
130
-
131
- Define charts in `_data/charts.json` or `_data/charts.yaml`:
132
-
133
- ```json
134
- {
135
- "releases": {
136
- "type": "stacked-column",
137
- "title": "Release Cadence",
138
- "file": "charts/releases.csv",
139
- "legend": ["Production", "Hotfix", "Beta"]
140
- }
141
- }
142
- ```
143
-
144
- ```markdown
145
- {% chart "releases" %}
146
- ```
147
-
148
- ### Inline Data
149
-
150
- Embed data directly in frontmatter:
151
-
152
- ```yaml
153
- charts:
154
- issues:
155
- type: donut
156
- title: Issue Types
157
- center:
158
- value: total
159
- label: Issues
160
- data:
161
- - label: Features
162
- value: 33
163
- - label: Bugs
164
- value: 21
165
- - label: Other
166
- value: 4
167
- ```
168
-
169
- ## CSV Format
170
-
171
- CSV files use the first column as labels and subsequent columns as data series. The column names can be anything descriptive:
172
-
173
- ```csv
174
- department,existing,new
175
- Finance,11,11
176
- Sales,16,2
177
- Core,8,0
178
- ```
179
-
180
- For scatter plots, columns are positional: point label, X value, Y value, and optionally series. Column names become axis labels by default:
181
-
182
- ```csv
183
- country,population,gdp,region
184
- USA,330,21,Americas
185
- China,1400,14,Asia
186
- Germany,83,4,Europe
187
- ```
188
-
189
- This displays "population" as the X-axis title and "gdp" as the Y-axis title. Override with explicit titles:
190
-
191
- ```yaml
192
- charts:
193
- my-scatter:
194
- type: scatter
195
- file: charts/data.csv
196
- titleX: "Population (millions)"
197
- titleY: "GDP (trillions)"
198
- ```
199
-
200
- ## Negative Values
201
-
202
- Stacked column, dot, and scatter charts support negative values. When negative values are present, a zero axis line appears automatically and values are positioned relative to it.
203
-
204
- For stacked columns, positive values stack upward from zero and negative values stack downward:
205
-
206
- ```csv
207
- quarter,Cost,Profit
208
- Q1,20,10
209
- Q2,25,-10
210
- Q3,15,25
211
- Q4,30,-10
212
- ```
213
-
214
- The chart automatically calculates the range from the maximum positive stack to the minimum negative stack, ensuring proper scaling.
215
-
216
- ## Configuration Options
217
-
218
- | Option | Type | Description |
219
- |--------|------|-------------|
220
- | `type` | string | Chart type (required) |
221
- | `title` | string | Chart title |
222
- | `subtitle` | string | Subtitle below title |
223
- | `file` | string | Path to CSV file (relative to dataDir) |
224
- | `data` | array | Inline data array |
225
- | `max` | number | Maximum Y value for scaling |
226
- | `min` | number | Minimum Y value for scaling (column, dot) |
227
- | `maxX` | number | Maximum X value (scatter only) |
228
- | `maxY` | number | Maximum Y value (scatter only) |
229
- | `minX` | number | Minimum X value (scatter only) |
230
- | `minY` | number | Minimum Y value (scatter only) |
231
- | `titleX` | string | X-axis title (scatter only, defaults to column name) |
232
- | `titleY` | string | Y-axis title (scatter only, defaults to column name) |
233
- | `legend` | array | Custom legend labels |
234
- | `center` | object | Donut center content (`value`, `label`) |
235
- | `showPercentages` | boolean | Show percentages instead of values in donut legend |
236
- | `animate` | boolean | Override global animation setting |
237
- | `format` | object | Number formatting options (see Value Formatting) |
238
- | `rotateLabels` | boolean | Rotate X-axis labels vertically (stacked-column, dot) |
239
- | `downloadData` | boolean/string | Enable download link (`true`, `false`, or custom label) |
240
-
241
- ## Download Links
242
-
243
- Add download links below charts so users can download the source CSV data.
244
-
245
- ### Setup
246
-
247
- Enable globally in plugin options:
248
-
249
- ```javascript
250
- eleventyConfig.addPlugin(uncharted, {
251
- downloadData: true, // show download links on all charts
252
- dataPassthrough: true, // copy CSV files to output
253
- dataPath: '/data/' // URL path for files (default)
254
- });
255
- ```
256
-
257
- ### Per-Chart Override
258
-
259
- ```yaml
260
- charts:
261
- # Uses global setting
262
- revenue:
31
+ sales:
263
32
  type: stacked-bar
264
- file: charts/revenue.csv
265
-
266
- # Custom label
267
- expenses:
268
- type: stacked-column
269
- file: charts/expenses.csv
270
- downloadData: "Download expense report"
271
-
272
- # Disable for this chart
273
- internal:
274
- type: donut
275
- file: charts/internal.csv
276
- downloadData: false
277
- ```
278
-
279
- ### Without Passthrough
280
-
281
- If `dataPassthrough` is false, you're responsible for ensuring CSV files are available at the expected URLs. The plugin generates links based on `dataPath` + `file`.
282
-
283
- ## Styling
284
-
285
- ### CSS Custom Properties
286
-
287
- Override the default color palette and sizing:
288
-
289
- ```css
290
- :root {
291
- --chart-color-1: #2196f3;
292
- --chart-color-2: #4caf50;
293
- --chart-color-3: #ffc107;
294
- --chart-color-4: #ff7043;
295
- --chart-color-5: #9c27b0;
296
- --chart-color-6: #e91e63;
297
- --chart-color-7: #009688;
298
- --chart-color-8: #78909c;
299
- --chart-bg: rgba(128, 128, 128, 0.15);
300
- --chart-height: 12rem; /* Height of bar/column/dot/scatter charts */
301
- --chart-column-width: 1rem; /* Min width per column */
302
- --chart-donut-size: 20rem; /* Donut chart max diameter */
303
- --chart-donut-hole: 30%; /* Donut hole size (percentage of diameter) */
304
- }
305
- ```
306
-
307
- ### Responsive Donut Charts
308
-
309
- Donut charts automatically adapt to their container using CSS container queries:
310
-
311
- - **Narrow containers**: Donut on top, legend wraps below horizontally
312
- - **Wide containers** (24rem+): Donut and legend side by side
313
-
314
- The donut scales to 80% of container width (minimum 8rem, maximum `--chart-donut-size`).
315
-
316
- ### Per-Chart Styling
317
-
318
- Each chart gets a class based on its ID for targeted styling:
319
-
320
- ```yaml
321
- charts:
322
- sales-growth:
323
- type: stacked-column
33
+ title: Quarterly Sales
324
34
  file: charts/sales.csv
325
- ```
326
-
327
- ```css
328
- /* Target this specific chart */
329
- .chart-sales-growth {
330
- --chart-height: 16rem;
331
- --chart-color-1: #ff6b6b;
332
- }
333
- ```
334
-
335
- ### Dual Class System
336
-
337
- Each chart element gets two classes for styling flexibility:
338
-
339
- 1. **Ordinal**: `.chart-color-1`, `.chart-color-2`, etc.
340
- 2. **Semantic**: `.chart-series-{slugified-name}`
341
-
342
- ```css
343
- /* Style by position */
344
- .chart-color-1 { --color: #ff6b6b; }
345
-
346
- /* Style by series name */
347
- .chart-series-production { --color: #51cf66; }
348
- ```
349
-
350
- ## Animations
351
-
352
- Animations are CSS-based with staggered reveals. Enable globally or per-chart:
35
+ ---
353
36
 
354
- ```javascript
355
- // Global
356
- eleventyConfig.addPlugin(uncharted, { animate: true });
37
+ {% chart "sales" %}
357
38
  ```
358
39
 
359
- ```yaml
360
- # Per-chart override
361
- charts:
362
- static-chart:
363
- type: donut
364
- animate: false
365
- ```
40
+ Chart types: `donut`, `stacked-bar`, `stacked-column`, `dot`, `scatter`
366
41
 
367
- For scroll-triggered animations, add your own Intersection Observer to toggle the `.chart-animate` class.
42
+ See the [documentation](https://uncharted.docs.seanlunsford.com/) for configuration options, styling, animations, and more.
package/css/uncharted.css CHANGED
@@ -59,6 +59,7 @@
59
59
  display: flex;
60
60
  flex-direction: column;
61
61
  flex: 1;
62
+ min-width: 16rem;
62
63
  }
63
64
 
64
65
  .chart-title {
@@ -368,8 +369,10 @@
368
369
  flex-wrap: wrap;
369
370
  align-items: center;
370
371
  align-content: center;
372
+ justify-content: center;
371
373
  gap: 2rem;
372
374
  flex: 1;
375
+ min-width: 0;
373
376
  }
374
377
 
375
378
  .chart-donut .donut-container {
@@ -435,6 +438,7 @@
435
438
  flex-wrap: wrap;
436
439
  justify-content: center;
437
440
  gap: 0.5rem 1rem;
441
+ max-width: 100%;
438
442
  }
439
443
 
440
444
  /* Wide container: legend beside donut, stack items vertically
@@ -569,24 +573,36 @@
569
573
  ========================================================================== */
570
574
 
571
575
  .chart-scatter .chart-body {
572
- align-items: stretch;
576
+ display: grid;
577
+ grid-template-columns: auto 1fr;
578
+ grid-template-rows: 1fr auto;
579
+ }
580
+
581
+ .chart-scatter .chart-y-axis {
582
+ grid-row: 1;
583
+ grid-column: 1;
573
584
  }
574
585
 
575
586
  .chart-scatter .scatter-container {
576
- display: flex;
577
- flex-direction: column;
578
- flex: 1;
587
+ grid-row: 1 / -1;
588
+ grid-column: 2;
589
+ display: grid;
590
+ grid-template-rows: subgrid;
579
591
  }
580
592
 
581
593
  .chart-scatter .dot-area {
594
+ grid-row: 1;
582
595
  position: relative;
583
- flex: 1;
584
596
  min-height: var(--chart-height);
585
597
  background: var(--chart-bg);
586
598
  border-radius: 3px;
587
599
  box-sizing: border-box;
588
600
  }
589
601
 
602
+ .chart-scatter .chart-x-axis {
603
+ grid-row: 2;
604
+ }
605
+
590
606
  /* Inner field sized to content area - dots position relative to this */
591
607
  .chart-scatter .dot-field {
592
608
  position: absolute;
@@ -867,7 +883,7 @@
867
883
  background-color: currentColor;
868
884
  opacity: 0.4;
869
885
  pointer-events: none;
870
- z-index: -1;
886
+ z-index: 0;
871
887
  }
872
888
 
873
889
  .chart-scatter.has-negative-y .dot-field::after {
@@ -880,7 +896,7 @@
880
896
  background-color: currentColor;
881
897
  opacity: 0.4;
882
898
  pointer-events: none;
883
- z-index: -1;
899
+ z-index: 0;
884
900
  }
885
901
 
886
902
  .chart-scatter.has-negative-x .dot-field::before {
@@ -893,7 +909,7 @@
893
909
  background-color: currentColor;
894
910
  opacity: 0.4;
895
911
  pointer-events: none;
896
- z-index: -1;
912
+ z-index: 0;
897
913
  }
898
914
 
899
915
  /* ==========================================================================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eleventy-plugin-uncharted",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "An Eleventy plugin that renders CSS-based charts from CSV data using shortcodes",
5
5
  "main": "eleventy.config.js",
6
6
  "type": "module",
@@ -27,7 +27,7 @@
27
27
  "type": "git",
28
28
  "url": "git+https://github.com/slunsford/uncharted.git"
29
29
  },
30
- "homepage": "https://github.com/slunsford/uncharted#readme",
30
+ "homepage": "https://uncharted.docs.seanlunsford.com",
31
31
  "bugs": {
32
32
  "url": "https://github.com/slunsford/uncharted/issues"
33
33
  },