@qkix/strapi-plugin-chartkit 0.1.1 → 0.1.2

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.
Files changed (2) hide show
  1. package/README.md +144 -81
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -1,31 +1,107 @@
1
- # @qkix/strapi-plugin-chartkit
2
-
3
- Charts for Strapi v5, as a custom field. The chart is rendered to **SVG on the
4
- server**, so a page carrying twenty of them ships no charting library and runs
5
- no JavaScript to draw them.
1
+ <h1 align="center">Chartkit for Strapi</h1>
2
+
3
+ <p align="center">Charts for Strapi v5, rendered as server-side SVG. Your pages ship <strong>zero client-side JavaScript</strong> to draw them.</p>
4
+
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@qkix/strapi-plugin-chartkit">
7
+ <img alt="npm version" src="https://img.shields.io/npm/v/@qkix/strapi-plugin-chartkit.svg" />
8
+ </a>
9
+ <a href="https://www.npmjs.com/package/@qkix/strapi-plugin-chartkit">
10
+ <img alt="npm downloads" src="https://img.shields.io/npm/dm/@qkix/strapi-plugin-chartkit.svg" />
11
+ </a>
12
+ <a href="https://github.com/qkix/strapi-plugins/blob/main/LICENSE">
13
+ <img alt="license" src="https://img.shields.io/npm/l/@qkix/strapi-plugin-chartkit.svg" />
14
+ </a>
15
+ <a href="https://buymeacoffee.com/qkix">
16
+ <img alt="Buy Me a Coffee" src="https://img.shields.io/badge/Buy%20Me%20a%20Coffee-support-FFDD00?logo=buymeacoffee&logoColor=black" />
17
+ </a>
18
+ </p>
19
+
20
+ <p align="center">
21
+ <img src="https://raw.githubusercontent.com/qkix/strapi-plugins/main/packages/strapi-plugin-chartkit/docs/field.png" alt="A chart in the Strapi edit view" width="720" />
22
+ </p>
6
23
 
7
24
  ```sh
8
25
  npm install @qkix/strapi-plugin-chartkit
9
26
  ```
10
27
 
11
- Add a **Chart** field to a content type, and the edit view gives the author a
12
- data grid, spreadsheet paste, and a live preview.
28
+ Add a **Chart** field to a content type. That's it — no config file, no provider.
29
+
30
+ ## Why server-side SVG
31
+
32
+ Most chart plugins hand the browser a charting library and some JSON, and let it
33
+ draw. That means shipping and executing a charting runtime on every page that
34
+ has a chart, and leaving a hole in the layout until it runs.
35
+
36
+ Chartkit renders the SVG **when the page is built or requested**. The browser
37
+ receives finished markup:
38
+
39
+ - **No runtime.** Nothing to download, parse, or execute.
40
+ - **Nothing to hydrate**, so no layout shift and no flash of empty box.
41
+ - **It scales and prints** — it is vector, not a canvas bitmap.
42
+ - **Screen readers get a real description**: `role="img"` with a `<title>` and
43
+ the description you wrote.
44
+
45
+ ## Every chart type
46
+
47
+ <img src="https://raw.githubusercontent.com/qkix/strapi-plugins/main/packages/strapi-plugin-chartkit/docs/chart-types.png" alt="Bar, grouped, stacked, line, area, pie, donut, gaps and negative values" width="900" />
48
+
49
+ Bar, grouped and stacked bars, line, area and stacked area, pie and donut.
50
+
51
+ Two of those tiles are the details that usually go wrong. A missing reading
52
+ stays a **gap** — never a zero pretending to be a measurement. And negative
53
+ values get a real baseline instead of being flipped or clipped.
54
+
55
+ ## Editing
56
+
57
+ <img src="https://raw.githubusercontent.com/qkix/strapi-plugins/main/packages/strapi-plugin-chartkit/docs/editor.png" alt="The chart editor: live preview, chart settings and a data grid" width="700" />
58
+
59
+ A live preview above a spreadsheet-style grid. **The preview is the real
60
+ renderer** — the same function that draws the published page — so a chart cannot
61
+ look right here and wrong there.
62
+
63
+ The editor opens in a dialog. Cancel genuinely cancels: it edits a draft and
64
+ only writes on save.
65
+
66
+ ## Three ways to get the numbers in
13
67
 
