@vertebr/react 0.1.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/dist/{VertebrAdmin.d.ts → components/admin/VertebrAdmin.d.ts} +3 -1
- package/dist/components/admin/VertebrAdmin.d.ts.map +1 -0
- package/dist/components/admin/VertebrAdmin.js +375 -0
- package/dist/components/config/ConfigForm.d.ts +3 -0
- package/dist/components/config/ConfigForm.d.ts.map +1 -0
- package/dist/components/config/ConfigForm.js +1 -0
- package/dist/components/config/DescriptionInput.d.ts +18 -0
- package/dist/components/config/DescriptionInput.d.ts.map +1 -0
- package/dist/components/config/DescriptionInput.js +152 -0
- package/dist/components/config/ImagePickerModal.d.ts +18 -0
- package/dist/components/config/ImagePickerModal.d.ts.map +1 -0
- package/dist/components/config/ImagePickerModal.js +120 -0
- package/dist/components/config/PriceInput.d.ts +12 -0
- package/dist/components/config/PriceInput.d.ts.map +1 -0
- package/dist/components/config/PriceInput.js +20 -0
- package/dist/components/config/form/ConfigField.d.ts +21 -0
- package/dist/components/config/form/ConfigField.d.ts.map +1 -0
- package/dist/components/config/form/ConfigField.js +48 -0
- package/dist/components/config/form/ConfigForm.d.ts +4 -0
- package/dist/components/config/form/ConfigForm.d.ts.map +1 -0
- package/dist/components/config/form/ConfigForm.js +70 -0
- package/dist/components/config/form/ConfigFormActions.d.ts +10 -0
- package/dist/components/config/form/ConfigFormActions.d.ts.map +1 -0
- package/dist/components/config/form/ConfigFormActions.js +4 -0
- package/dist/components/config/form/RecordConfigForm.d.ts +21 -0
- package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -0
- package/dist/components/config/form/RecordConfigForm.js +37 -0
- package/dist/components/config/form/SettingsConfigForm.d.ts +21 -0
- package/dist/components/config/form/SettingsConfigForm.d.ts.map +1 -0
- package/dist/components/config/form/SettingsConfigForm.js +7 -0
- package/dist/components/config/form/helpers.d.ts +16 -0
- package/dist/components/config/form/helpers.d.ts.map +1 -0
- package/dist/components/config/form/helpers.js +186 -0
- package/dist/components/config/form/types.d.ts +27 -0
- package/dist/components/config/form/types.d.ts.map +1 -0
- package/dist/{EnvSelect.d.ts → components/env/EnvSelect.d.ts} +1 -1
- package/dist/components/env/EnvSelect.d.ts.map +1 -0
- package/dist/components/gallery/GalleryBoard.d.ts +14 -0
- package/dist/components/gallery/GalleryBoard.d.ts.map +1 -0
- package/dist/components/gallery/GalleryBoard.js +14 -0
- package/dist/components/index.d.ts +9 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +6 -0
- package/dist/{MetricsBoard.d.ts → components/metrics/MetricsBoard.d.ts} +1 -1
- package/dist/components/metrics/MetricsBoard.d.ts.map +1 -0
- package/dist/components/resources/BulkImageUploadModal.d.ts +17 -0
- package/dist/components/resources/BulkImageUploadModal.d.ts.map +1 -0
- package/dist/components/resources/BulkImageUploadModal.js +47 -0
- package/dist/components/resources/ColumnVisibilityMenu.d.ts +11 -0
- package/dist/components/resources/ColumnVisibilityMenu.d.ts.map +1 -0
- package/dist/components/resources/ColumnVisibilityMenu.js +40 -0
- package/dist/components/resources/ImageUploadControl.d.ts +10 -0
- package/dist/components/resources/ImageUploadControl.d.ts.map +1 -0
- package/dist/components/resources/ImageUploadControl.js +50 -0
- package/dist/components/resources/ResourceCell.d.ts +10 -0
- package/dist/components/resources/ResourceCell.d.ts.map +1 -0
- package/dist/components/resources/ResourceCell.js +100 -0
- package/dist/components/resources/ResourceTable.d.ts +34 -0
- package/dist/components/resources/ResourceTable.d.ts.map +1 -0
- package/dist/components/resources/ResourceTable.js +249 -0
- package/dist/components/resources/ResourceViewModal.d.ts +11 -0
- package/dist/components/resources/ResourceViewModal.d.ts.map +1 -0
- package/dist/components/resources/ResourceViewModal.js +44 -0
- package/dist/components/theme/ThemeToggle.d.ts +7 -0
- package/dist/components/theme/ThemeToggle.d.ts.map +1 -0
- package/dist/components/theme/ThemeToggle.js +10 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +2 -0
- package/dist/{useVertebrControls.d.ts → hooks/useVertebrControls.d.ts} +2 -2
- package/dist/hooks/useVertebrControls.d.ts.map +1 -0
- package/dist/{useVertebrControls.js → hooks/useVertebrControls.js} +11 -21
- package/dist/hooks/useVertebrTheme.d.ts +7 -0
- package/dist/hooks/useVertebrTheme.d.ts.map +1 -0
- package/dist/hooks/useVertebrTheme.js +38 -0
- package/dist/index.d.ts +20 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -6
- package/dist/lib/description.d.ts +18 -0
- package/dist/lib/description.d.ts.map +1 -0
- package/dist/lib/description.js +85 -0
- package/dist/lib/images.d.ts +14 -0
- package/dist/lib/images.d.ts.map +1 -0
- package/dist/lib/images.js +63 -0
- package/dist/lib/price.d.ts +15 -0
- package/dist/lib/price.d.ts.map +1 -0
- package/dist/lib/price.js +50 -0
- package/dist/styles/auth.css +39 -0
- package/dist/styles/base.css +70 -0
- package/dist/styles/buttons.css +86 -0
- package/dist/styles/cells.css +178 -0
- package/dist/styles/columns.css +103 -0
- package/dist/styles/form.css +773 -0
- package/dist/styles/gallery.css +90 -0
- package/dist/styles/index.css +18 -0
- package/dist/styles/main.css +89 -0
- package/dist/styles/modal.css +225 -0
- package/dist/styles/nav.css +92 -0
- package/dist/styles/panel.css +215 -0
- package/dist/styles/select.css +151 -0
- package/dist/styles/sidebar.css +42 -0
- package/dist/styles/states.css +169 -0
- package/dist/styles/table.css +101 -0
- package/dist/styles/theme-toggle.css +87 -0
- package/dist/styles.css +2 -997
- package/dist/themes/dark.css +55 -0
- package/dist/themes/index.css +2 -0
- package/dist/themes/light.css +102 -0
- package/package.json +13 -3
- package/dist/ConfigForm.d.ts +0 -9
- package/dist/ConfigForm.d.ts.map +0 -1
- package/dist/ConfigForm.js +0 -87
- package/dist/EnvSelect.d.ts.map +0 -1
- package/dist/MetricsBoard.d.ts.map +0 -1
- package/dist/ResourceTable.d.ts +0 -23
- package/dist/ResourceTable.d.ts.map +0 -1
- package/dist/ResourceTable.js +0 -112
- package/dist/VertebrAdmin.d.ts.map +0 -1
- package/dist/VertebrAdmin.js +0 -269
- package/dist/client.d.ts +0 -32
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -65
- package/dist/types.d.ts +0 -103
- package/dist/types.d.ts.map +0 -1
- package/dist/useVertebrControls.d.ts.map +0 -1
- /package/dist/{types.js → components/config/form/types.js} +0 -0
- /package/dist/{EnvSelect.js → components/env/EnvSelect.js} +0 -0
- /package/dist/{MetricsBoard.js → components/metrics/MetricsBoard.js} +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vertebr dark theme (default).
|
|
3
|
+
* Apply with data-vb-theme="dark" or leave unset (:root defaults here).
|
|
4
|
+
*/
|
|
5
|
+
:root,
|
|
6
|
+
[data-vb-theme="dark"] {
|
|
7
|
+
color-scheme: dark;
|
|
8
|
+
|
|
9
|
+
--vb-bg: #0e1014;
|
|
10
|
+
--vb-bg-deep: #12151c;
|
|
11
|
+
--vb-bg-elevated: #161922;
|
|
12
|
+
--vb-bg-muted: #1e2330;
|
|
13
|
+
--vb-bg-hover: #252b3a;
|
|
14
|
+
--vb-border: #2a3142;
|
|
15
|
+
--vb-border-strong: #3a4358;
|
|
16
|
+
--vb-text: #f0eee8;
|
|
17
|
+
--vb-text-muted: #8b93a7;
|
|
18
|
+
--vb-text-subtle: #6a7285;
|
|
19
|
+
--vb-accent: #c9a66b;
|
|
20
|
+
--vb-accent-dim: #9a7d45;
|
|
21
|
+
--vb-accent-soft: rgba(201, 166, 107, 0.14);
|
|
22
|
+
--vb-accent-contrast: #1a140c;
|
|
23
|
+
--vb-danger: #e07a72;
|
|
24
|
+
--vb-danger-soft: rgba(224, 122, 114, 0.12);
|
|
25
|
+
--vb-danger-text: #f3c4bf;
|
|
26
|
+
--vb-ok: #87a87f;
|
|
27
|
+
--vb-ok-soft: rgba(135, 168, 127, 0.14);
|
|
28
|
+
--vb-warn-text: #e8d0a0;
|
|
29
|
+
|
|
30
|
+
--vb-glow-accent: rgba(201, 166, 107, 0.07);
|
|
31
|
+
--vb-glow-cool: rgba(60, 80, 120, 0.08);
|
|
32
|
+
--vb-surface-tint: rgba(255, 255, 255, 0.02);
|
|
33
|
+
--vb-surface-tint-strong: rgba(255, 255, 255, 0.04);
|
|
34
|
+
--vb-sidebar-from: #0e1014;
|
|
35
|
+
--vb-sidebar-to: #12151c;
|
|
36
|
+
--vb-header-from: rgba(14, 16, 20, 0.96);
|
|
37
|
+
--vb-header-to: rgba(14, 16, 20, 0.86);
|
|
38
|
+
--vb-actions-from: rgba(22, 25, 34, 0.65);
|
|
39
|
+
--vb-actions-to: rgba(18, 21, 28, 0.95);
|
|
40
|
+
--vb-input-focus-bg: #12151c;
|
|
41
|
+
--vb-btn-primary-from: #d4b27a;
|
|
42
|
+
--vb-btn-primary-to: #c9a66b;
|
|
43
|
+
--vb-btn-primary-border: #b89255;
|
|
44
|
+
--vb-btn-primary-hover-from: #dbbc88;
|
|
45
|
+
--vb-btn-primary-hover-to: #d0ad72;
|
|
46
|
+
--vb-btn-primary-hover-border: #c4a574;
|
|
47
|
+
|
|
48
|
+
--vb-font: "IBM Plex Sans", "Segoe UI", sans-serif;
|
|
49
|
+
--vb-mono: "IBM Plex Mono", ui-monospace, monospace;
|
|
50
|
+
--vb-radius: 8px;
|
|
51
|
+
--vb-radius-sm: 6px;
|
|
52
|
+
--vb-shadow: 0 1px 0 rgba(255, 255, 255, 0.04) inset,
|
|
53
|
+
0 18px 48px rgba(0, 0, 0, 0.45);
|
|
54
|
+
--vb-sidebar-width: 260px;
|
|
55
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vertebr light theme.
|
|
3
|
+
* Apply with data-vb-theme="light" on <html> or .vertebr-root.
|
|
4
|
+
*/
|
|
5
|
+
[data-vb-theme="light"] {
|
|
6
|
+
color-scheme: light;
|
|
7
|
+
|
|
8
|
+
--vb-bg: #f4f2ec;
|
|
9
|
+
--vb-bg-deep: #ebe7de;
|
|
10
|
+
--vb-bg-elevated: #fffcf7;
|
|
11
|
+
--vb-bg-muted: #ebe6db;
|
|
12
|
+
--vb-bg-hover: #e2dcd0;
|
|
13
|
+
--vb-border: #d5cfc2;
|
|
14
|
+
--vb-border-strong: #bdb5a6;
|
|
15
|
+
--vb-text: #1c1a16;
|
|
16
|
+
--vb-text-muted: #5c564c;
|
|
17
|
+
--vb-text-subtle: #7a7368;
|
|
18
|
+
--vb-accent: #9a6f2e;
|
|
19
|
+
--vb-accent-dim: #7d5924;
|
|
20
|
+
--vb-accent-soft: rgba(154, 111, 46, 0.12);
|
|
21
|
+
--vb-accent-contrast: #fff8eb;
|
|
22
|
+
--vb-danger: #c44d44;
|
|
23
|
+
--vb-danger-soft: rgba(196, 77, 68, 0.12);
|
|
24
|
+
--vb-danger-text: #9a2f28;
|
|
25
|
+
--vb-ok: #3f6b3a;
|
|
26
|
+
--vb-ok-soft: rgba(63, 107, 58, 0.12);
|
|
27
|
+
--vb-warn-text: #7a5620;
|
|
28
|
+
|
|
29
|
+
--vb-glow-accent: rgba(154, 111, 46, 0.1);
|
|
30
|
+
--vb-glow-cool: rgba(80, 100, 140, 0.06);
|
|
31
|
+
--vb-surface-tint: rgba(28, 26, 22, 0.03);
|
|
32
|
+
--vb-surface-tint-strong: rgba(28, 26, 22, 0.05);
|
|
33
|
+
--vb-sidebar-from: #fffcf7;
|
|
34
|
+
--vb-sidebar-to: #f4f2ec;
|
|
35
|
+
--vb-header-from: rgba(255, 252, 247, 0.96);
|
|
36
|
+
--vb-header-to: rgba(255, 252, 247, 0.88);
|
|
37
|
+
--vb-actions-from: rgba(255, 252, 247, 0.85);
|
|
38
|
+
--vb-actions-to: rgba(244, 242, 236, 0.98);
|
|
39
|
+
--vb-input-focus-bg: #fffcf7;
|
|
40
|
+
--vb-btn-primary-from: #b8893f;
|
|
41
|
+
--vb-btn-primary-to: #9a6f2e;
|
|
42
|
+
--vb-btn-primary-border: #815c26;
|
|
43
|
+
--vb-btn-primary-hover-from: #c4964a;
|
|
44
|
+
--vb-btn-primary-hover-to: #a87a34;
|
|
45
|
+
--vb-btn-primary-hover-border: #8f662a;
|
|
46
|
+
|
|
47
|
+
--vb-font: "IBM Plex Sans", "Segoe UI", sans-serif;
|
|
48
|
+
--vb-mono: "IBM Plex Mono", ui-monospace, monospace;
|
|
49
|
+
--vb-radius: 8px;
|
|
50
|
+
--vb-radius-sm: 6px;
|
|
51
|
+
--vb-shadow: 0 1px 0 rgba(255, 255, 255, 0.65) inset,
|
|
52
|
+
0 14px 40px rgba(40, 32, 18, 0.1);
|
|
53
|
+
--vb-sidebar-width: 260px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@media (prefers-color-scheme: light) {
|
|
57
|
+
:root:not([data-vb-theme]) {
|
|
58
|
+
color-scheme: light;
|
|
59
|
+
|
|
60
|
+
--vb-bg: #f4f2ec;
|
|
61
|
+
--vb-bg-deep: #ebe7de;
|
|
62
|
+
--vb-bg-elevated: #fffcf7;
|
|
63
|
+
--vb-bg-muted: #ebe6db;
|
|
64
|
+
--vb-bg-hover: #e2dcd0;
|
|
65
|
+
--vb-border: #d5cfc2;
|
|
66
|
+
--vb-border-strong: #bdb5a6;
|
|
67
|
+
--vb-text: #1c1a16;
|
|
68
|
+
--vb-text-muted: #5c564c;
|
|
69
|
+
--vb-text-subtle: #7a7368;
|
|
70
|
+
--vb-accent: #9a6f2e;
|
|
71
|
+
--vb-accent-dim: #7d5924;
|
|
72
|
+
--vb-accent-soft: rgba(154, 111, 46, 0.12);
|
|
73
|
+
--vb-accent-contrast: #fff8eb;
|
|
74
|
+
--vb-danger: #c44d44;
|
|
75
|
+
--vb-danger-soft: rgba(196, 77, 68, 0.12);
|
|
76
|
+
--vb-danger-text: #9a2f28;
|
|
77
|
+
--vb-ok: #3f6b3a;
|
|
78
|
+
--vb-ok-soft: rgba(63, 107, 58, 0.12);
|
|
79
|
+
--vb-warn-text: #7a5620;
|
|
80
|
+
|
|
81
|
+
--vb-glow-accent: rgba(154, 111, 46, 0.1);
|
|
82
|
+
--vb-glow-cool: rgba(80, 100, 140, 0.06);
|
|
83
|
+
--vb-surface-tint: rgba(28, 26, 22, 0.03);
|
|
84
|
+
--vb-surface-tint-strong: rgba(28, 26, 22, 0.05);
|
|
85
|
+
--vb-sidebar-from: #fffcf7;
|
|
86
|
+
--vb-sidebar-to: #f4f2ec;
|
|
87
|
+
--vb-header-from: rgba(255, 252, 247, 0.96);
|
|
88
|
+
--vb-header-to: rgba(255, 252, 247, 0.88);
|
|
89
|
+
--vb-actions-from: rgba(255, 252, 247, 0.85);
|
|
90
|
+
--vb-actions-to: rgba(244, 242, 236, 0.98);
|
|
91
|
+
--vb-input-focus-bg: #fffcf7;
|
|
92
|
+
--vb-btn-primary-from: #b8893f;
|
|
93
|
+
--vb-btn-primary-to: #9a6f2e;
|
|
94
|
+
--vb-btn-primary-border: #815c26;
|
|
95
|
+
--vb-btn-primary-hover-from: #c4964a;
|
|
96
|
+
--vb-btn-primary-hover-to: #a87a34;
|
|
97
|
+
--vb-btn-primary-hover-border: #8f662a;
|
|
98
|
+
|
|
99
|
+
--vb-shadow: 0 1px 0 rgba(255, 255, 255, 0.65) inset,
|
|
100
|
+
0 14px 40px rgba(40, 32, 18, 0.1);
|
|
101
|
+
}
|
|
102
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vertebr/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Vertebr admin dashboard UI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -10,13 +10,15 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
12
|
},
|
|
13
|
-
"./styles.css": "./dist/styles.css"
|
|
13
|
+
"./styles.css": "./dist/styles.css",
|
|
14
|
+
"./styles/*": "./dist/styles/*",
|
|
15
|
+
"./themes/*": "./dist/themes/*"
|
|
14
16
|
},
|
|
15
17
|
"files": [
|
|
16
18
|
"dist"
|
|
17
19
|
],
|
|
18
20
|
"scripts": {
|
|
19
|
-
"build": "tsc -p tsconfig.json && cp src/styles.css dist/styles.css",
|
|
21
|
+
"build": "tsc -p tsconfig.json && rm -rf dist/styles dist/themes && cp src/styles.css dist/styles.css && cp -R src/styles dist/styles && cp -R src/themes dist/themes",
|
|
20
22
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
21
23
|
"prepublishOnly": "npm run typecheck && npm run build"
|
|
22
24
|
},
|
|
@@ -40,6 +42,14 @@
|
|
|
40
42
|
"@radix-ui/react-separator": "^1.1.7",
|
|
41
43
|
"@radix-ui/react-switch": "^1.2.5",
|
|
42
44
|
"@tanstack/react-table": "^8.21.3",
|
|
45
|
+
"@tiptap/extension-image": "^3.29.2",
|
|
46
|
+
"@tiptap/extension-table": "^3.29.2",
|
|
47
|
+
"@tiptap/extensions": "^3.29.2",
|
|
48
|
+
"@tiptap/markdown": "^3.29.2",
|
|
49
|
+
"@tiptap/pm": "^3.29.2",
|
|
50
|
+
"@tiptap/react": "^3.29.2",
|
|
51
|
+
"@tiptap/starter-kit": "^3.29.2",
|
|
52
|
+
"@vertebr/client": "*",
|
|
43
53
|
"react-hook-form": "^7.62.0",
|
|
44
54
|
"zod": "^3.25.76"
|
|
45
55
|
},
|
package/dist/ConfigForm.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { FieldSchema } from "./types";
|
|
2
|
-
type ConfigFormProps = {
|
|
3
|
-
schema: Record<string, FieldSchema>;
|
|
4
|
-
value: Record<string, unknown>;
|
|
5
|
-
onSave: (value: Record<string, unknown>) => Promise<void>;
|
|
6
|
-
};
|
|
7
|
-
export declare function ConfigForm({ schema, value, onSave }: ConfigFormProps): import("react").JSX.Element;
|
|
8
|
-
export {};
|
|
9
|
-
//# sourceMappingURL=ConfigForm.d.ts.map
|
package/dist/ConfigForm.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigForm.d.ts","sourceRoot":"","sources":["../src/ConfigForm.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D,CAAC;AAgCF,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,eAAe,+BA4HpE"}
|
package/dist/ConfigForm.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useMemo, useState } from "react";
|
|
3
|
-
import { useForm, Controller } from "react-hook-form";
|
|
4
|
-
import { z } from "zod";
|
|
5
|
-
import { zodResolver } from "@hookform/resolvers/zod";
|
|
6
|
-
import * as Label from "@radix-ui/react-label";
|
|
7
|
-
import * as Switch from "@radix-ui/react-switch";
|
|
8
|
-
function buildZodSchema(schema) {
|
|
9
|
-
const shape = {};
|
|
10
|
-
for (const [key, field] of Object.entries(schema)) {
|
|
11
|
-
let zodField;
|
|
12
|
-
switch (field.type) {
|
|
13
|
-
case "number":
|
|
14
|
-
zodField = z.number();
|
|
15
|
-
if (field.min != null)
|
|
16
|
-
zodField = zodField.min(field.min);
|
|
17
|
-
if (field.max != null)
|
|
18
|
-
zodField = zodField.max(field.max);
|
|
19
|
-
break;
|
|
20
|
-
case "boolean":
|
|
21
|
-
zodField = z.boolean();
|
|
22
|
-
break;
|
|
23
|
-
default:
|
|
24
|
-
zodField = z.string();
|
|
25
|
-
}
|
|
26
|
-
if (!field.required) {
|
|
27
|
-
zodField = zodField.optional();
|
|
28
|
-
}
|
|
29
|
-
shape[key] = zodField;
|
|
30
|
-
}
|
|
31
|
-
return z.object(shape);
|
|
32
|
-
}
|
|
33
|
-
function spanFor(field) {
|
|
34
|
-
if (field.type === "boolean")
|
|
35
|
-
return "full";
|
|
36
|
-
if (field.type === "richtext")
|
|
37
|
-
return "wide";
|
|
38
|
-
return undefined;
|
|
39
|
-
}
|
|
40
|
-
export function ConfigForm({ schema, value, onSave }) {
|
|
41
|
-
const zodSchema = useMemo(() => buildZodSchema(schema), [schema]);
|
|
42
|
-
const [status, setStatus] = useState(null);
|
|
43
|
-
const [tone, setTone] = useState();
|
|
44
|
-
const form = useForm({
|
|
45
|
-
resolver: zodResolver(zodSchema),
|
|
46
|
-
defaultValues: value,
|
|
47
|
-
});
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
form.reset(value);
|
|
50
|
-
}, [value, form]);
|
|
51
|
-
const onSubmit = form.handleSubmit(async (data) => {
|
|
52
|
-
setStatus("Saving…");
|
|
53
|
-
setTone(undefined);
|
|
54
|
-
try {
|
|
55
|
-
await onSave(data);
|
|
56
|
-
setStatus("Saved");
|
|
57
|
-
setTone("ok");
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
setStatus(error instanceof Error ? error.message : "Save failed");
|
|
61
|
-
setTone("danger");
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
const isDirty = form.formState.isDirty;
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
const onKeyDown = (event) => {
|
|
67
|
-
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "s") {
|
|
68
|
-
event.preventDefault();
|
|
69
|
-
void onSubmit();
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
window.addEventListener("keydown", onKeyDown);
|
|
73
|
-
return () => window.removeEventListener("keydown", onKeyDown);
|
|
74
|
-
}, [onSubmit]);
|
|
75
|
-
return (_jsxs("form", { className: "vertebr-form", onSubmit: onSubmit, children: [_jsx("div", { className: "vertebr-form-fields", children: Object.entries(schema).map(([key, field]) => {
|
|
76
|
-
if (field.type === "boolean") {
|
|
77
|
-
return (_jsxs("div", { className: "vertebr-switch-row", children: [_jsx(Label.Root, { htmlFor: key, children: field.label ?? key }), _jsx(Controller, { control: form.control, name: key, render: ({ field: controllerField }) => (_jsx(Switch.Root, { className: "vertebr-switch", id: key, checked: Boolean(controllerField.value), onCheckedChange: controllerField.onChange, children: _jsx(Switch.Thumb, { className: "vertebr-switch-thumb" }) })) })] }, key));
|
|
78
|
-
}
|
|
79
|
-
return (_jsxs("div", { className: "vertebr-field", "data-span": spanFor(field), children: [_jsx(Label.Root, { htmlFor: key, children: field.label ?? key }), field.type === "richtext" ? (_jsx("textarea", { id: key, rows: 3, readOnly: field.readOnly, ...form.register(key) })) : (_jsx("input", { id: key, type: field.type === "number" ? "number" : "text", readOnly: field.readOnly, ...form.register(key, {
|
|
80
|
-
valueAsNumber: field.type === "number",
|
|
81
|
-
}) }))] }, key));
|
|
82
|
-
}) }), _jsxs("div", { className: "vertebr-actions", children: [_jsx("button", { className: "vertebr-btn vertebr-btn-primary", type: "submit", disabled: form.formState.isSubmitting || !isDirty, children: form.formState.isSubmitting ? "Saving…" : "Save changes" }), isDirty ? (_jsx("button", { className: "vertebr-btn", type: "button", onClick: () => {
|
|
83
|
-
form.reset(value);
|
|
84
|
-
setStatus(null);
|
|
85
|
-
setTone(undefined);
|
|
86
|
-
}, children: "Discard" })) : null, isDirty ? (_jsx("span", { className: "vertebr-dirty", children: "Unsaved" })) : status ? (_jsx("span", { className: "vertebr-status", "data-tone": tone, children: status })) : null, _jsx("span", { className: "vertebr-actions-spacer" }), _jsx("span", { className: "vertebr-kbd", children: "\u2318S" })] })] }));
|
|
87
|
-
}
|
package/dist/EnvSelect.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EnvSelect.d.ts","sourceRoot":"","sources":["../src/EnvSelect.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,KAAK,cAAc,GAAG;IACpB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,wBAAgB,SAAS,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,cAAc,+BAqD1E"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MetricsBoard.d.ts","sourceRoot":"","sources":["../src/MetricsBoard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAC3B,KAAkB,EAClB,OAAO,EACP,SAAS,EACT,OAAO,GACR,EAAE,iBAAiB,+BAqCnB"}
|
package/dist/ResourceTable.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { FieldSchema, ResourceActionMeta } from "./types";
|
|
2
|
-
type ResourcePanelProps = {
|
|
3
|
-
schema: Record<string, FieldSchema>;
|
|
4
|
-
items: Record<string, unknown>[];
|
|
5
|
-
permissions?: {
|
|
6
|
-
create?: boolean;
|
|
7
|
-
update?: boolean;
|
|
8
|
-
delete?: boolean;
|
|
9
|
-
};
|
|
10
|
-
actions?: Record<string, ResourceActionMeta>;
|
|
11
|
-
rowIdKeys?: string[];
|
|
12
|
-
onUpdate?: (rowId: string, value: Record<string, unknown>) => Promise<void>;
|
|
13
|
-
onDelete?: (rowId: string) => Promise<void>;
|
|
14
|
-
onAction?: (rowId: string, actionId: string) => Promise<void>;
|
|
15
|
-
};
|
|
16
|
-
export declare function ResourcePanel({ schema, items, permissions, actions, rowIdKeys, onUpdate, onDelete, onAction, }: ResourcePanelProps): import("react").JSX.Element;
|
|
17
|
-
/** @deprecated Prefer ResourcePanel */
|
|
18
|
-
export declare function ResourceTable(props: {
|
|
19
|
-
schema: Record<string, FieldSchema>;
|
|
20
|
-
items: Record<string, unknown>[];
|
|
21
|
-
}): import("react").JSX.Element;
|
|
22
|
-
export {};
|
|
23
|
-
//# sourceMappingURL=ResourceTable.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ResourceTable.d.ts","sourceRoot":"","sources":["../src/ResourceTable.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE/D,KAAK,kBAAkB,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACjC,WAAW,CAAC,EAAE;QACZ,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D,CAAC;AAmCF,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,WAAW,EACX,OAAY,EACZ,SAA0C,EAC1C,QAAQ,EACR,QAAQ,EACR,QAAQ,GACT,EAAE,kBAAkB,+BAqKpB;AAED,uCAAuC;AACvC,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CAClC,+BAEA"}
|
package/dist/ResourceTable.js
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useState } from "react";
|
|
3
|
-
import { flexRender, getCoreRowModel, useReactTable, } from "@tanstack/react-table";
|
|
4
|
-
import { ConfigForm } from "./ConfigForm";
|
|
5
|
-
function formatCell(value) {
|
|
6
|
-
if (value == null)
|
|
7
|
-
return "—";
|
|
8
|
-
if (typeof value === "boolean")
|
|
9
|
-
return value ? "Yes" : "No";
|
|
10
|
-
if (typeof value === "object") {
|
|
11
|
-
if (value &&
|
|
12
|
-
typeof value === "object" &&
|
|
13
|
-
"toDate" in value &&
|
|
14
|
-
typeof value.toDate === "function") {
|
|
15
|
-
try {
|
|
16
|
-
return value.toDate().toLocaleString();
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
// fall through
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return JSON.stringify(value);
|
|
23
|
-
}
|
|
24
|
-
return String(value);
|
|
25
|
-
}
|
|
26
|
-
function resolveRowId(row, keys) {
|
|
27
|
-
for (const key of keys) {
|
|
28
|
-
const value = row[key];
|
|
29
|
-
if (typeof value === "string" && value.trim())
|
|
30
|
-
return value;
|
|
31
|
-
if (typeof value === "number")
|
|
32
|
-
return String(value);
|
|
33
|
-
}
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
export function ResourcePanel({ schema, items, permissions, actions = {}, rowIdKeys = ["id", "slug", "uid", "email"], onUpdate, onDelete, onAction, }) {
|
|
37
|
-
const [editing, setEditing] = useState(null);
|
|
38
|
-
const [busyAction, setBusyAction] = useState(null);
|
|
39
|
-
const canUpdate = Boolean(permissions?.update && onUpdate);
|
|
40
|
-
const canDelete = Boolean(permissions?.delete && onDelete);
|
|
41
|
-
const actionEntries = Object.entries(actions);
|
|
42
|
-
const columns = useMemo(() => {
|
|
43
|
-
const keys = Object.keys(schema);
|
|
44
|
-
const defs = keys.length === 0
|
|
45
|
-
? [
|
|
46
|
-
{
|
|
47
|
-
id: "raw",
|
|
48
|
-
header: "Item",
|
|
49
|
-
cell: ({ row }) => formatCell(row.original),
|
|
50
|
-
},
|
|
51
|
-
]
|
|
52
|
-
: keys.map((key) => ({
|
|
53
|
-
accessorKey: key,
|
|
54
|
-
header: schema[key]?.label ?? key,
|
|
55
|
-
cell: ({ getValue }) => formatCell(getValue()),
|
|
56
|
-
}));
|
|
57
|
-
if (canUpdate || canDelete || actionEntries.length > 0) {
|
|
58
|
-
defs.push({
|
|
59
|
-
id: "_actions",
|
|
60
|
-
header: "",
|
|
61
|
-
cell: ({ row }) => {
|
|
62
|
-
const rowId = resolveRowId(row.original, rowIdKeys);
|
|
63
|
-
if (!rowId)
|
|
64
|
-
return null;
|
|
65
|
-
return (_jsxs("div", { className: "vertebr-row-actions", children: [canUpdate ? (_jsx("button", { type: "button", className: "vertebr-btn", onClick: () => setEditing(row.original), children: "Edit" })) : null, actionEntries.map(([actionId, meta]) => (_jsx("button", { type: "button", className: "vertebr-btn", disabled: busyAction === `${rowId}:${actionId}`, onClick: () => {
|
|
66
|
-
if (!onAction)
|
|
67
|
-
return;
|
|
68
|
-
setBusyAction(`${rowId}:${actionId}`);
|
|
69
|
-
void onAction(rowId, actionId).finally(() => setBusyAction(null));
|
|
70
|
-
}, children: meta.label }, actionId))), canDelete ? (_jsx("button", { type: "button", className: "vertebr-btn", onClick: () => {
|
|
71
|
-
if (window.confirm("Delete this row? This cannot be undone.")) {
|
|
72
|
-
void onDelete?.(rowId);
|
|
73
|
-
}
|
|
74
|
-
}, children: "Delete" })) : null] }));
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
return defs;
|
|
79
|
-
}, [
|
|
80
|
-
schema,
|
|
81
|
-
canUpdate,
|
|
82
|
-
canDelete,
|
|
83
|
-
actionEntries,
|
|
84
|
-
busyAction,
|
|
85
|
-
onAction,
|
|
86
|
-
onDelete,
|
|
87
|
-
rowIdKeys,
|
|
88
|
-
]);
|
|
89
|
-
const table = useReactTable({
|
|
90
|
-
data: items,
|
|
91
|
-
columns,
|
|
92
|
-
getCoreRowModel: getCoreRowModel(),
|
|
93
|
-
});
|
|
94
|
-
const editingId = editing ? resolveRowId(editing, rowIdKeys) : null;
|
|
95
|
-
if (editing && editingId && onUpdate) {
|
|
96
|
-
const editableSchema = Object.fromEntries(Object.entries(schema).filter(([, field]) => !field.readOnly));
|
|
97
|
-
return (_jsxs("div", { className: "vertebr-resource-edit", children: [_jsxs("div", { className: "vertebr-panel-head", children: [_jsxs("h2", { children: ["Edit ", editingId] }), _jsx("button", { type: "button", className: "vertebr-btn", onClick: () => setEditing(null), children: "Back" })] }), _jsx(ConfigForm, { schema: editableSchema, value: editing, onSave: async (next) => {
|
|
98
|
-
await onUpdate(editingId, next);
|
|
99
|
-
setEditing(null);
|
|
100
|
-
} })] }));
|
|
101
|
-
}
|
|
102
|
-
if (items.length === 0) {
|
|
103
|
-
return _jsx("div", { className: "vertebr-empty", children: "No rows yet." });
|
|
104
|
-
}
|
|
105
|
-
return (_jsx("div", { className: "vertebr-table-wrap", children: _jsxs("table", { className: "vertebr-table", children: [_jsx("thead", { children: table.getHeaderGroups().map((headerGroup) => (_jsx("tr", { children: headerGroup.headers.map((header) => (_jsx("th", { children: header.isPlaceholder
|
|
106
|
-
? null
|
|
107
|
-
: flexRender(header.column.columnDef.header, header.getContext()) }, header.id))) }, headerGroup.id))) }), _jsx("tbody", { children: table.getRowModel().rows.map((row) => (_jsx("tr", { children: row.getVisibleCells().map((cell) => (_jsx("td", { children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))) }, row.id))) })] }) }));
|
|
108
|
-
}
|
|
109
|
-
/** @deprecated Prefer ResourcePanel */
|
|
110
|
-
export function ResourceTable(props) {
|
|
111
|
-
return _jsx(ResourcePanel, { ...props });
|
|
112
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"VertebrAdmin.d.ts","sourceRoot":"","sources":["../src/VertebrAdmin.tsx"],"names":[],"mappings":"AAcA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACtF,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAgCF,wBAAgB,YAAY,CAAC,EAC3B,OAAsB,EACtB,KAAuB,EACvB,aAA6B,EAC7B,eAAiC,EACjC,cAAc,EACd,aAAa,EACb,SAAS,GACV,EAAE,iBAAiB,+BAgdnB"}
|