@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.
Files changed (128) hide show
  1. package/dist/{VertebrAdmin.d.ts → components/admin/VertebrAdmin.d.ts} +3 -1
  2. package/dist/components/admin/VertebrAdmin.d.ts.map +1 -0
  3. package/dist/components/admin/VertebrAdmin.js +375 -0
  4. package/dist/components/config/ConfigForm.d.ts +3 -0
  5. package/dist/components/config/ConfigForm.d.ts.map +1 -0
  6. package/dist/components/config/ConfigForm.js +1 -0
  7. package/dist/components/config/DescriptionInput.d.ts +18 -0
  8. package/dist/components/config/DescriptionInput.d.ts.map +1 -0
  9. package/dist/components/config/DescriptionInput.js +152 -0
  10. package/dist/components/config/ImagePickerModal.d.ts +18 -0
  11. package/dist/components/config/ImagePickerModal.d.ts.map +1 -0
  12. package/dist/components/config/ImagePickerModal.js +120 -0
  13. package/dist/components/config/PriceInput.d.ts +12 -0
  14. package/dist/components/config/PriceInput.d.ts.map +1 -0
  15. package/dist/components/config/PriceInput.js +20 -0
  16. package/dist/components/config/form/ConfigField.d.ts +21 -0
  17. package/dist/components/config/form/ConfigField.d.ts.map +1 -0
  18. package/dist/components/config/form/ConfigField.js +48 -0
  19. package/dist/components/config/form/ConfigForm.d.ts +4 -0
  20. package/dist/components/config/form/ConfigForm.d.ts.map +1 -0
  21. package/dist/components/config/form/ConfigForm.js +70 -0
  22. package/dist/components/config/form/ConfigFormActions.d.ts +10 -0
  23. package/dist/components/config/form/ConfigFormActions.d.ts.map +1 -0
  24. package/dist/components/config/form/ConfigFormActions.js +4 -0
  25. package/dist/components/config/form/RecordConfigForm.d.ts +21 -0
  26. package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -0
  27. package/dist/components/config/form/RecordConfigForm.js +37 -0
  28. package/dist/components/config/form/SettingsConfigForm.d.ts +21 -0
  29. package/dist/components/config/form/SettingsConfigForm.d.ts.map +1 -0
  30. package/dist/components/config/form/SettingsConfigForm.js +7 -0
  31. package/dist/components/config/form/helpers.d.ts +16 -0
  32. package/dist/components/config/form/helpers.d.ts.map +1 -0
  33. package/dist/components/config/form/helpers.js +186 -0
  34. package/dist/components/config/form/types.d.ts +27 -0
  35. package/dist/components/config/form/types.d.ts.map +1 -0
  36. package/dist/{EnvSelect.d.ts → components/env/EnvSelect.d.ts} +1 -1
  37. package/dist/components/env/EnvSelect.d.ts.map +1 -0
  38. package/dist/components/gallery/GalleryBoard.d.ts +14 -0
  39. package/dist/components/gallery/GalleryBoard.d.ts.map +1 -0
  40. package/dist/components/gallery/GalleryBoard.js +14 -0
  41. package/dist/components/index.d.ts +9 -0
  42. package/dist/components/index.d.ts.map +1 -0
  43. package/dist/components/index.js +6 -0
  44. package/dist/{MetricsBoard.d.ts → components/metrics/MetricsBoard.d.ts} +1 -1
  45. package/dist/components/metrics/MetricsBoard.d.ts.map +1 -0
  46. package/dist/components/resources/BulkImageUploadModal.d.ts +17 -0
  47. package/dist/components/resources/BulkImageUploadModal.d.ts.map +1 -0
  48. package/dist/components/resources/BulkImageUploadModal.js +47 -0
  49. package/dist/components/resources/ColumnVisibilityMenu.d.ts +11 -0
  50. package/dist/components/resources/ColumnVisibilityMenu.d.ts.map +1 -0
  51. package/dist/components/resources/ColumnVisibilityMenu.js +40 -0
  52. package/dist/components/resources/ImageUploadControl.d.ts +10 -0
  53. package/dist/components/resources/ImageUploadControl.d.ts.map +1 -0
  54. package/dist/components/resources/ImageUploadControl.js +50 -0
  55. package/dist/components/resources/ResourceCell.d.ts +10 -0
  56. package/dist/components/resources/ResourceCell.d.ts.map +1 -0
  57. package/dist/components/resources/ResourceCell.js +100 -0
  58. package/dist/components/resources/ResourceTable.d.ts +34 -0
  59. package/dist/components/resources/ResourceTable.d.ts.map +1 -0
  60. package/dist/components/resources/ResourceTable.js +249 -0
  61. package/dist/components/resources/ResourceViewModal.d.ts +11 -0
  62. package/dist/components/resources/ResourceViewModal.d.ts.map +1 -0
  63. package/dist/components/resources/ResourceViewModal.js +44 -0
  64. package/dist/components/theme/ThemeToggle.d.ts +7 -0
  65. package/dist/components/theme/ThemeToggle.d.ts.map +1 -0
  66. package/dist/components/theme/ThemeToggle.js +10 -0
  67. package/dist/hooks/index.d.ts +5 -0
  68. package/dist/hooks/index.d.ts.map +1 -0
  69. package/dist/hooks/index.js +2 -0
  70. package/dist/{useVertebrControls.d.ts → hooks/useVertebrControls.d.ts} +2 -2
  71. package/dist/hooks/useVertebrControls.d.ts.map +1 -0
  72. package/dist/{useVertebrControls.js → hooks/useVertebrControls.js} +11 -21
  73. package/dist/hooks/useVertebrTheme.d.ts +7 -0
  74. package/dist/hooks/useVertebrTheme.d.ts.map +1 -0
  75. package/dist/hooks/useVertebrTheme.js +38 -0
  76. package/dist/index.d.ts +20 -10
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +14 -6
  79. package/dist/lib/description.d.ts +18 -0
  80. package/dist/lib/description.d.ts.map +1 -0
  81. package/dist/lib/description.js +85 -0
  82. package/dist/lib/images.d.ts +14 -0
  83. package/dist/lib/images.d.ts.map +1 -0
  84. package/dist/lib/images.js +63 -0
  85. package/dist/lib/price.d.ts +15 -0
  86. package/dist/lib/price.d.ts.map +1 -0
  87. package/dist/lib/price.js +50 -0
  88. package/dist/styles/auth.css +39 -0
  89. package/dist/styles/base.css +70 -0
  90. package/dist/styles/buttons.css +86 -0
  91. package/dist/styles/cells.css +178 -0
  92. package/dist/styles/columns.css +103 -0
  93. package/dist/styles/form.css +773 -0
  94. package/dist/styles/gallery.css +90 -0
  95. package/dist/styles/index.css +18 -0
  96. package/dist/styles/main.css +89 -0
  97. package/dist/styles/modal.css +225 -0
  98. package/dist/styles/nav.css +92 -0
  99. package/dist/styles/panel.css +215 -0
  100. package/dist/styles/select.css +151 -0
  101. package/dist/styles/sidebar.css +42 -0
  102. package/dist/styles/states.css +169 -0
  103. package/dist/styles/table.css +101 -0
  104. package/dist/styles/theme-toggle.css +87 -0
  105. package/dist/styles.css +2 -997
  106. package/dist/themes/dark.css +55 -0
  107. package/dist/themes/index.css +2 -0
  108. package/dist/themes/light.css +102 -0
  109. package/package.json +13 -3
  110. package/dist/ConfigForm.d.ts +0 -9
  111. package/dist/ConfigForm.d.ts.map +0 -1
  112. package/dist/ConfigForm.js +0 -87
  113. package/dist/EnvSelect.d.ts.map +0 -1
  114. package/dist/MetricsBoard.d.ts.map +0 -1
  115. package/dist/ResourceTable.d.ts +0 -23
  116. package/dist/ResourceTable.d.ts.map +0 -1
  117. package/dist/ResourceTable.js +0 -112
  118. package/dist/VertebrAdmin.d.ts.map +0 -1
  119. package/dist/VertebrAdmin.js +0 -269
  120. package/dist/client.d.ts +0 -32
  121. package/dist/client.d.ts.map +0 -1
  122. package/dist/client.js +0 -65
  123. package/dist/types.d.ts +0 -103
  124. package/dist/types.d.ts.map +0 -1
  125. package/dist/useVertebrControls.d.ts.map +0 -1
  126. /package/dist/{types.js → components/config/form/types.js} +0 -0
  127. /package/dist/{EnvSelect.js → components/env/EnvSelect.js} +0 -0
  128. /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,2 @@
1
+ @import "./dark.css";
2
+ @import "./light.css";
@@ -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.1.1",
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
  },
@@ -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
@@ -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"}
@@ -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
- }
@@ -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"}
@@ -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"}
@@ -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"}