14
- ## What it stores
68
+ Most charts already exist as numbers somewhere, and retyping them is the worst
69
+ part of every charting tool.
15
70
 
16
- A `ChartSpec` — the same object the renderers take. There is nothing in between
17
- the field and the page:
71
+ <img src="https://raw.githubusercontent.com/qkix/strapi-plugins/main/packages/strapi-plugin-chartkit/docs/paste.png" alt="Pasting a semicolon-separated spreadsheet, with the parse summary shown before anything is replaced" width="700" />
72
+
73
+ **Paste from a spreadsheet.** Copy a range out of Sheets or Excel and paste it.
74
+
75
+ | Input | Read as |
76
+ | ------------------------- | ------------------------------------- |
77
+ | tab, comma or semicolon | detected per paste |
78
+ | `1.234,50` and `1,234.50` | 1234.5 either way |
79
+ | `€1 234,50` | 1234.5 — currency and spaces stripped |
80
+ | `"North, inland"` | one cell; a quoted delimiter survives |
81
+ | `n/a`, `—`, empty | a **gap**, never a zero |
82
+
83
+ It shows **what it parsed before replacing anything** — above, four categories,
84
+ two series, and one unreadable cell called out. The parser has to guess whether
85
+ the first row is a header, and a wrong guess that silently overwrites your data
86
+ is far worse than one you can cancel.
87
+
88
+ **From the Media Library.** Pick a `.csv`, `.tsv` or `.txt` you already
89
+ uploaded. Anything else is refused before it is fetched — handing a PDF to a CSV
90
+ parser produces a confident table of nonsense.
91
+
92
+ **By hand**, in the grid.
93
+
94
+ ## Rendering it
95
+
96
+ The field stores a `ChartSpec` — the same object the renderers take. Nothing
97
+ sits in between:
18
98
 
19
99
  ```tsx
20
100
  import { Chart } from '@qkix/chartkit-react-renderer';
21
101
 
22
- const article = await fetch('/api/articles/1').then((r) => r.json());
23
-
24
- <Chart spec={article.data.chart} locale="en-US" />;
102
+ <Chart spec={article.chart} locale="en-US" />;
25
103
  ```
26
104
 
27
- Astro is the same shape:
28
-
29
105
  ```astro
30
106
  ---
31
107
  import { Chart } from '@qkix/chartkit-astro-renderer';
@@ -34,81 +110,42 @@ import { Chart } from '@qkix/chartkit-astro-renderer';
34
110
  <Chart spec={article.chart} locale="en-US" />
35
111
  ```
36
112
 
37
- Both render to markup at build or request time. Neither sends a runtime.
113
+ Both produce markup at build or request time. Neither ships a runtime.
38
114
 
39
- ## Styling
115
+ ## It takes your theme, including dark mode
40
116
 
41
117
  The chart carries no colors of its own. Series are drawn as
42
- `fill="var(--chart-series-N, currentColor)"` and text inherits the page's font,
43
- so a chart takes the theme of wherever it lands — including class-based dark
44
- mode, which is the reason for hand-written SVG rather than an off-the-shelf SSR
45
- renderer that bakes hex values into the markup.
118
+ `fill="var(--chart-series-N, currentColor)"` and text inherits the page font, so
119
+ a chart looks like it belongs wherever it lands:
46
120
 
47
121
  ```css
48
122
  :root {
49
123
  --chart-series-1: #4945ff;
50
- --chart-series-2: #66b7f1;
124
+ --chart-series-2: #f0a500;
51
125
  --chart-axis: #8e8ea9;
52
126
  --chart-text: #32324a;
53
127
  --chart-grid: #eaeaef;
54
128
  }
55
- ```
56
-
57
- The admin preview is deliberately drawn on white with dark text regardless of
58
- the admin's theme, because it is showing what the chart will look like on a page
59
- this plugin knows nothing about.
60
-
61
- ## Field options
62
129
 
