eleventy-plugin-uncharted 0.2.1 → 0.3.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.
package/README.md CHANGED
@@ -253,11 +253,20 @@ Override the default color palette and sizing:
253
253
  --chart-bg: rgba(128, 128, 128, 0.15);
254
254
  --chart-height: 12rem; /* Height of bar/column/dot/scatter charts */
255
255
  --chart-column-width: 1rem; /* Min width per column */
256
- --chart-donut-size: 12rem; /* Donut chart diameter */
257
- --chart-donut-thickness: 2.5rem; /* Donut ring thickness */
256
+ --chart-donut-size: 20rem; /* Donut chart max diameter */
257
+ --chart-donut-hole: 30%; /* Donut hole size (percentage of diameter) */
258
258
  }
259
259
  ```
260
260
 
261
+ ### Responsive Donut Charts
262
+
263
+ Donut charts automatically adapt to their container using CSS container queries:
264
+
265
+ - **Narrow containers**: Donut on top, legend wraps below horizontally
266
+ - **Wide containers** (24rem+): Donut and legend side by side
267
+
268
+ The donut scales to 80% of container width (minimum 8rem, maximum `--chart-donut-size`).
269
+
261
270
  ### Per-Chart Styling
262
271
 
263
272
  Each chart gets a class based on its ID for targeted styling:
package/css/uncharted.css CHANGED
@@ -27,8 +27,8 @@
27
27
  --chart-gap: 0.5rem;
28
28
  --chart-bar-height: 1.5rem;
29
29
  --chart-column-width: 1rem;
30
- --chart-donut-size: 12rem;
31
- --chart-donut-thickness: 2.5rem;
30
+ --chart-donut-size: 20rem;
31
+ --chart-donut-hole: 30%;
32
32
  --chart-dot-size: 0.75rem;
33
33
  --chart-height: 12rem;
34
34
  }
@@ -55,8 +55,10 @@
55
55
  ========================================================================== */
56
56
 
57
57
  .chart {
58
- margin: 1.5rem 0;
59
58
  font-family: inherit;
59
+ display: flex;
60
+ flex-direction: column;
61
+ flex: 1;
60
62
  }
61
63
 
62
64
  .chart-title {
@@ -112,7 +114,7 @@
112
114
 
113
115
  .chart-legend-item .legend-value {
114
116
  opacity: 0.7;
115
- margin-left: 0.25rem;
117
+ margin-left: 0.125rem;
116
118
  }
117
119
 
118
120
  /* ==========================================================================
@@ -122,6 +124,8 @@
122
124
  .chart-body {
123
125
  display: flex;
124
126
  gap: 0.5rem;
127
+ flex: 1;
128
+ min-height: var(--chart-height);
125
129
  }
126
130
 
127
131
  .chart-y-axis {
@@ -132,7 +136,7 @@
132
136
  align-items: flex-end;
133
137
  min-width: 2rem;
134
138
  box-sizing: border-box;
135
- height: var(--chart-height);
139
+ min-height: var(--chart-height);
136
140
  padding-top: 0.5rem;
137
141
  padding-bottom: 0;
138
142
  }
@@ -202,8 +206,10 @@
202
206
  .chart-stacked-bar .chart-bars {
203
207
  display: grid;
204
208
  grid-template-columns: auto 1fr auto;
205
- gap: var(--chart-gap) 0.75rem;
206
- align-items: center;
209
+ grid-auto-rows: 1fr;
210
+ gap: clamp(0.375rem, 1.5cqi, 1rem) 0.75rem;
211
+ align-items: stretch;
212
+ min-height: var(--chart-height);
207
213
  }
208
214
 
209
215
  .chart-stacked-bar .bar-row {
@@ -213,10 +219,13 @@
213
219
  .chart-stacked-bar .bar-label {
214
220
  font-size: 0.875rem;
215
221
  text-align: right;
222
+ display: flex;
223
+ align-items: center;
224
+ justify-content: flex-end;
216
225
  }
217
226
 
218
227
  .chart-stacked-bar .bar-track {
219
- height: var(--chart-bar-height);
228
+ min-height: var(--chart-bar-height);
220
229
  border-radius: 3px;
221
230
  overflow: hidden;
222
231
  background: var(--chart-bg);
@@ -235,6 +244,8 @@
235
244
  }
236
245
 
237
246
  .chart-stacked-bar .bar-value {
247
+ display: flex;
248
+ align-items: center;
238
249
  font-size: 0.875rem;
239
250
  font-variant-numeric: tabular-nums;
240
251
  min-width: 2rem;
@@ -245,36 +256,36 @@
245
256
  ========================================================================== */
246
257
 
247
258
  .chart-stacked-column .chart-body {
248
- align-items: stretch;
259
+ display: grid;
260
+ grid-template-columns: auto 1fr;
261
+ grid-template-rows: 1fr auto;
262
+ }
263
+
264
+ .chart-stacked-column .chart-y-axis {
265
+ grid-row: 1;
266
+ grid-column: 1;
249
267
  }
250
268
 
251
269
  .chart-stacked-column .chart-scroll {
252
- flex: 1;
270
+ grid-row: 1 / -1;
271
+ grid-column: 2;
272
+ display: grid;
273
+ grid-template-rows: subgrid;
253
274
  overflow-x: auto;
254
275
  overflow-y: visible;
255
- position: relative;
256
- }
257
-
258
- .chart-stacked-column .chart-scroll::before {
259
- content: '';
260
- position: sticky;
261
- left: 0;
262
- display: block;
263
- height: var(--chart-height);
264
- margin-bottom: calc(-1 * var(--chart-height));
265
- background: var(--chart-bg);
266
- border-radius: 3px;
267
- pointer-events: none;
268
276
  }
269
277
 
270
278
  .chart-stacked-column .chart-columns {
279
+ grid-row: 1;
271
280
  position: relative;
272
281
  display: flex;
273
- gap: 0.25rem;
282
+ gap: clamp(0.375rem, 1.5cqi, 1rem);
274
283
  align-items: stretch;
275
- height: var(--chart-height);
284
+ min-height: var(--chart-height);
276
285
  padding: 0.5rem 0.5rem 0 0.5rem;
277
286
  box-sizing: border-box;
287
+ background: var(--chart-bg);
288
+ border-radius: 3px;
278
289
  }
279
290
 
280
291
  .chart-stacked-column .column-track {
@@ -282,7 +293,6 @@
282
293
  flex-direction: column-reverse;
283
294
  flex: 1;
284
295
  min-width: var(--chart-column-width);
285
- max-width: calc(var(--chart-column-width) * 2);
286
296
  border-radius: 3px 3px 0 0;
287
297
  overflow: hidden;
288
298
  }
@@ -295,15 +305,15 @@
295
305
  }
296
306
 
297
307
  .chart-stacked-column .column-labels {
308
+ grid-row: 2;
298
309
  display: flex;
299
- gap: 0.25rem;
310
+ gap: clamp(0.375rem, 1.5cqi, 1rem);
300
311
  padding: 0.25rem 0.5rem 0;
301
312
  }
302
313
 
303
314
  .chart-stacked-column .column-label {
304
315
  flex: 1;
305
316
  min-width: var(--chart-column-width);
306
- max-width: calc(var(--chart-column-width) * 2);
307
317
  font-size: 0.7rem;
308
318
  opacity: 0.6;
309
319
  text-align: center;
@@ -332,11 +342,6 @@
332
342
  ========================================================================== */
333
343
 
334
344
  .chart-donut {
335
- display: flex;
336
- flex-direction: row;
337
- flex-wrap: wrap;
338
- align-items: flex-start;
339
- gap: 1rem;
340
345
  --donut-1: var(--chart-color-1);
341
346
  --donut-2: var(--chart-color-2);
342
347
  --donut-3: var(--chart-color-3);
@@ -351,34 +356,50 @@
351
356
  --donut-12: var(--chart-color-12);
352
357
  }
353
358
 
354
- .chart-donut > .chart-title {
355
- flex-basis: 100%;
359
+ .chart-donut .donut-body {
360
+ container-type: inline-size;
361
+ container-name: donut;
362
+ display: flex;
363
+ flex-wrap: wrap;
364
+ align-items: center;
365
+ align-content: center;
366
+ justify-content: center;
367
+ gap: 1rem;
368
+ flex: 1;
356
369
  }
357
370
 
358
371
  .chart-donut .donut-container {
359
372
  position: relative;
360
373
  display: flex;
361
374
  justify-content: center;
375
+ /* Size based on container width, clamped */
376
+ width: clamp(8rem, 80cqi, var(--chart-donut-size));
377
+ aspect-ratio: 1;
378
+ }
379
+
380
+ /* In portrait, legend takes full width to wrap below */
381
+ .chart-donut .donut-body > .chart-legend {
382
+ flex: 0 0 100%;
383
+ justify-content: center;
362
384
  }
363
385
 
364
386
  .chart-donut .donut-ring {
365
- width: var(--chart-donut-size);
366
- height: var(--chart-donut-size);
387
+ width: 100%;
388
+ height: 100%;
367
389
  border-radius: 50%;
368
390
  display: flex;
369
391
  align-items: center;
370
392
  justify-content: center;
371
393
  /* Radial mask punches out the center hole */
372
- --_hole-size: calc((var(--chart-donut-size) - var(--chart-donut-thickness) * 2) / 2);
373
394
  mask-image: radial-gradient(
374
395
  circle at center,
375
- transparent var(--_hole-size),
376
- black var(--_hole-size)
396
+ transparent var(--chart-donut-hole, 30%),
397
+ black var(--chart-donut-hole, 30%)
377
398
  );
378
399
  -webkit-mask-image: radial-gradient(
379
400
  circle at center,
380
- transparent var(--_hole-size),
381
- black var(--_hole-size)
401
+ transparent var(--chart-donut-hole, 30%),
402
+ black var(--chart-donut-hole, 30%)
382
403
  );
383
404
  }
384
405
 
@@ -406,12 +427,30 @@
406
427
  }
407
428
 
408
429
  .chart-donut .chart-legend {
409
- flex-direction: column;
410
- gap: 0.5rem;
430
+ /* Default (portrait): horizontal legend below donut */
431
+ flex-direction: row;
432
+ flex-wrap: wrap;
433
+ justify-content: center;
434
+ gap: 0.5rem 1rem;
411
435
  }
412
436
 
413
437
  .chart-donut .chart-legend-item {
414
- min-width: 10rem;
438
+ min-width: 8rem;
439
+ }
440
+
441
+ /* Wide container: row layout with legend beside donut */
442
+ @container donut (min-width: 24rem) {
443
+ .donut-container,
444
+ .chart-legend {
445
+ flex: 0 0 auto;
446
+ }
447
+
448
+ .chart-legend {
449
+ flex-direction: column;
450
+ flex-wrap: nowrap;
451
+ justify-content: center;
452
+ gap: 0.5rem;
453
+ }
415
454
  }
416
455
 
417
456
  /* Donut legend uses same variables as gradient for consistent overrides */
@@ -428,41 +467,38 @@
428
467
  .chart-donut .chart-color-11 { --color: var(--donut-11, var(--chart-color-11)); }
429
468
  .chart-donut .chart-color-12 { --color: var(--donut-12, var(--chart-color-12)); }
430
469
 
431
- .chart-donut .chart-legend-item .legend-label {
432
- flex: 1;
433
- }
434
470
 
435
471
  /* ==========================================================================
436
472
  Dot Chart (Categorical - columns with dots at Y positions)
437
473
  ========================================================================== */
438
474
 
439
475
  .chart-dot .chart-body {
440
- align-items: stretch;
476
+ display: grid;
477
+ grid-template-columns: auto 1fr;
478
+ grid-template-rows: 1fr auto;
479
+ }
480
+
481
+ .chart-dot .chart-y-axis {
482
+ grid-row: 1;
483
+ grid-column: 1;
441
484
  }
442
485
 
443
486
  .chart-dot .chart-scroll {
444
- flex: 1;
487
+ grid-row: 1 / -1;
488
+ grid-column: 2;
489
+ display: grid;
490
+ grid-template-rows: subgrid;
445
491
  overflow-x: auto;
446
492
  overflow-y: visible;
447
- position: relative;
448
- }
449
-
450
- .chart-dot .chart-scroll::before {
451
- content: '';
452
- position: sticky;
453
- left: 0;
454
- display: block;
455
- height: var(--chart-height);
456
- margin-bottom: calc(-1 * var(--chart-height));
457
- background: var(--chart-bg);
458
- border-radius: 3px;
459
- pointer-events: none;
460
493
  }
461
494
 
462
495
  .chart-dot .dot-chart {
496
+ grid-row: 1;
463
497
  position: relative;
464
- height: var(--chart-height);
498
+ min-height: var(--chart-height);
465
499
  box-sizing: border-box;
500
+ background: var(--chart-bg);
501
+ border-radius: 3px;
466
502
  }
467
503
 
468
504
  /* Inner field sized to content area - dots position relative to this */
@@ -501,6 +537,7 @@
501
537
  }
502
538
 
503
539
  .chart-dot .dot-labels {
540
+ grid-row: 2;
504
541
  display: flex;
505
542
  gap: 6px;
506
543
  padding: 0 0.5rem;
@@ -545,7 +582,8 @@
545
582
 
546
583
  .chart-scatter .dot-area {
547
584
  position: relative;
548
- height: var(--chart-height);
585
+ flex: 1;
586
+ min-height: var(--chart-height);
549
587
  background: var(--chart-bg);
550
588
  border-radius: 3px;
551
589
  box-sizing: border-box;
@@ -684,13 +722,12 @@
684
722
  }
685
723
 
686
724
  .chart-animate .donut-ring {
687
- --_hole-size: calc((var(--chart-donut-size) - var(--chart-donut-thickness) * 2) / 2);
688
725
  mask-image:
689
- radial-gradient(circle at center, transparent var(--_hole-size), black var(--_hole-size)),
726
+ radial-gradient(circle at center, transparent var(--chart-donut-hole, 30%), black var(--chart-donut-hole, 30%)),
690
727
  conic-gradient(from 0deg, black var(--donut-reveal), transparent var(--donut-reveal));
691
728
  mask-composite: intersect;
692
729
  -webkit-mask-image:
693
- radial-gradient(circle at center, transparent var(--_hole-size), black var(--_hole-size)),
730
+ radial-gradient(circle at center, transparent var(--chart-donut-hole, 30%), black var(--chart-donut-hole, 30%)),
694
731
  conic-gradient(from 0deg, black var(--donut-reveal), transparent var(--donut-reveal));
695
732
  -webkit-mask-composite: source-in;
696
733
  animation: donut-clockwise 0.8s ease-out 0.1s forwards;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eleventy-plugin-uncharted",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
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",
@@ -77,6 +77,9 @@ export function renderDonut(config) {
77
77
  html += `</figcaption>`;
78
78
  }
79
79
 
80
+ // Donut body wrapper (for container queries)
81
+ html += `<div class="donut-body">`;
82
+
80
83
  // Donut visual
81
84
  html += `<div class="donut-container">`;
82
85
  html += `<div class="donut-ring" style="background: ${gradient}"></div>`;
@@ -117,6 +120,8 @@ export function renderDonut(config) {
117
120
  });
118
121
  html += `</ul>`;
119
122
 
123
+ html += `</div>`; // Close donut-body
124
+
120
125
  html += `</figure>`;
121
126
 
122
127
  return html;