create-ncblock 0.0.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 +49 -0
- package/bin/cli.js +33 -0
- package/package.json +25 -0
- package/scripts/init.ts +527 -0
- package/scripts/scaffold-assets/AGENTS.md +65 -0
- package/scripts/utils/templates.ts +293 -0
- package/sdk-version.json +1 -0
- package/templates/debug/README.md +36 -0
- package/templates/debug/_gitignore +2 -0
- package/templates/debug/custom_blocks.json +9 -0
- package/templates/debug/dist/assets/index-Cet2SsjS.css +2 -0
- package/templates/debug/dist/assets/index-DAzv_fuh.js +9 -0
- package/templates/debug/dist/custom_blocks.json +9 -0
- package/templates/debug/dist/index.html +16 -0
- package/templates/debug/index.html +15 -0
- package/templates/debug/node_modules/.bin/browserslist +21 -0
- package/templates/debug/node_modules/.bin/esbuild +21 -0
- package/templates/debug/node_modules/.bin/jiti +21 -0
- package/templates/debug/node_modules/.bin/rollup +21 -0
- package/templates/debug/node_modules/.bin/tsc +21 -0
- package/templates/debug/node_modules/.bin/tsserver +21 -0
- package/templates/debug/node_modules/.bin/tsx +21 -0
- package/templates/debug/node_modules/.bin/vite +21 -0
- package/templates/debug/node_modules/.vite/deps/_metadata.json +50 -0
- package/templates/debug/node_modules/.vite/deps/package.json +3 -0
- package/templates/debug/node_modules/.vite/deps/react-CsV5wVHy.js +770 -0
- package/templates/debug/node_modules/.vite/deps/react-CsV5wVHy.js.map +1 -0
- package/templates/debug/node_modules/.vite/deps/react-dom.js +185 -0
- package/templates/debug/node_modules/.vite/deps/react-dom.js.map +1 -0
- package/templates/debug/node_modules/.vite/deps/react-dom_client.js +14384 -0
- package/templates/debug/node_modules/.vite/deps/react-dom_client.js.map +1 -0
- package/templates/debug/node_modules/.vite/deps/react.js +2 -0
- package/templates/debug/node_modules/.vite/deps/react_jsx-dev-runtime.js +204 -0
- package/templates/debug/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +1 -0
- package/templates/debug/node_modules/.vite/deps/react_jsx-runtime.js +208 -0
- package/templates/debug/node_modules/.vite/deps/react_jsx-runtime.js.map +1 -0
- package/templates/debug/node_modules/.vite/deps/valibot.js +6623 -0
- package/templates/debug/node_modules/.vite/deps/valibot.js.map +1 -0
- package/templates/debug/node_modules/.vite-temp/vite.config.ts.timestamp-1778623720803-0bcf523a67aa8.mjs +15 -0
- package/templates/debug/package.json +30 -0
- package/templates/debug/src/index.css +62 -0
- package/templates/debug/src/index.tsx +1963 -0
- package/templates/debug/tsconfig.json +17 -0
- package/templates/debug/vite.config.ts +8 -0
- package/templates/empty/README.md +10 -0
- package/templates/empty/_gitignore +2 -0
- package/templates/empty/custom_blocks.json +12 -0
- package/templates/empty/dist/assets/index-CodJADav.js +9 -0
- package/templates/empty/dist/custom_blocks.json +12 -0
- package/templates/empty/dist/index.html +15 -0
- package/templates/empty/index.html +15 -0
- package/templates/empty/node_modules/.bin/esbuild +21 -0
- package/templates/empty/node_modules/.bin/jiti +21 -0
- package/templates/empty/node_modules/.bin/tsc +21 -0
- package/templates/empty/node_modules/.bin/tsserver +21 -0
- package/templates/empty/node_modules/.bin/tsx +21 -0
- package/templates/empty/node_modules/.bin/vite +21 -0
- package/templates/empty/node_modules/.vite/deps/_metadata.json +50 -0
- package/templates/empty/node_modules/.vite/deps/package.json +3 -0
- package/templates/empty/node_modules/.vite/deps/react-CsV5wVHy.js +770 -0
- package/templates/empty/node_modules/.vite/deps/react-CsV5wVHy.js.map +1 -0
- package/templates/empty/node_modules/.vite/deps/react-dom.js +185 -0
- package/templates/empty/node_modules/.vite/deps/react-dom.js.map +1 -0
- package/templates/empty/node_modules/.vite/deps/react-dom_client.js +14384 -0
- package/templates/empty/node_modules/.vite/deps/react-dom_client.js.map +1 -0
- package/templates/empty/node_modules/.vite/deps/react.js +2 -0
- package/templates/empty/node_modules/.vite/deps/react_jsx-dev-runtime.js +204 -0
- package/templates/empty/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +1 -0
- package/templates/empty/node_modules/.vite/deps/react_jsx-runtime.js +208 -0
- package/templates/empty/node_modules/.vite/deps/react_jsx-runtime.js.map +1 -0
- package/templates/empty/node_modules/.vite/deps/valibot.js +6623 -0
- package/templates/empty/node_modules/.vite/deps/valibot.js.map +1 -0
- package/templates/empty/package.json +28 -0
- package/templates/empty/src/index.tsx +12 -0
- package/templates/empty/tsconfig.json +17 -0
- package/templates/empty/vite.config.ts +7 -0
- package/templates/gantt-chart/node_modules/.bin/tsc +21 -0
- package/templates/gantt-chart/node_modules/.bin/tsserver +21 -0
- package/templates/gantt-chart/node_modules/.bin/vite +21 -0
- package/templates/gantt-chart/node_modules/.vite/deps/_metadata.json +50 -0
- package/templates/gantt-chart/node_modules/.vite/deps/package.json +3 -0
- package/templates/gantt-chart/node_modules/.vite/deps/react-CsV5wVHy.js +770 -0
- package/templates/gantt-chart/node_modules/.vite/deps/react-CsV5wVHy.js.map +1 -0
- package/templates/gantt-chart/node_modules/.vite/deps/react-dom.js +185 -0
- package/templates/gantt-chart/node_modules/.vite/deps/react-dom.js.map +1 -0
- package/templates/gantt-chart/node_modules/.vite/deps/react-dom_client.js +14384 -0
- package/templates/gantt-chart/node_modules/.vite/deps/react-dom_client.js.map +1 -0
- package/templates/gantt-chart/node_modules/.vite/deps/react.js +2 -0
- package/templates/gantt-chart/node_modules/.vite/deps/react_jsx-dev-runtime.js +204 -0
- package/templates/gantt-chart/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +1 -0
- package/templates/gantt-chart/node_modules/.vite/deps/react_jsx-runtime.js +208 -0
- package/templates/gantt-chart/node_modules/.vite/deps/react_jsx-runtime.js.map +1 -0
- package/templates/gantt-chart/node_modules/.vite/deps/valibot.js +6623 -0
- package/templates/gantt-chart/node_modules/.vite/deps/valibot.js.map +1 -0
- package/templates/hello-world/node_modules/.bin/tsc +21 -0
- package/templates/hello-world/node_modules/.bin/tsserver +21 -0
- package/templates/hello-world/node_modules/.bin/vite +21 -0
- package/templates/hello-world/node_modules/.vite/deps/_metadata.json +50 -0
- package/templates/hello-world/node_modules/.vite/deps/package.json +3 -0
- package/templates/hello-world/node_modules/.vite/deps/react-CsV5wVHy.js +770 -0
- package/templates/hello-world/node_modules/.vite/deps/react-CsV5wVHy.js.map +1 -0
- package/templates/hello-world/node_modules/.vite/deps/react-dom.js +185 -0
- package/templates/hello-world/node_modules/.vite/deps/react-dom.js.map +1 -0
- package/templates/hello-world/node_modules/.vite/deps/react-dom_client.js +14384 -0
- package/templates/hello-world/node_modules/.vite/deps/react-dom_client.js.map +1 -0
- package/templates/hello-world/node_modules/.vite/deps/react.js +2 -0
- package/templates/hello-world/node_modules/.vite/deps/react_jsx-dev-runtime.js +204 -0
- package/templates/hello-world/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +1 -0
- package/templates/hello-world/node_modules/.vite/deps/react_jsx-runtime.js +208 -0
- package/templates/hello-world/node_modules/.vite/deps/react_jsx-runtime.js.map +1 -0
- package/templates/hello-world/node_modules/.vite/deps/valibot.js +6623 -0
- package/templates/hello-world/node_modules/.vite/deps/valibot.js.map +1 -0
- package/templates/interactive-resize/node_modules/.bin/tsc +21 -0
- package/templates/interactive-resize/node_modules/.bin/tsserver +21 -0
- package/templates/interactive-resize/node_modules/.bin/vite +21 -0
- package/templates/interactive-resize/node_modules/.vite/deps/_metadata.json +50 -0
- package/templates/interactive-resize/node_modules/.vite/deps/package.json +3 -0
- package/templates/interactive-resize/node_modules/.vite/deps/react-CsV5wVHy.js +770 -0
- package/templates/interactive-resize/node_modules/.vite/deps/react-CsV5wVHy.js.map +1 -0
- package/templates/interactive-resize/node_modules/.vite/deps/react-dom.js +185 -0
- package/templates/interactive-resize/node_modules/.vite/deps/react-dom.js.map +1 -0
- package/templates/interactive-resize/node_modules/.vite/deps/react-dom_client.js +14384 -0
- package/templates/interactive-resize/node_modules/.vite/deps/react-dom_client.js.map +1 -0
- package/templates/interactive-resize/node_modules/.vite/deps/react.js +2 -0
- package/templates/interactive-resize/node_modules/.vite/deps/react_jsx-dev-runtime.js +204 -0
- package/templates/interactive-resize/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +1 -0
- package/templates/interactive-resize/node_modules/.vite/deps/react_jsx-runtime.js +208 -0
- package/templates/interactive-resize/node_modules/.vite/deps/react_jsx-runtime.js.map +1 -0
- package/templates/interactive-resize/node_modules/.vite/deps/valibot.js +6623 -0
- package/templates/interactive-resize/node_modules/.vite/deps/valibot.js.map +1 -0
- package/templates/org-chart/node_modules/.bin/tsc +21 -0
- package/templates/org-chart/node_modules/.bin/tsserver +21 -0
- package/templates/org-chart/node_modules/.bin/vite +21 -0
- package/templates/org-chart/node_modules/.vite/deps/_metadata.json +50 -0
- package/templates/org-chart/node_modules/.vite/deps/package.json +3 -0
- package/templates/org-chart/node_modules/.vite/deps/react-CsV5wVHy.js +770 -0
- package/templates/org-chart/node_modules/.vite/deps/react-CsV5wVHy.js.map +1 -0
- package/templates/org-chart/node_modules/.vite/deps/react-dom.js +185 -0
- package/templates/org-chart/node_modules/.vite/deps/react-dom.js.map +1 -0
- package/templates/org-chart/node_modules/.vite/deps/react-dom_client.js +14384 -0
- package/templates/org-chart/node_modules/.vite/deps/react-dom_client.js.map +1 -0
- package/templates/org-chart/node_modules/.vite/deps/react.js +2 -0
- package/templates/org-chart/node_modules/.vite/deps/react_jsx-dev-runtime.js +204 -0
- package/templates/org-chart/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +1 -0
- package/templates/org-chart/node_modules/.vite/deps/react_jsx-runtime.js +208 -0
- package/templates/org-chart/node_modules/.vite/deps/react_jsx-runtime.js.map +1 -0
- package/templates/org-chart/node_modules/.vite/deps/valibot.js +6623 -0
- package/templates/org-chart/node_modules/.vite/deps/valibot.js.map +1 -0
- package/templates/radar-chart/README.md +55 -0
- package/templates/radar-chart/_gitignore +2 -0
- package/templates/radar-chart/custom_blocks.json +34 -0
- package/templates/radar-chart/dist/assets/index-DOf05oXg.css +2 -0
- package/templates/radar-chart/dist/assets/index-DWpNd1qt.js +9 -0
- package/templates/radar-chart/dist/custom_blocks.json +34 -0
- package/templates/radar-chart/dist/index.html +16 -0
- package/templates/radar-chart/index.html +15 -0
- package/templates/radar-chart/node_modules/.bin/esbuild +21 -0
- package/templates/radar-chart/node_modules/.bin/jiti +21 -0
- package/templates/radar-chart/node_modules/.bin/tsc +21 -0
- package/templates/radar-chart/node_modules/.bin/tsserver +21 -0
- package/templates/radar-chart/node_modules/.bin/tsx +21 -0
- package/templates/radar-chart/node_modules/.bin/vite +21 -0
- package/templates/radar-chart/node_modules/.vite/deps/_metadata.json +50 -0
- package/templates/radar-chart/node_modules/.vite/deps/package.json +3 -0
- package/templates/radar-chart/node_modules/.vite/deps/react-CsV5wVHy.js +770 -0
- package/templates/radar-chart/node_modules/.vite/deps/react-CsV5wVHy.js.map +1 -0
- package/templates/radar-chart/node_modules/.vite/deps/react-dom.js +185 -0
- package/templates/radar-chart/node_modules/.vite/deps/react-dom.js.map +1 -0
- package/templates/radar-chart/node_modules/.vite/deps/react-dom_client.js +14384 -0
- package/templates/radar-chart/node_modules/.vite/deps/react-dom_client.js.map +1 -0
- package/templates/radar-chart/node_modules/.vite/deps/react.js +2 -0
- package/templates/radar-chart/node_modules/.vite/deps/react_jsx-dev-runtime.js +204 -0
- package/templates/radar-chart/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +1 -0
- package/templates/radar-chart/node_modules/.vite/deps/react_jsx-runtime.js +208 -0
- package/templates/radar-chart/node_modules/.vite/deps/react_jsx-runtime.js.map +1 -0
- package/templates/radar-chart/node_modules/.vite/deps/valibot.js +6623 -0
- package/templates/radar-chart/node_modules/.vite/deps/valibot.js.map +1 -0
- package/templates/radar-chart/package.json +30 -0
- package/templates/radar-chart/src/index.css +44 -0
- package/templates/radar-chart/src/index.tsx +531 -0
- package/templates/radar-chart/tsconfig.json +17 -0
- package/templates/radar-chart/vite.config.ts +8 -0
- package/templates/table-view/README.md +43 -0
- package/templates/table-view/_gitignore +2 -0
- package/templates/table-view/custom_blocks.json +9 -0
- package/templates/table-view/dist/assets/index-Bd8u_e4X.js +12 -0
- package/templates/table-view/dist/assets/index-BkZn3aQZ.css +1 -0
- package/templates/table-view/dist/custom_blocks.json +9 -0
- package/templates/table-view/dist/index.html +16 -0
- package/templates/table-view/index.html +15 -0
- package/templates/table-view/node_modules/.bin/esbuild +21 -0
- package/templates/table-view/node_modules/.bin/jiti +21 -0
- package/templates/table-view/node_modules/.bin/rollup +21 -0
- package/templates/table-view/node_modules/.bin/tsc +21 -0
- package/templates/table-view/node_modules/.bin/tsserver +21 -0
- package/templates/table-view/node_modules/.bin/tsx +21 -0
- package/templates/table-view/node_modules/.bin/vite +21 -0
- package/templates/table-view/node_modules/.vite/deps/@tanstack_react-table.js +2809 -0
- package/templates/table-view/node_modules/.vite/deps/@tanstack_react-table.js.map +1 -0
- package/templates/table-view/node_modules/.vite/deps/_metadata.json +56 -0
- package/templates/table-view/node_modules/.vite/deps/package.json +3 -0
- package/templates/table-view/node_modules/.vite/deps/react-D5jdVkJj.js +790 -0
- package/templates/table-view/node_modules/.vite/deps/react-D5jdVkJj.js.map +1 -0
- package/templates/table-view/node_modules/.vite/deps/react-dom.js +185 -0
- package/templates/table-view/node_modules/.vite/deps/react-dom.js.map +1 -0
- package/templates/table-view/node_modules/.vite/deps/react-dom_client.js +14384 -0
- package/templates/table-view/node_modules/.vite/deps/react-dom_client.js.map +1 -0
- package/templates/table-view/node_modules/.vite/deps/react.js +2 -0
- package/templates/table-view/node_modules/.vite/deps/react_jsx-dev-runtime.js +204 -0
- package/templates/table-view/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +1 -0
- package/templates/table-view/node_modules/.vite/deps/react_jsx-runtime.js +208 -0
- package/templates/table-view/node_modules/.vite/deps/react_jsx-runtime.js.map +1 -0
- package/templates/table-view/node_modules/.vite/deps/valibot.js +6623 -0
- package/templates/table-view/node_modules/.vite/deps/valibot.js.map +1 -0
- package/templates/table-view/package.json +31 -0
- package/templates/table-view/src/index.css +256 -0
- package/templates/table-view/src/index.tsx +1814 -0
- package/templates/table-view/src/table-model.ts +663 -0
- package/templates/table-view/tsconfig.json +17 -0
- package/templates/table-view/vite.config.ts +8 -0
- package/templates/us-heatmap/node_modules/.bin/tsc +21 -0
- package/templates/us-heatmap/node_modules/.bin/tsserver +21 -0
- package/templates/us-heatmap/node_modules/.bin/vite +21 -0
- package/templates/us-heatmap/node_modules/.vite/deps/_metadata.json +50 -0
- package/templates/us-heatmap/node_modules/.vite/deps/package.json +3 -0
- package/templates/us-heatmap/node_modules/.vite/deps/react-CsV5wVHy.js +770 -0
- package/templates/us-heatmap/node_modules/.vite/deps/react-CsV5wVHy.js.map +1 -0
- package/templates/us-heatmap/node_modules/.vite/deps/react-dom.js +185 -0
- package/templates/us-heatmap/node_modules/.vite/deps/react-dom.js.map +1 -0
- package/templates/us-heatmap/node_modules/.vite/deps/react-dom_client.js +14384 -0
- package/templates/us-heatmap/node_modules/.vite/deps/react-dom_client.js.map +1 -0
- package/templates/us-heatmap/node_modules/.vite/deps/react.js +2 -0
- package/templates/us-heatmap/node_modules/.vite/deps/react_jsx-dev-runtime.js +204 -0
- package/templates/us-heatmap/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +1 -0
- package/templates/us-heatmap/node_modules/.vite/deps/react_jsx-runtime.js +208 -0
- package/templates/us-heatmap/node_modules/.vite/deps/react_jsx-runtime.js.map +1 -0
- package/templates/us-heatmap/node_modules/.vite/deps/valibot.js +6623 -0
- package/templates/us-heatmap/node_modules/.vite/deps/valibot.js.map +1 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "radar-chart",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"notionCustomTemplate": {
|
|
7
|
+
"title": "Radar Chart",
|
|
8
|
+
"description": "Multi-series chart demo with a fixed numeric schema for mapped collection data.",
|
|
9
|
+
"recommended": false
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"dev": "vite",
|
|
13
|
+
"build": "vite build",
|
|
14
|
+
"typecheck": "tsc --noEmit"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"ncblock": "workspace:*",
|
|
18
|
+
"react": "^19.2.5",
|
|
19
|
+
"react-dom": "^19.2.5"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@tailwindcss/vite": "^4.2.4",
|
|
23
|
+
"@types/react": "^19.2.14",
|
|
24
|
+
"@types/react-dom": "^19.2.3",
|
|
25
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
26
|
+
"tailwindcss": "^4.2.4",
|
|
27
|
+
"typescript": "^6.0.3",
|
|
28
|
+
"vite": "^8.0.10"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
font-family:
|
|
5
|
+
ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica,
|
|
6
|
+
Arial, sans-serif;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
:root,
|
|
10
|
+
[data-theme="light"] {
|
|
11
|
+
--app-bg: var(--color-white);
|
|
12
|
+
--card-bg: var(--color-stone-100);
|
|
13
|
+
--surface-bg: var(--color-white);
|
|
14
|
+
--foreground: var(--color-stone-800);
|
|
15
|
+
--muted: color-mix(in oklab, var(--color-stone-800) 45%, transparent);
|
|
16
|
+
--border: color-mix(in oklab, var(--color-stone-800) 12%, transparent);
|
|
17
|
+
--grid-stroke: color-mix(in oklab, var(--color-stone-800) 12%, transparent);
|
|
18
|
+
--series-1: var(--color-blue-600);
|
|
19
|
+
--series-2: var(--color-red-600);
|
|
20
|
+
--series-3: var(--color-green-600);
|
|
21
|
+
--series-4: var(--color-violet-700);
|
|
22
|
+
--series-5: var(--color-amber-600);
|
|
23
|
+
--series-6: var(--color-cyan-600);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
[data-theme="dark"] {
|
|
27
|
+
--app-bg: var(--color-zinc-900);
|
|
28
|
+
--card-bg: var(--color-zinc-800);
|
|
29
|
+
--surface-bg: var(--color-zinc-900);
|
|
30
|
+
--foreground: var(--color-zinc-200);
|
|
31
|
+
--muted: color-mix(in oklab, var(--color-white) 45%, transparent);
|
|
32
|
+
--border: color-mix(in oklab, var(--color-white) 12%, transparent);
|
|
33
|
+
--grid-stroke: color-mix(in oklab, var(--color-white) 16%, transparent);
|
|
34
|
+
--series-1: var(--color-blue-400);
|
|
35
|
+
--series-2: var(--color-red-400);
|
|
36
|
+
--series-3: var(--color-green-400);
|
|
37
|
+
--series-4: var(--color-violet-400);
|
|
38
|
+
--series-5: var(--color-amber-400);
|
|
39
|
+
--series-6: var(--color-cyan-400);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
body {
|
|
43
|
+
margin: 0;
|
|
44
|
+
}
|
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NotionCustomBlock,
|
|
3
|
+
type NotionDataSourcePage,
|
|
4
|
+
type NotionPageId,
|
|
5
|
+
useDataSource,
|
|
6
|
+
useDataSourceDefinitions,
|
|
7
|
+
useTheme,
|
|
8
|
+
} from "ncblock"
|
|
9
|
+
import React from "react"
|
|
10
|
+
import ReactDOM from "react-dom/client"
|
|
11
|
+
|
|
12
|
+
import "./index.css"
|
|
13
|
+
|
|
14
|
+
type RadarSeries = {
|
|
15
|
+
id: string
|
|
16
|
+
label: string
|
|
17
|
+
color: string
|
|
18
|
+
values: number[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type RadarSchemaAnalysis = {
|
|
22
|
+
labelKey?: string
|
|
23
|
+
missingFields: string[]
|
|
24
|
+
isReady: boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function makeFakeItem(
|
|
28
|
+
id: string,
|
|
29
|
+
properties: NotionDataSourcePage["propertiesByKey"],
|
|
30
|
+
): NotionDataSourcePage {
|
|
31
|
+
return {
|
|
32
|
+
id: id as NotionPageId,
|
|
33
|
+
propertiesById: {},
|
|
34
|
+
propertiesByKey: properties,
|
|
35
|
+
update: async () => ({
|
|
36
|
+
status: "error",
|
|
37
|
+
error: "Sample rows are read-only",
|
|
38
|
+
}),
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const FAKE_ITEMS: NotionDataSourcePage[] = [
|
|
43
|
+
makeFakeItem("engineering", {
|
|
44
|
+
name: "Engineering",
|
|
45
|
+
speed: 82,
|
|
46
|
+
quality: 91,
|
|
47
|
+
focus: 74,
|
|
48
|
+
collaboration: 88,
|
|
49
|
+
execution: 79,
|
|
50
|
+
}),
|
|
51
|
+
makeFakeItem("design", {
|
|
52
|
+
name: "Design",
|
|
53
|
+
speed: 68,
|
|
54
|
+
quality: 84,
|
|
55
|
+
focus: 90,
|
|
56
|
+
collaboration: 77,
|
|
57
|
+
execution: 70,
|
|
58
|
+
}),
|
|
59
|
+
makeFakeItem("product", {
|
|
60
|
+
name: "Product",
|
|
61
|
+
speed: 75,
|
|
62
|
+
quality: 79,
|
|
63
|
+
focus: 86,
|
|
64
|
+
collaboration: 81,
|
|
65
|
+
execution: 83,
|
|
66
|
+
}),
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
const EXPECTED_LABEL_KEYS = ["name", "title"]
|
|
70
|
+
const EXPECTED_DIMENSION_KEYS = [
|
|
71
|
+
"speed",
|
|
72
|
+
"quality",
|
|
73
|
+
"focus",
|
|
74
|
+
"collaboration",
|
|
75
|
+
"execution",
|
|
76
|
+
]
|
|
77
|
+
const SERIES_COLORS = [
|
|
78
|
+
"var(--series-1)",
|
|
79
|
+
"var(--series-2)",
|
|
80
|
+
"var(--series-3)",
|
|
81
|
+
"var(--series-4)",
|
|
82
|
+
"var(--series-5)",
|
|
83
|
+
"var(--series-6)",
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
function isFiniteNumber(value: unknown): value is number {
|
|
87
|
+
return typeof value === "number" && Number.isFinite(value)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function formatDimensionLabel(key: string): string {
|
|
91
|
+
return key.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function getLabelKey(items: NotionDataSourcePage[]): string | undefined {
|
|
95
|
+
for (const key of EXPECTED_LABEL_KEYS) {
|
|
96
|
+
if (items.some(item => typeof item.propertiesByKey[key] === "string")) {
|
|
97
|
+
return key
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return undefined
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function analyzeRadarSchema(
|
|
104
|
+
items: NotionDataSourcePage[],
|
|
105
|
+
): RadarSchemaAnalysis {
|
|
106
|
+
const labelKey = getLabelKey(items)
|
|
107
|
+
const missingFields: string[] = []
|
|
108
|
+
|
|
109
|
+
if (!labelKey) {
|
|
110
|
+
missingFields.push("name (or title)")
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
for (const key of EXPECTED_DIMENSION_KEYS) {
|
|
114
|
+
if (!items.some(item => isFiniteNumber(item.propertiesByKey[key]))) {
|
|
115
|
+
missingFields.push(key)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
labelKey,
|
|
121
|
+
missingFields,
|
|
122
|
+
isReady: missingFields.length === 0,
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function getRoundedMaxValue(
|
|
127
|
+
items: NotionDataSourcePage[],
|
|
128
|
+
keys: string[],
|
|
129
|
+
): number {
|
|
130
|
+
const maxValue = items.reduce((currentMax, item) => {
|
|
131
|
+
return keys.reduce((rowMax, key) => {
|
|
132
|
+
const value = item.propertiesByKey[key]
|
|
133
|
+
return isFiniteNumber(value) ? Math.max(rowMax, value) : rowMax
|
|
134
|
+
}, currentMax)
|
|
135
|
+
}, 0)
|
|
136
|
+
|
|
137
|
+
if (maxValue <= 10) {
|
|
138
|
+
return 10
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (maxValue <= 100) {
|
|
142
|
+
return Math.ceil(maxValue / 10) * 10
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return Math.ceil(maxValue / 25) * 25
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function RadarChart(props: {
|
|
149
|
+
items: NotionDataSourcePage[]
|
|
150
|
+
isUsingFallbackData: boolean
|
|
151
|
+
analysis: RadarSchemaAnalysis
|
|
152
|
+
queryError: string | undefined
|
|
153
|
+
hasMore: boolean
|
|
154
|
+
isLoading: boolean
|
|
155
|
+
onFetchMore: () => void
|
|
156
|
+
}) {
|
|
157
|
+
const {
|
|
158
|
+
items,
|
|
159
|
+
isUsingFallbackData,
|
|
160
|
+
analysis,
|
|
161
|
+
queryError,
|
|
162
|
+
hasMore,
|
|
163
|
+
isLoading,
|
|
164
|
+
onFetchMore,
|
|
165
|
+
} = props
|
|
166
|
+
|
|
167
|
+
const { labelKey } = analysis
|
|
168
|
+
const dimensionKeys = EXPECTED_DIMENSION_KEYS
|
|
169
|
+
const maxValue = React.useMemo(
|
|
170
|
+
() => getRoundedMaxValue(items, dimensionKeys),
|
|
171
|
+
[dimensionKeys, items],
|
|
172
|
+
)
|
|
173
|
+
const chartSize = 520
|
|
174
|
+
const radius = 170
|
|
175
|
+
const levels = 4
|
|
176
|
+
const labelRadius = radius + 34
|
|
177
|
+
const angleStep =
|
|
178
|
+
dimensionKeys.length > 0 ? (Math.PI * 2) / dimensionKeys.length : 0
|
|
179
|
+
|
|
180
|
+
// Center the chart's bounding box (including labels) within the viewBox.
|
|
181
|
+
// The pentagon is asymmetric vertically: with a vertex pointing up, the
|
|
182
|
+
// top vertex sits at -radius from center, but the bottom vertices only
|
|
183
|
+
// reach +radius * sin(54°) ≈ +0.809 * radius. Account for label sizing
|
|
184
|
+
// so the chart looks visually centered.
|
|
185
|
+
const verticalExtents = React.useMemo(() => {
|
|
186
|
+
let topMost = 0
|
|
187
|
+
let bottomMost = 0
|
|
188
|
+
for (let i = 0; i < dimensionKeys.length; i += 1) {
|
|
189
|
+
const angle = -Math.PI / 2 + angleStep * i
|
|
190
|
+
const labelY = Math.sin(angle) * labelRadius
|
|
191
|
+
const isAbove = labelY < -10
|
|
192
|
+
const isBelow = labelY > 10
|
|
193
|
+
const textHalfHeight = 6
|
|
194
|
+
const top = isAbove
|
|
195
|
+
? labelY - textHalfHeight * 2
|
|
196
|
+
: labelY - textHalfHeight
|
|
197
|
+
const bottom = isBelow
|
|
198
|
+
? labelY + textHalfHeight * 2
|
|
199
|
+
: labelY + textHalfHeight
|
|
200
|
+
if (top < topMost) {
|
|
201
|
+
topMost = top
|
|
202
|
+
}
|
|
203
|
+
if (bottom > bottomMost) {
|
|
204
|
+
bottomMost = bottom
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return { topMost, bottomMost }
|
|
208
|
+
}, [angleStep, dimensionKeys.length, labelRadius])
|
|
209
|
+
|
|
210
|
+
const cx = chartSize / 2
|
|
211
|
+
const cy =
|
|
212
|
+
chartSize / 2 - (verticalExtents.topMost + verticalExtents.bottomMost) / 2
|
|
213
|
+
|
|
214
|
+
const series = React.useMemo<RadarSeries[]>(() => {
|
|
215
|
+
return items.map((item, index) => {
|
|
216
|
+
const labelValue = labelKey ? item.propertiesByKey[labelKey] : undefined
|
|
217
|
+
return {
|
|
218
|
+
id: item.id,
|
|
219
|
+
label:
|
|
220
|
+
(typeof labelValue === "string" && labelValue) ||
|
|
221
|
+
`Series ${index + 1}`,
|
|
222
|
+
color: SERIES_COLORS[index % SERIES_COLORS.length],
|
|
223
|
+
values: dimensionKeys.map(key => {
|
|
224
|
+
const value = item.propertiesByKey[key]
|
|
225
|
+
return isFiniteNumber(value) ? value : 0
|
|
226
|
+
}),
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
}, [dimensionKeys, items, labelKey])
|
|
230
|
+
|
|
231
|
+
function getPoint(value: number, index: number) {
|
|
232
|
+
const ratio = Math.max(0, Math.min(1, value / maxValue))
|
|
233
|
+
const angle = -Math.PI / 2 + angleStep * index
|
|
234
|
+
return {
|
|
235
|
+
x: cx + Math.cos(angle) * radius * ratio,
|
|
236
|
+
y: cy + Math.sin(angle) * radius * ratio,
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function getPath(values: number[]) {
|
|
241
|
+
return (
|
|
242
|
+
values
|
|
243
|
+
.map((value, index) => {
|
|
244
|
+
const point = getPoint(value, index)
|
|
245
|
+
return `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`
|
|
246
|
+
})
|
|
247
|
+
.join(" ") + " Z"
|
|
248
|
+
)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<div className="grid gap-5">
|
|
253
|
+
<div className="rounded-xl border border-(--border) bg-(--card-bg) px-4 py-4 text-sm leading-6 text-(--muted)">
|
|
254
|
+
{isUsingFallbackData
|
|
255
|
+
? "Showing fake sample data until a collection is mapped."
|
|
256
|
+
: `Showing ${items.length} row${items.length === 1 ? "" : "s"} from the mapped collection.`}
|
|
257
|
+
{queryError ? ` Query note: ${queryError}` : ""}
|
|
258
|
+
</div>
|
|
259
|
+
|
|
260
|
+
<div className="grid grid-cols-[minmax(0,1fr)_220px] items-start gap-6">
|
|
261
|
+
<div className="overflow-x-auto rounded-2xl border border-(--border) bg-(--surface-bg) p-5">
|
|
262
|
+
<svg
|
|
263
|
+
className="block h-auto min-w-[360px] w-full"
|
|
264
|
+
viewBox={`0 0 ${chartSize} ${chartSize}`}
|
|
265
|
+
>
|
|
266
|
+
{Array.from({ length: levels }, (_, levelIndex) => {
|
|
267
|
+
const level = (levelIndex + 1) / levels
|
|
268
|
+
const points = dimensionKeys
|
|
269
|
+
.map((_, index) => {
|
|
270
|
+
const angle = -Math.PI / 2 + angleStep * index
|
|
271
|
+
const x = cx + Math.cos(angle) * radius * level
|
|
272
|
+
const y = cy + Math.sin(angle) * radius * level
|
|
273
|
+
return `${x},${y}`
|
|
274
|
+
})
|
|
275
|
+
.join(" ")
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<polygon
|
|
279
|
+
key={level}
|
|
280
|
+
points={points}
|
|
281
|
+
fill="none"
|
|
282
|
+
stroke="var(--grid-stroke)"
|
|
283
|
+
strokeWidth={1}
|
|
284
|
+
/>
|
|
285
|
+
)
|
|
286
|
+
})}
|
|
287
|
+
|
|
288
|
+
{dimensionKeys.map((key, index) => {
|
|
289
|
+
const angle = -Math.PI / 2 + angleStep * index
|
|
290
|
+
const cosA = Math.cos(angle)
|
|
291
|
+
const sinA = Math.sin(angle)
|
|
292
|
+
const axisX = cx + cosA * radius
|
|
293
|
+
const axisY = cy + sinA * radius
|
|
294
|
+
const labelX = cx + cosA * labelRadius
|
|
295
|
+
const labelY = cy + sinA * labelRadius
|
|
296
|
+
const horizontalThreshold = 0.15
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<g key={key}>
|
|
300
|
+
<line
|
|
301
|
+
x1={cx}
|
|
302
|
+
y1={cy}
|
|
303
|
+
x2={axisX}
|
|
304
|
+
y2={axisY}
|
|
305
|
+
stroke="var(--grid-stroke)"
|
|
306
|
+
strokeWidth={1}
|
|
307
|
+
/>
|
|
308
|
+
<text
|
|
309
|
+
x={labelX}
|
|
310
|
+
y={labelY}
|
|
311
|
+
fill="var(--foreground)"
|
|
312
|
+
fontSize={12}
|
|
313
|
+
textAnchor={
|
|
314
|
+
Math.abs(cosA) < horizontalThreshold
|
|
315
|
+
? "middle"
|
|
316
|
+
: cosA < 0
|
|
317
|
+
? "end"
|
|
318
|
+
: "start"
|
|
319
|
+
}
|
|
320
|
+
dominantBaseline={
|
|
321
|
+
Math.abs(sinA) < horizontalThreshold
|
|
322
|
+
? "middle"
|
|
323
|
+
: sinA < 0
|
|
324
|
+
? "auto"
|
|
325
|
+
: "hanging"
|
|
326
|
+
}
|
|
327
|
+
>
|
|
328
|
+
{formatDimensionLabel(key)}
|
|
329
|
+
</text>
|
|
330
|
+
</g>
|
|
331
|
+
)
|
|
332
|
+
})}
|
|
333
|
+
|
|
334
|
+
{series.map(seriesItem => (
|
|
335
|
+
<path
|
|
336
|
+
key={seriesItem.id}
|
|
337
|
+
d={getPath(seriesItem.values)}
|
|
338
|
+
fill={seriesItem.color}
|
|
339
|
+
fillOpacity={0.14}
|
|
340
|
+
stroke={seriesItem.color}
|
|
341
|
+
strokeWidth={2}
|
|
342
|
+
/>
|
|
343
|
+
))}
|
|
344
|
+
|
|
345
|
+
{series.flatMap(seriesItem =>
|
|
346
|
+
seriesItem.values.map((value, index) => {
|
|
347
|
+
const point = getPoint(value, index)
|
|
348
|
+
return (
|
|
349
|
+
<circle
|
|
350
|
+
key={`${seriesItem.id}-${dimensionKeys[index]}`}
|
|
351
|
+
cx={point.x}
|
|
352
|
+
cy={point.y}
|
|
353
|
+
r={4}
|
|
354
|
+
fill={seriesItem.color}
|
|
355
|
+
/>
|
|
356
|
+
)
|
|
357
|
+
}),
|
|
358
|
+
)}
|
|
359
|
+
</svg>
|
|
360
|
+
</div>
|
|
361
|
+
|
|
362
|
+
<div className="rounded-2xl border border-(--border) bg-(--card-bg) p-5">
|
|
363
|
+
<div className="mb-3 text-base font-semibold text-(--foreground)">
|
|
364
|
+
Legend
|
|
365
|
+
</div>
|
|
366
|
+
<div className="mb-5 grid gap-2.5">
|
|
367
|
+
{series.map(seriesItem => (
|
|
368
|
+
<div
|
|
369
|
+
key={seriesItem.id}
|
|
370
|
+
className="grid grid-cols-[12px_minmax(0,1fr)] items-center gap-2.5"
|
|
371
|
+
>
|
|
372
|
+
<div
|
|
373
|
+
className="h-3 w-3 rounded-full"
|
|
374
|
+
style={{
|
|
375
|
+
background: seriesItem.color,
|
|
376
|
+
}}
|
|
377
|
+
/>
|
|
378
|
+
<div className="text-sm text-(--foreground)">
|
|
379
|
+
{seriesItem.label}
|
|
380
|
+
</div>
|
|
381
|
+
</div>
|
|
382
|
+
))}
|
|
383
|
+
</div>
|
|
384
|
+
|
|
385
|
+
<div className="text-[13px] leading-[1.7] text-(--muted)">
|
|
386
|
+
<div>Max scale: {maxValue}</div>
|
|
387
|
+
<div>Label field: {labelKey ?? "name"}</div>
|
|
388
|
+
<div>Dimensions: {dimensionKeys.join(", ")}</div>
|
|
389
|
+
</div>
|
|
390
|
+
|
|
391
|
+
{hasMore ? (
|
|
392
|
+
<button
|
|
393
|
+
onClick={onFetchMore}
|
|
394
|
+
disabled={isLoading}
|
|
395
|
+
className="mt-4 w-full rounded-lg border border-(--border) bg-(--surface-bg) px-3 py-2.5 text-(--foreground)"
|
|
396
|
+
style={{ cursor: isLoading ? "progress" : "pointer" }}
|
|
397
|
+
>
|
|
398
|
+
{isLoading ? "Loading..." : "Fetch more"}
|
|
399
|
+
</button>
|
|
400
|
+
) : null}
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function SetupHint(props: {
|
|
408
|
+
missingFields: string[]
|
|
409
|
+
dataSourceKey: string
|
|
410
|
+
isUsingFallbackData: boolean
|
|
411
|
+
}) {
|
|
412
|
+
const { missingFields, dataSourceKey, isUsingFallbackData } = props
|
|
413
|
+
|
|
414
|
+
return (
|
|
415
|
+
<div className="mb-6 rounded-[14px] border border-(--border) bg-(--card-bg) p-5">
|
|
416
|
+
<div className="mb-2 text-lg font-semibold text-(--foreground)">
|
|
417
|
+
Set up the source database
|
|
418
|
+
</div>
|
|
419
|
+
<div className="mb-3 text-sm leading-[1.7] text-(--muted)">
|
|
420
|
+
This demo is hardcoded to one radar schema. Map a data source with key{" "}
|
|
421
|
+
<code>{dataSourceKey}</code> and create these exact semantic fields:
|
|
422
|
+
</div>
|
|
423
|
+
<div className="mb-3 text-sm leading-[1.8] text-(--foreground)">
|
|
424
|
+
<div>
|
|
425
|
+
<code>name</code> or <code>title</code> as the row label
|
|
426
|
+
</div>
|
|
427
|
+
<div>
|
|
428
|
+
<code>speed</code>, <code>quality</code>, <code>focus</code>,{" "}
|
|
429
|
+
<code>collaboration</code>, <code>execution</code> as number columns
|
|
430
|
+
</div>
|
|
431
|
+
</div>
|
|
432
|
+
{missingFields.length > 0 ? (
|
|
433
|
+
<div className="text-sm leading-[1.7] text-(--muted)">
|
|
434
|
+
Missing right now: <code>{missingFields.join(", ")}</code>
|
|
435
|
+
</div>
|
|
436
|
+
) : null}
|
|
437
|
+
<div className="mt-3 text-sm leading-[1.7] text-(--muted)">
|
|
438
|
+
{isUsingFallbackData
|
|
439
|
+
? "Showing built-in sample data below until the mapped collection matches this schema."
|
|
440
|
+
: "Showing your mapped collection below."}
|
|
441
|
+
</div>
|
|
442
|
+
</div>
|
|
443
|
+
)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function App() {
|
|
447
|
+
const theme = useTheme()
|
|
448
|
+
const dataSources = useDataSourceDefinitions()
|
|
449
|
+
const activeDataSourceKey = dataSources[0]?.key ?? "default"
|
|
450
|
+
const query = useDataSource(activeDataSourceKey)
|
|
451
|
+
const colorTheme = theme === "dark" ? "dark" : "light"
|
|
452
|
+
const mappedAnalysis = analyzeRadarSchema(query.items)
|
|
453
|
+
const isUsingFallbackData = !mappedAnalysis.isReady
|
|
454
|
+
const items = isUsingFallbackData ? FAKE_ITEMS : query.items
|
|
455
|
+
const analysis = isUsingFallbackData
|
|
456
|
+
? analyzeRadarSchema(FAKE_ITEMS)
|
|
457
|
+
: mappedAnalysis
|
|
458
|
+
|
|
459
|
+
return (
|
|
460
|
+
<div
|
|
461
|
+
data-theme={colorTheme}
|
|
462
|
+
className="bg-(--app-bg) p-8 text-(--foreground)"
|
|
463
|
+
>
|
|
464
|
+
<div className="mb-6">
|
|
465
|
+
<h1 className="mb-2 text-[32px] font-bold leading-tight tracking-[-0.03em]">
|
|
466
|
+
Radar Chart
|
|
467
|
+
</h1>
|
|
468
|
+
<p className="m-0 max-w-[760px] text-[15px] leading-6 text-(--muted)">
|
|
469
|
+
Each row in the mapped collection becomes one spider-chart polygon.
|
|
470
|
+
One text field is used for the legend, and this demo expects one fixed
|
|
471
|
+
set of score columns.
|
|
472
|
+
</p>
|
|
473
|
+
</div>
|
|
474
|
+
|
|
475
|
+
<div className="mb-6 grid grid-cols-[repeat(auto-fit,minmax(220px,1fr))] gap-5">
|
|
476
|
+
{[
|
|
477
|
+
{
|
|
478
|
+
label: "Active data source",
|
|
479
|
+
value: activeDataSourceKey,
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
label: "Rows",
|
|
483
|
+
value: String(items.length),
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
label: "Mode",
|
|
487
|
+
value: isUsingFallbackData
|
|
488
|
+
? "Sample preview data"
|
|
489
|
+
: "Mapped collection",
|
|
490
|
+
},
|
|
491
|
+
].map(card => (
|
|
492
|
+
<div
|
|
493
|
+
key={card.label}
|
|
494
|
+
className="rounded-[14px] border border-(--border) bg-(--card-bg) p-[18px]"
|
|
495
|
+
>
|
|
496
|
+
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.04em] text-(--muted)">
|
|
497
|
+
{card.label}
|
|
498
|
+
</div>
|
|
499
|
+
<div className="text-lg font-semibold text-(--foreground)">
|
|
500
|
+
{card.value}
|
|
501
|
+
</div>
|
|
502
|
+
</div>
|
|
503
|
+
))}
|
|
504
|
+
</div>
|
|
505
|
+
|
|
506
|
+
{isUsingFallbackData ? (
|
|
507
|
+
<SetupHint
|
|
508
|
+
missingFields={mappedAnalysis.missingFields}
|
|
509
|
+
dataSourceKey={activeDataSourceKey}
|
|
510
|
+
isUsingFallbackData={isUsingFallbackData}
|
|
511
|
+
/>
|
|
512
|
+
) : null}
|
|
513
|
+
|
|
514
|
+
<RadarChart
|
|
515
|
+
items={items}
|
|
516
|
+
isUsingFallbackData={isUsingFallbackData}
|
|
517
|
+
analysis={analysis}
|
|
518
|
+
queryError={query.error}
|
|
519
|
+
hasMore={query.hasMore}
|
|
520
|
+
isLoading={query.isLoading}
|
|
521
|
+
onFetchMore={query.fetchMore}
|
|
522
|
+
/>
|
|
523
|
+
</div>
|
|
524
|
+
)
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
528
|
+
<NotionCustomBlock>
|
|
529
|
+
<App />
|
|
530
|
+
</NotionCustomBlock>,
|
|
531
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"noUnusedLocals": true,
|
|
8
|
+
"noUnusedParameters": true,
|
|
9
|
+
"types": ["vite/client"],
|
|
10
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "react-jsx"
|
|
15
|
+
},
|
|
16
|
+
"include": ["src", "vite.config.ts"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import tailwindcss from "@tailwindcss/vite"
|
|
2
|
+
import react from "@vitejs/plugin-react"
|
|
3
|
+
import { notionCustomBlock } from "ncblock/vite"
|
|
4
|
+
import { defineConfig } from "vite"
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
plugins: [react(), tailwindcss(), notionCustomBlock()],
|
|
8
|
+
})
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# {{name}}
|
|
2
|
+
|
|
3
|
+
A [Notion custom view](https://developers.notion.com) block.
|
|
4
|
+
|
|
5
|
+
## Development
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run dev # Start Vite dev server
|
|
9
|
+
npm run build # Build to dist/
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
From the repo root you can also run just this template with:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm --filter table-view dev
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
If you run `pnpm run dev` at the repo root, every template starts at once and
|
|
19
|
+
`table-view` is available at `http://localhost:9882`.
|
|
20
|
+
|
|
21
|
+
## Project structure
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
src/
|
|
25
|
+
index.tsx # TanStack Table-powered custom view
|
|
26
|
+
index.css # Tailwind CSS entrypoint
|
|
27
|
+
index.html # Vite entry HTML
|
|
28
|
+
custom_blocks.json # Manifest declaring required data sources (served at runtime)
|
|
29
|
+
dist/ # Built output: index.html + assets/ + custom_blocks.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This template includes Tailwind by default and renders every supported
|
|
33
|
+
`ncblock` value shape: text, numbers, booleans, dates,
|
|
34
|
+
string arrays, and relations. It also includes search, column visibility
|
|
35
|
+
controls, density switching, and relation pills that render `-> title` when a
|
|
36
|
+
related page is loaded or `-> uuid` when it is not.
|
|
37
|
+
|
|
38
|
+
## SDK hooks
|
|
39
|
+
|
|
40
|
+
- **`useCustomBlockContext()`** -- returns `{ customBlockId, parent, page }` describing the block's location in the document tree
|
|
41
|
+
- **`useTheme()`** -- returns the host's current theme (`"light"` or `"dark"`)
|
|
42
|
+
- **`useDataSourceDefinitions()`** -- returns resolved data-source definitions
|
|
43
|
+
- **`useDataSource(key)`** -- returns `{ items, collectionSchema, propertySchemasById, propertySchemasByKey, isLoading, hasMore, fetchMore, error }`. Each `item` has `{ id, propertiesById, propertiesByKey }`. The four built-ins (`created_time`, `last_edited_time`, `created_by`, `last_edited_by`) appear in `propertiesById` / `propertySchemasById`, never in the `*ByKey` views.
|