eleventy-plugin-uncharted 0.2.1 → 0.3.1

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,48 @@
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
+ gap: 1rem;
367
+ flex: 1;
356
368
  }
357
369
 
358
370
  .chart-donut .donut-container {
359
371
  position: relative;
360
372
  display: flex;
361
373
  justify-content: center;
374
+ /* Size based on container width, clamped */
375
+ width: clamp(8rem, 80cqi, var(--chart-donut-size));
376
+ aspect-ratio: 1;
377
+ }
378
+
379
+ /* In portrait, legend takes full width to wrap below */
380
+ .chart-donut .donut-body > .chart-legend {
381
+ flex: 0 0 100%;
362
382
  }
363
383
 
364
384
  .chart-donut .donut-ring {
365
- width: var(--chart-donut-size);
366
- height: var(--chart-donut-size);
385
+ width: 100%;
386
+ height: 100%;
367
387
  border-radius: 50%;
368
388
  display: flex;
369
389
  align-items: center;
370
390
  justify-content: center;
371
391
  /* Radial mask punches out the center hole */
372
- --_hole-size: calc((var(--chart-donut-size) - var(--chart-donut-thickness) * 2) / 2);
373
392
  mask-image: radial-gradient(
374
393
  circle at center,
375
- transparent var(--_hole-size),
376
- black var(--_hole-size)
394
+ transparent var(--chart-donut-hole, 30%),
395
+ black var(--chart-donut-hole, 30%)
377
396
  );
378
397
  -webkit-mask-image: radial-gradient(
379
398
  circle at center,
380
- transparent var(--_hole-size),
381
- black var(--_hole-size)
399
+ transparent var(--chart-donut-hole, 30%),
400
+ black var(--chart-donut-hole, 30%)
382
401
  );
383
402
  }
384
403
 
@@ -406,12 +425,29 @@
406
425
  }
407
426
 
408
427
  .chart-donut .chart-legend {
409
- flex-direction: column;
410
- gap: 0.5rem;
428
+ /* Default (portrait): horizontal legend below donut */
429
+ flex-direction: row;
430
+ flex-wrap: wrap;
431
+ gap: 0.5rem 1rem;
411
432
  }
412
433
 
413
434
  .chart-donut .chart-legend-item {
414
- min-width: 10rem;
435
+ min-width: 8rem;
436
+ }
437
+
438
+ /* Wide container: row layout with legend beside donut */
439
+ @container donut (min-width: 24rem) {
440
+ .donut-container,
441
+ .chart-donut .donut-body > .chart-legend {
442
+ flex: 0 0 auto;
443
+ }
444
+
445
+ .chart-donut .donut-body > .chart-legend {
446
+ flex-direction: column;
447
+ flex-wrap: nowrap;
448
+ justify-content: center;
449
+ gap: 0.5rem;
450
+ }
415
451
  }
416
452
 
417
453
  /* Donut legend uses same variables as gradient for consistent overrides */
@@ -428,41 +464,38 @@
428
464
  .chart-donut .chart-color-11 { --color: var(--donut-11, var(--chart-color-11)); }
429
465
  .chart-donut .chart-color-12 { --color: var(--donut-12, var(--chart-color-12)); }
430
466
 
431
- .chart-donut .chart-legend-item .legend-label {
432
- flex: 1;
433
- }
434
467
 
435
468
  /* ==========================================================================
436
469
  Dot Chart (Categorical - columns with dots at Y positions)
437
470
  ========================================================================== */
438
471
 
439
472
  .chart-dot .chart-body {
440
- align-items: stretch;
473
+ display: grid;
474
+ grid-template-columns: auto 1fr;
475
+ grid-template-rows: 1fr auto;
476
+ }
477
+
478
+ .chart-dot .chart-y-axis {
479
+ grid-row: 1;
480
+ grid-column: 1;
441
481
  }
442
482
 
443
483
  .chart-dot .chart-scroll {
444
- flex: 1;
484
+ grid-row: 1 / -1;
485
+ grid-column: 2;
486
+ display: grid;
487
+ grid-template-rows: subgrid;
445
488
  overflow-x: auto;
446
489
  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
490
  }
461
491
 
462
492
  .chart-dot .dot-chart {
493
+ grid-row: 1;
463
494
  position: relative;
464
- height: var(--chart-height);
495
+ min-height: var(--chart-height);
465
496
  box-sizing: border-box;
497
+ background: var(--chart-bg);
498
+ border-radius: 3px;
466
499
  }
467
500
 
468
501
  /* Inner field sized to content area - dots position relative to this */
@@ -501,6 +534,7 @@
501
534
  }
502
535
 
503
536
  .chart-dot .dot-labels {
537
+ grid-row: 2;
504
538
  display: flex;
505
539
  gap: 6px;
506
540
  padding: 0 0.5rem;
@@ -545,7 +579,8 @@
545
579
 
546
580
  .chart-scatter .dot-area {
547
581
  position: relative;
548
- height: var(--chart-height);
582
+ flex: 1;
583
+ min-height: var(--chart-height);
549
584
  background: var(--chart-bg);
550
585
  border-radius: 3px;
551
586
  box-sizing: border-box;
@@ -684,13 +719,12 @@
684
719
  }
685
720
 
686
721
  .chart-animate .donut-ring {
687
- --_hole-size: calc((var(--chart-donut-size) - var(--chart-donut-thickness) * 2) / 2);
688
722
  mask-image:
689
- radial-gradient(circle at center, transparent var(--_hole-size), black var(--_hole-size)),
723
+ radial-gradient(circle at center, transparent var(--chart-donut-hole, 30%), black var(--chart-donut-hole, 30%)),
690
724
  conic-gradient(from 0deg, black var(--donut-reveal), transparent var(--donut-reveal));
691
725
  mask-composite: intersect;
692
726
  -webkit-mask-image:
693
- radial-gradient(circle at center, transparent var(--_hole-size), black var(--_hole-size)),
727
+ radial-gradient(circle at center, transparent var(--chart-donut-hole, 30%), black var(--chart-donut-hole, 30%)),
694
728
  conic-gradient(from 0deg, black var(--donut-reveal), transparent var(--donut-reveal));
695
729
  -webkit-mask-composite: source-in;
696
730
  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.1",
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;