63
- | Option | Effect |
64
- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
65
- | **Number formatting locale** | How axis numbers are formatted **in the admin preview** — a BCP 47 tag such as `de-DE`. The front end passes its own at render. |
66
- | **Required** | Standard Strapi validation. |
67
-
68
- ## Three ways to get data in
69
-
70
- The grid is there to type into, but most charts already exist as numbers
71
- somewhere:
72
-
73
- - **Paste from a spreadsheet** — copy a range out of Sheets or Excel and paste.
74
- Tab, comma and semicolon are all detected; `1.234,5` and `1,234.5` both read
75
- as 1234.5; `n/a` and blanks become **gaps, not zeroes**.
76
- - **From the Media Library** — pick a `.csv`, `.tsv` or `.txt` already uploaded.
77
- - **By hand** — add categories and series in the grid.
78
-
79
- Paste and import both show **what was parsed before replacing anything**. The
80
- parser has to guess whether the first row is a header, and a wrong guess that
81
- silently overwrites an author's data is far worse than one they can cancel.
82
-
83
- ## The editor opens in a dialog
84
-
85
- Rather than sitting inline. The editing surface is a preview plus a grid plus a
86
- row of settings — most of a screen, given to a field the author is usually
87
- scrolling past on their way to the rest of the form. Clicking the preview or
88
- **Edit chart** opens it; **Cancel** genuinely cancels, because the dialog edits a
89
- draft and only writes on save.
90
-
91
- A field nobody has filled in shows an empty state rather than writing a starter
92
- chart into the document. Opening an entry must not be enough to mark it dirty.
93
-
94
- ## Old charts, and charts that are not charts
130
+ [data-theme='dark'] {
131
+ --chart-text: #ffffff;
132
+ --chart-grid: #32324a;
133
+ }
134
+ ```
95
135
 
96
- The field **migrates a spec on the way in**, so an author who opens a chart saved
97
- against an older schema edits and saves the current shape. Pages stay correct in
98
- the meantime on their own: `renderChart` migrates in memory too, so nothing has
99
- to be resaved for a site to keep working.
136
+ This is the reason the SVG is hand-written rather than produced by an existing
137
+ SSR chart renderer. The obvious candidate, ECharts in SSR mode, writes its
138
+ palette into the markup as literal hex values — which makes class-based dark
139
+ mode impossible without post-processing the output.
100
140
 
101
- If the field holds something that is not a readable chart — a value written by an
102
- import script, or a field that used to be a different type — it says so and goes
103
- **read-only**. Showing the usual "create a chart" prompt over data that exists
104
- would be an offer to overwrite it.
141
+ ## Also a block, if you use Better Blocks
105
142
 
106
- ## Also available as a block
143
+ <img src="https://raw.githubusercontent.com/qkix/strapi-plugins/main/packages/strapi-plugin-chartkit/docs/block.png" alt="A chart block inside a Better Blocks rich-text document" width="700" />
107
144
 
108
- Chartkit is two surfaces over one editor. If you use
109
- [Better Blocks](https://www.npmjs.com/package/@qkix/strapi-plugin-better-blocks),
110
- charts can live inside a rich-text document as a block instead of, or as well
111
- as, in a field of their own. Register it from your app's `src/admin/app.tsx`:
145
+ Charts can live inside a rich-text document instead of, or as well as, in a
146
+ field of their own. With
147
+ [Better Blocks](https://www.npmjs.com/package/@qkix/strapi-plugin-better-blocks)
148
+ installed, that is one line in `src/admin/app.tsx`:
112
149
 
113
150
  ```ts
114
151
  import { registerBlock } from '@qkix/strapi-plugin-better-blocks/strapi-admin';
@@ -125,15 +162,41 @@ The front end needs its own half — `chartBlockPlugin` from whichever renderer
125
162
  you use — or a chart authored in a document is stored correctly and drawn as
126
163
  nothing.
127
164
 
165
+ ## Field options
166
+
167
+ | Option | Effect |
168
+ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
169
+ | **Number formatting locale** | How axis numbers are formatted **in the admin preview** — a BCP 47 tag such as `de-DE`. The front end passes its own at render. |
170
+ | **Required** | Standard Strapi validation. |
171
+
172
+ ## Old charts stay working
173
+
174
+ The spec is versioned, and the field **migrates on read**, so opening a chart
175
+ saved against an older schema edits and saves the current shape. Nothing has to
176
+ be resaved for a site to keep working: `renderChart` migrates in memory too.
177
+
178
+ If a field holds something that is not a readable chart — a value from an import
179
+ script, or a field that used to be a different type — it says so and goes
180
+ **read-only** rather than offering to overwrite it.
181
+
128
182
  ## Packages
129
183
 
130
- | Package | For |
131
- | ---------------------------------------------------------------------------------------------- | -------------------------------------------- |
132
- | [`@qkix/strapi-plugin-chartkit`](https://www.npmjs.com/package/@qkix/strapi-plugin-chartkit) | this plugin — the field in the Strapi admin |
133
- | [`@qkix/chartkit-core`](https://www.npmjs.com/package/@qkix/chartkit-core) | the spec, the validator and the SVG renderer |
134
- | [`@qkix/chartkit-react-renderer`](https://www.npmjs.com/package/@qkix/chartkit-react-renderer) | rendering a stored chart in React / Next.js |
135
- | [`@qkix/chartkit-astro-renderer`](https://www.npmjs.com/package/@qkix/chartkit-astro-renderer) | rendering a stored chart in Astro |
136
- | [`@qkix/chartkit-editor`](https://www.npmjs.com/package/@qkix/chartkit-editor) | the editing surface, if you are embedding it |
184
+ | Package | For |
185
+ | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
186
+ | [`@qkix/strapi-plugin-chartkit`](https://www.npmjs.com/package/@qkix/strapi-plugin-chartkit) | this plugin — the field in the Strapi admin |
187
+ | [`@qkix/chartkit-core`](https://www.npmjs.com/package/@qkix/chartkit-core) | the spec, the validator and the SVG renderer. No dependencies. |
188
+ | [`@qkix/chartkit-react-renderer`](https://www.npmjs.com/package/@qkix/chartkit-react-renderer) | rendering a stored chart in React / Next.js |
189
+ | [`@qkix/chartkit-astro-renderer`](https://www.npmjs.com/package/@qkix/chartkit-astro-renderer) | rendering a stored chart in Astro |
190
+ | [`@qkix/chartkit-editor`](https://www.npmjs.com/package/@qkix/chartkit-editor) | the editing surface, and the ready-made block |
191
+
192
+ ## Not there yet
193
+
194
+ Being honest about the edges: no time axes, no tooltips or other
195
+ interactivity, and no per-chart color overrides — palettes are set in your site's
196
+ CSS. Data is stored with the chart rather than queried from a collection.
197
+
198
+ Issues and ideas welcome at
199
+ [qkix/strapi-plugins](https://github.com/qkix/strapi-plugins/issues).
137
200
 
138
201
  ## License
139
202
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qkix/strapi-plugin-chartkit",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Charts for Strapi v5, rendered as server-side SVG with no client-side JavaScript",
5
5
  "strapi": {
6
6
  "kind": "plugin",
@@ -43,8 +43,8 @@
43
43
  "dist"
44
44
  ],
45
45
  "dependencies": {
46
- "@qkix/chartkit-editor": "^0.1.2",
47
- "@qkix/chartkit-core": "^0.2.0"
46
+ "@qkix/chartkit-core": "^0.2.0",
47
+ "@qkix/chartkit-editor": "^0.1.2"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@strapi/sdk-plugin": "^5.3.2",
@@ -59,8 +59,8 @@
59
59
  "styled-components": "^6.1.17",
60
60
  "typescript": "^5.8.3",
61
61
  "vitest": "^3.2.4",
62
- "@qkix/eslint-config": "0.0.0",
63
- "@qkix/tsconfig": "0.0.0"
62
+ "@qkix/tsconfig": "0.0.0",
63
+ "@qkix/eslint-config": "0.0.0"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "@strapi/admin": "^5.0.0",