@rebasepro/core 0.6.0 → 0.6.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/dist/index.es.js +215 -345
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +214 -344
- package/dist/index.umd.js.map +1 -1
- package/package.json +6 -6
- package/src/components/Debug/UIReferenceView.tsx +109 -201
- package/src/components/LoginView/LoginView.tsx +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.1",
|
|
5
5
|
"description": "Rebase core — framework-agnostic runtime for data-driven admin panels",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/rebaseco"
|
|
@@ -52,11 +52,11 @@
|
|
|
52
52
|
"i18next": "^26.3.1",
|
|
53
53
|
"notistack": "^3.0.2",
|
|
54
54
|
"react-i18next": "^17.0.8",
|
|
55
|
-
"@rebasepro/common": "0.6.
|
|
56
|
-
"@rebasepro/
|
|
57
|
-
"@rebasepro/
|
|
58
|
-
"@rebasepro/
|
|
59
|
-
"@rebasepro/
|
|
55
|
+
"@rebasepro/common": "0.6.1",
|
|
56
|
+
"@rebasepro/types": "0.6.1",
|
|
57
|
+
"@rebasepro/utils": "0.6.1",
|
|
58
|
+
"@rebasepro/ui": "0.6.1",
|
|
59
|
+
"@rebasepro/formex": "0.6.1"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"react": ">=19.0.0",
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
import React, { useState } from "react";
|
|
14
14
|
import {
|
|
15
15
|
Alert,
|
|
16
|
+
AlertCircleIcon,
|
|
16
17
|
Avatar,
|
|
18
|
+
AppWindow,
|
|
17
19
|
BooleanSwitch,
|
|
18
20
|
Button,
|
|
19
21
|
Checkbox,
|
|
@@ -21,9 +23,14 @@ import {
|
|
|
21
23
|
ChevronsLeftIcon,
|
|
22
24
|
ChevronsRightIcon,
|
|
23
25
|
Chip,
|
|
26
|
+
CircleUserIcon,
|
|
24
27
|
CircularProgress,
|
|
25
28
|
cls,
|
|
29
|
+
ColumnsIcon,
|
|
26
30
|
defaultBorderMixin,
|
|
31
|
+
FileIcon,
|
|
32
|
+
FileTextIcon,
|
|
33
|
+
FilterChip,
|
|
27
34
|
FilterIcon,
|
|
28
35
|
FolderIcon,
|
|
29
36
|
IconButton,
|
|
@@ -38,6 +45,7 @@ import {
|
|
|
38
45
|
MoonIcon,
|
|
39
46
|
MultiSelect,
|
|
40
47
|
MultiSelectItem,
|
|
48
|
+
PanelLeftIcon,
|
|
41
49
|
PencilIcon,
|
|
42
50
|
PlusIcon,
|
|
43
51
|
SearchBar,
|
|
@@ -59,54 +67,45 @@ import {
|
|
|
59
67
|
TextField,
|
|
60
68
|
Tooltip,
|
|
61
69
|
Trash2Icon,
|
|
70
|
+
TypeIcon,
|
|
62
71
|
Typography,
|
|
63
72
|
UserIcon
|
|
64
73
|
} from "@rebasepro/ui";
|
|
65
74
|
import { RebaseLogo } from "../RebaseLogo";
|
|
66
75
|
|
|
67
76
|
const SECTIONS = [
|
|
68
|
-
{ id: "drawer",
|
|
69
|
-
label: "
|
|
70
|
-
{ id: "
|
|
71
|
-
label: "
|
|
72
|
-
{ id: "
|
|
73
|
-
label: "
|
|
74
|
-
{ id: "
|
|
75
|
-
label: "
|
|
76
|
-
{ id: "
|
|
77
|
-
label: "
|
|
78
|
-
{ id: "
|
|
79
|
-
label: "Typography" },
|
|
80
|
-
{ id: "buttons",
|
|
81
|
-
label: "Buttons" },
|
|
82
|
-
{ id: "inputs",
|
|
83
|
-
label: "Form Inputs" },
|
|
84
|
-
{ id: "chips-alerts",
|
|
85
|
-
label: "Chips & Alerts" },
|
|
86
|
-
{ id: "users",
|
|
87
|
-
label: "Users View" },
|
|
88
|
-
{ id: "user-dialog",
|
|
89
|
-
label: "User Dialog" },
|
|
90
|
-
{ id: "roles",
|
|
91
|
-
label: "Roles View" },
|
|
92
|
-
{ id: "role-dialog",
|
|
93
|
-
label: "Role Dialog" }
|
|
77
|
+
{ id: "drawer", label: "Drawer", icon: PanelLeftIcon },
|
|
78
|
+
{ id: "appbar", label: "App Bar", icon: AppWindow },
|
|
79
|
+
{ id: "tabs", label: "Tabs", icon: ListIcon },
|
|
80
|
+
{ id: "editor-sidebar", label: "Editor Sidebar", icon: ColumnsIcon },
|
|
81
|
+
{ id: "empty-states", label: "Empty States", icon: FileIcon },
|
|
82
|
+
{ id: "typography", label: "Typography", icon: TypeIcon },
|
|
83
|
+
{ id: "buttons", label: "Buttons", icon: PlusIcon },
|
|
84
|
+
{ id: "inputs", label: "Form Inputs", icon: FileTextIcon },
|
|
85
|
+
{ id: "chips-alerts", label: "Chips & Alerts", icon: AlertCircleIcon },
|
|
86
|
+
{ id: "users", label: "Users View", icon: UserIcon },
|
|
87
|
+
{ id: "user-dialog", label: "User Dialog", icon: CircleUserIcon }
|
|
94
88
|
];
|
|
95
89
|
|
|
96
90
|
export function UIReferenceView() {
|
|
97
91
|
const [activeSection, setActiveSection] = useState("drawer");
|
|
92
|
+
const scrollContainerRef = React.useRef<HTMLDivElement>(null);
|
|
98
93
|
|
|
99
94
|
const scrollTo = (id: string) => {
|
|
100
|
-
document.getElementById(id)
|
|
101
|
-
|
|
95
|
+
const el = document.getElementById(id);
|
|
96
|
+
const container = scrollContainerRef.current;
|
|
97
|
+
if (el && container) {
|
|
98
|
+
const offsetTop = el.offsetTop - container.offsetTop;
|
|
99
|
+
container.scrollTo({ top: offsetTop, behavior: "smooth" });
|
|
100
|
+
}
|
|
102
101
|
setActiveSection(id);
|
|
103
102
|
};
|
|
104
103
|
|
|
105
104
|
return (
|
|
106
|
-
<div className="flex
|
|
105
|
+
<div className="flex w-full">
|
|
107
106
|
|
|
108
107
|
{/* ── Sidebar nav (same structure as DefaultDrawer) ─────────────── */}
|
|
109
|
-
<div className={cls("flex flex-col h-
|
|
108
|
+
<div className={cls("flex flex-col sticky top-0 h-screen grow-0 shrink-0 w-[200px] border-r", defaultBorderMixin)}>
|
|
110
109
|
{/* DrawerLogo */}
|
|
111
110
|
<div className="flex flex-row items-center shrink-0 pt-4 pb-2 px-2">
|
|
112
111
|
<div className="shrink-0 flex items-center justify-center w-[56px] h-[40px]">
|
|
@@ -127,28 +126,31 @@ block: "start" });
|
|
|
127
126
|
</div>
|
|
128
127
|
{/* Nav items — from DrawerNavigationItem */}
|
|
129
128
|
<div className="overflow-hidden bg-surface-50 dark:bg-surface-950/30 rounded-b-lg">
|
|
130
|
-
{SECTIONS.map(s =>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
129
|
+
{SECTIONS.map(s => {
|
|
130
|
+
const IconComponent = s.icon;
|
|
131
|
+
return (
|
|
132
|
+
<div key={s.id}>
|
|
133
|
+
<div
|
|
134
|
+
onClick={() => scrollTo(s.id)}
|
|
135
|
+
className={cls(
|
|
136
|
+
"rounded-lg truncate group/nav",
|
|
137
|
+
"hover:bg-primary/5 dark:hover:bg-primary/5 text-text-primary dark:text-surface-200 hover:text-surface-900 dark:hover:text-white",
|
|
138
|
+
"flex flex-row items-center",
|
|
139
|
+
"pr-4 h-10",
|
|
140
|
+
"font-medium text-xs cursor-pointer",
|
|
141
|
+
activeSection === s.id ? "bg-primary/8 dark:bg-primary/10 text-primary dark:text-primary" : ""
|
|
142
|
+
)}
|
|
143
|
+
>
|
|
144
|
+
<div className={cls("shrink-0 flex items-center justify-center w-[56px] h-[40px] text-surface-500 dark:text-text-secondary-dark transition-colors duration-150 group-hover/nav:text-primary", activeSection === s.id && "text-primary dark:text-primary")}>
|
|
145
|
+
<IconComponent size={iconSize.small}/>
|
|
146
|
+
</div>
|
|
147
|
+
<div className="text-text-primary dark:text-surface-200 opacity-100 font-inherit truncate space-x-2">
|
|
148
|
+
{s.label.toUpperCase()}
|
|
149
|
+
</div>
|
|
148
150
|
</div>
|
|
149
151
|
</div>
|
|
150
|
-
|
|
151
|
-
)
|
|
152
|
+
);
|
|
153
|
+
})}
|
|
152
154
|
</div>
|
|
153
155
|
</div>
|
|
154
156
|
</div>
|
|
@@ -171,8 +173,8 @@ block: "start" });
|
|
|
171
173
|
</div>
|
|
172
174
|
</div>
|
|
173
175
|
|
|
174
|
-
{/* ── Main
|
|
175
|
-
<div className="flex-1
|
|
176
|
+
{/* ── Main content area ───────────────────────────────────────────── */}
|
|
177
|
+
<div ref={scrollContainerRef} className="flex-1">
|
|
176
178
|
|
|
177
179
|
{/* ═══════════════════════════════════════════════
|
|
178
180
|
SECTION: Drawer
|
|
@@ -187,7 +189,7 @@ block: "start" });
|
|
|
187
189
|
{/* Collapsed — exact markup from DefaultDrawer + DrawerNavigationItem */}
|
|
188
190
|
<div>
|
|
189
191
|
<Typography variant="caption" color="secondary" className="block mb-1">Collapsed (72px)</Typography>
|
|
190
|
-
<div className={cls("flex flex-col h-72 relative w-[72px] border rounded-lg overflow-hidden", defaultBorderMixin)}>
|
|
192
|
+
<div className={cls("flex flex-col h-72 relative w-[72px] border rounded-lg overflow-hidden bg-white dark:bg-surface-900", defaultBorderMixin)}>
|
|
191
193
|
<div className="flex flex-row items-center shrink-0 pt-4 pb-2 px-2">
|
|
192
194
|
<div className="shrink-0 flex items-center justify-center w-[56px] h-[40px]">
|
|
193
195
|
<RebaseLogo width="28px" height="28px"/>
|
|
@@ -197,7 +199,7 @@ block: "start" });
|
|
|
197
199
|
<div className="my-2 mx-2 flex flex-col">
|
|
198
200
|
<div className="overflow-hidden rounded-lg bg-surface-50 dark:bg-surface-950/30">
|
|
199
201
|
{[<FolderIcon key="folder" size={iconSize.small}/>, <UserIcon key="user" size={iconSize.small}/>, <TagIcon key="tag" size={iconSize.small}/>].map((icon, i) => (
|
|
200
|
-
<div key={i} className="rounded-lg truncate hover:bg-
|
|
202
|
+
<div key={i} className="rounded-lg truncate hover:bg-primary/5 dark:hover:bg-primary/5 flex flex-row items-center h-10">
|
|
201
203
|
<div className="shrink-0 flex items-center justify-center w-[56px] h-[40px] text-text-secondary dark:text-text-secondary-dark">
|
|
202
204
|
{icon}
|
|
203
205
|
</div>
|
|
@@ -219,7 +221,7 @@ block: "start" });
|
|
|
219
221
|
{/* Expanded — exact markup from DefaultDrawer + DrawerNavigationGroup + DrawerNavigationItem */}
|
|
220
222
|
<div>
|
|
221
223
|
<Typography variant="caption" color="secondary" className="block mb-1">Expanded (280px)</Typography>
|
|
222
|
-
<div className={cls("flex flex-col h-72 relative w-[280px] border rounded-lg overflow-hidden", defaultBorderMixin)}>
|
|
224
|
+
<div className={cls("flex flex-col h-72 relative w-[280px] border rounded-lg overflow-hidden bg-white dark:bg-surface-900", defaultBorderMixin)}>
|
|
223
225
|
{/* DrawerLogo */}
|
|
224
226
|
<div className="flex flex-row items-center shrink-0 pt-4 pb-2 px-2">
|
|
225
227
|
<div className="shrink-0 flex items-center justify-center w-[56px] h-[40px]">
|
|
@@ -249,10 +251,10 @@ icon: <TagIcon size={iconSize.small}/>,
|
|
|
249
251
|
active: false }
|
|
250
252
|
].map(({ label, icon, active }) => (
|
|
251
253
|
<div key={label} className={cls(
|
|
252
|
-
"rounded-lg truncate hover:bg-
|
|
253
|
-
active ? "bg-
|
|
254
|
+
"rounded-lg truncate hover:bg-primary/5 dark:hover:bg-primary/5 text-text-primary dark:text-surface-200 hover:text-surface-900 dark:hover:text-white flex flex-row items-center pr-4 h-10 font-medium text-xs cursor-pointer",
|
|
255
|
+
active ? "bg-primary/8 dark:bg-primary/10 text-primary dark:text-primary" : ""
|
|
254
256
|
)}>
|
|
255
|
-
<div className="shrink-0 flex items-center justify-center w-[56px] h-[40px] text-text-
|
|
257
|
+
<div className={cls("shrink-0 flex items-center justify-center w-[56px] h-[40px] transition-colors duration-150", active ? "text-primary dark:text-primary" : "text-surface-500 dark:text-text-secondary-dark")}>
|
|
256
258
|
{icon}
|
|
257
259
|
</div>
|
|
258
260
|
<div className="text-text-primary dark:text-surface-200 font-inherit truncate">
|
|
@@ -623,15 +625,31 @@ selected: true }, { name: "Tags" }].map(c => (
|
|
|
623
625
|
</div>
|
|
624
626
|
</div>
|
|
625
627
|
<div>
|
|
626
|
-
<Typography variant="caption" color="secondary" className="block mb-2 font-mono">IconButton</Typography>
|
|
628
|
+
<Typography variant="caption" color="secondary" className="block mb-2 font-mono">IconButton — sizes</Typography>
|
|
627
629
|
<div className="flex flex-wrap gap-3 items-center">
|
|
628
|
-
{([
|
|
629
|
-
<
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
630
|
+
{([
|
|
631
|
+
{ s: "smallest" as const, icon: <PencilIcon size={14}/> },
|
|
632
|
+
{ s: "small" as const, icon: <PencilIcon size={16}/> },
|
|
633
|
+
{ s: "medium" as const, icon: <PencilIcon size={20}/> },
|
|
634
|
+
{ s: "large" as const, icon: <PencilIcon size={24}/> }
|
|
635
|
+
]).map(({ s, icon }) => (
|
|
636
|
+
<div key={s} className="flex flex-col items-center gap-1">
|
|
637
|
+
<IconButton size={s}>{icon}</IconButton>
|
|
638
|
+
<Typography variant="caption" color="secondary">{s}</Typography>
|
|
639
|
+
</div>
|
|
633
640
|
))}
|
|
634
|
-
<
|
|
641
|
+
<div className="flex flex-col items-center gap-1">
|
|
642
|
+
<IconButton disabled><Trash2Icon size={20}/></IconButton>
|
|
643
|
+
<Typography variant="caption" color="secondary">disabled</Typography>
|
|
644
|
+
</div>
|
|
645
|
+
<div className="flex flex-col items-center gap-1">
|
|
646
|
+
<IconButton variant="filled"><PlusIcon size={20}/></IconButton>
|
|
647
|
+
<Typography variant="caption" color="secondary">filled</Typography>
|
|
648
|
+
</div>
|
|
649
|
+
<div className="flex flex-col items-center gap-1">
|
|
650
|
+
<IconButton shape="square"><SettingsIcon size={20}/></IconButton>
|
|
651
|
+
<Typography variant="caption" color="secondary">square</Typography>
|
|
652
|
+
</div>
|
|
635
653
|
</div>
|
|
636
654
|
</div>
|
|
637
655
|
<div>
|
|
@@ -706,17 +724,37 @@ selected: true }, { name: "Tags" }].map(c => (
|
|
|
706
724
|
SECTION: Chips & Alerts
|
|
707
725
|
═══════════════════════════════════════════════ */}
|
|
708
726
|
<SectionBlock id="chips-alerts" title="Chips & Alerts">
|
|
709
|
-
<Typography variant="caption" color="secondary" className="block mb-2 font-mono">Chip — colorScheme
|
|
727
|
+
<Typography variant="caption" color="secondary" className="block mb-2 font-mono">Chip — colorScheme</Typography>
|
|
710
728
|
<div className="flex flex-wrap gap-2 mb-4">
|
|
711
|
-
{(["
|
|
712
|
-
<Chip key={s} colorScheme={s}
|
|
729
|
+
{(["blue", "teal", "red", "green", "yellow", "orange", "purple", "pink", "cyan", "indigo", "violet", "fuchsia", "rose", "emerald", "gray"] as const).map(s => (
|
|
730
|
+
<Chip key={s} colorScheme={s}>{s}</Chip>
|
|
713
731
|
))}
|
|
714
732
|
</div>
|
|
715
|
-
<
|
|
716
|
-
|
|
717
|
-
|
|
733
|
+
<Typography variant="caption" color="secondary" className="block mb-2 font-mono">Chip — sizes</Typography>
|
|
734
|
+
<div className="flex flex-wrap gap-2 items-center mb-4">
|
|
735
|
+
{(["smallest", "small", "medium", "large"] as const).map(sz => (
|
|
736
|
+
<Chip key={sz} colorScheme="blue" size={sz}>{sz}</Chip>
|
|
718
737
|
))}
|
|
719
738
|
</div>
|
|
739
|
+
<Typography variant="caption" color="secondary" className="block mb-2 font-mono">Chip — outlined, error, clickable, icon</Typography>
|
|
740
|
+
<div className="flex flex-wrap gap-2 items-center mb-4">
|
|
741
|
+
<Chip colorScheme="red" outlined>Outlined Red</Chip>
|
|
742
|
+
<Chip colorScheme="blue" outlined>Outlined Blue</Chip>
|
|
743
|
+
<Chip error>Error</Chip>
|
|
744
|
+
<Chip error outlined>Error Outlined</Chip>
|
|
745
|
+
<Chip onClick={() => {}}>Clickable</Chip>
|
|
746
|
+
<Chip icon={<TagIcon size={12}/>} colorScheme="teal">With Icon</Chip>
|
|
747
|
+
<Chip>Default (no scheme)</Chip>
|
|
748
|
+
<Chip outlined>Default Outlined</Chip>
|
|
749
|
+
</div>
|
|
750
|
+
<Typography variant="caption" color="secondary" className="block mb-2 font-mono">FilterChip</Typography>
|
|
751
|
+
<div className="flex flex-wrap gap-2 items-center mb-6">
|
|
752
|
+
<FilterChip active>Active</FilterChip>
|
|
753
|
+
<FilterChip>Inactive</FilterChip>
|
|
754
|
+
<FilterChip icon={<FilterIcon size={12}/>} active>With Icon</FilterChip>
|
|
755
|
+
<FilterChip size="small">Small</FilterChip>
|
|
756
|
+
<FilterChip disabled>Disabled</FilterChip>
|
|
757
|
+
</div>
|
|
720
758
|
<Typography variant="caption" color="secondary" className="block mb-2 font-mono">Alert — color variants</Typography>
|
|
721
759
|
<div className="flex flex-col gap-2">
|
|
722
760
|
<Alert color="info">Info — informational message</Alert>
|
|
@@ -850,136 +888,6 @@ roles: [] }
|
|
|
850
888
|
</div>
|
|
851
889
|
</div>
|
|
852
890
|
</SectionBlock>
|
|
853
|
-
|
|
854
|
-
{/* ═══════════════════════════════════════════════
|
|
855
|
-
SECTION: Roles View
|
|
856
|
-
═══════════════════════════════════════════════ */}
|
|
857
|
-
<SectionBlock id="roles" title="Roles View — RolesView.tsx">
|
|
858
|
-
<Typography variant="body2" color="secondary" className="mb-4">
|
|
859
|
-
Layout from <code className="font-mono text-xs">RolesView</code>: same header pattern, table, and <code className="font-mono text-xs">CollectionPermissionsMatrix</code> with <code className="font-mono text-xs">defaultBorderMixin</code>.
|
|
860
|
-
</Typography>
|
|
861
|
-
<div className="flex items-center mt-12">
|
|
862
|
-
<Typography gutterBottom variant="h4" className="grow" component="h4">Roles</Typography>
|
|
863
|
-
<Button startIcon={<PlusIcon/>}>Add role</Button>
|
|
864
|
-
</div>
|
|
865
|
-
<div className="w-full overflow-auto">
|
|
866
|
-
<Table className="w-full">
|
|
867
|
-
<TableHeader>
|
|
868
|
-
<TableCell header className="w-16"></TableCell>
|
|
869
|
-
<TableCell header>Role</TableCell>
|
|
870
|
-
<TableCell header className="items-center">Is Admin</TableCell>
|
|
871
|
-
</TableHeader>
|
|
872
|
-
<TableBody>
|
|
873
|
-
{[
|
|
874
|
-
{ id: "admin",
|
|
875
|
-
name: "Admin",
|
|
876
|
-
isAdmin: true },
|
|
877
|
-
{ id: "editor",
|
|
878
|
-
name: "Editor",
|
|
879
|
-
isAdmin: false },
|
|
880
|
-
{ id: "viewer",
|
|
881
|
-
name: "Viewer",
|
|
882
|
-
isAdmin: false }
|
|
883
|
-
].map(role => (
|
|
884
|
-
<TableRow key={role.id}>
|
|
885
|
-
<TableCell style={{ width: "64px" }}>
|
|
886
|
-
{!role.isAdmin && (
|
|
887
|
-
<Tooltip asChild title="Delete this role">
|
|
888
|
-
<IconButton size="small"><Trash2Icon/></IconButton>
|
|
889
|
-
</Tooltip>
|
|
890
|
-
)}
|
|
891
|
-
</TableCell>
|
|
892
|
-
<TableCell>
|
|
893
|
-
<Chip colorScheme={role.isAdmin ? "purpleDark" : "blueDark"} size="small">{role.name}</Chip>
|
|
894
|
-
</TableCell>
|
|
895
|
-
<TableCell className="items-center">
|
|
896
|
-
<Checkbox checked={role.isAdmin ?? false} disabled/>
|
|
897
|
-
</TableCell>
|
|
898
|
-
</TableRow>
|
|
899
|
-
))}
|
|
900
|
-
</TableBody>
|
|
901
|
-
</Table>
|
|
902
|
-
</div>
|
|
903
|
-
{/* CollectionPermissionsMatrix — from RolesView line 365-406 */}
|
|
904
|
-
<div className="mt-4">
|
|
905
|
-
<Typography variant="label" className="mb-2 block text-surface-500 dark:text-surface-400 uppercase tracking-wide text-xs">
|
|
906
|
-
Collection permissions
|
|
907
|
-
</Typography>
|
|
908
|
-
<div className={`rounded-lg overflow-hidden border w-full ${defaultBorderMixin}`}>
|
|
909
|
-
<Table className="w-full">
|
|
910
|
-
<TableHeader>
|
|
911
|
-
<TableCell header>Collection</TableCell>
|
|
912
|
-
{["Read", "Create", "Edit", "Delete"].map(op => (
|
|
913
|
-
<TableCell key={op} header align="center" className="w-20">{op}</TableCell>
|
|
914
|
-
))}
|
|
915
|
-
</TableHeader>
|
|
916
|
-
<TableBody>
|
|
917
|
-
{[{ name: "Posts",
|
|
918
|
-
slug: "posts" }, { name: "Authors",
|
|
919
|
-
slug: "authors" }].map(col => (
|
|
920
|
-
<TableRow key={col.slug}>
|
|
921
|
-
<TableCell>
|
|
922
|
-
<div className="flex items-center gap-1.5">
|
|
923
|
-
<span className="font-medium">{col.name}</span>
|
|
924
|
-
<Tooltip title="No security rules defined — all operations unrestricted">
|
|
925
|
-
<Chip size="smallest" colorScheme="gray">no rules</Chip>
|
|
926
|
-
</Tooltip>
|
|
927
|
-
</div>
|
|
928
|
-
<span className="text-xs text-surface-400 font-mono">{col.slug}</span>
|
|
929
|
-
</TableCell>
|
|
930
|
-
{["select", "insert", "update", "delete"].map(op => (
|
|
931
|
-
<TableCell key={op} align="center" className="w-20">
|
|
932
|
-
<span className="text-green-500 dark:text-green-400 font-bold">✓</span>
|
|
933
|
-
</TableCell>
|
|
934
|
-
))}
|
|
935
|
-
</TableRow>
|
|
936
|
-
))}
|
|
937
|
-
</TableBody>
|
|
938
|
-
</Table>
|
|
939
|
-
</div>
|
|
940
|
-
</div>
|
|
941
|
-
</SectionBlock>
|
|
942
|
-
|
|
943
|
-
{/* ═══════════════════════════════════════════════
|
|
944
|
-
SECTION: Role Dialog
|
|
945
|
-
═══════════════════════════════════════════════ */}
|
|
946
|
-
<SectionBlock id="role-dialog" title="Role Dialog — RoleDetailsForm">
|
|
947
|
-
<Typography variant="body2" color="secondary" className="mb-4">
|
|
948
|
-
Exact structure of <code className="font-mono text-xs">RoleDetailsForm</code>: <code className="font-mono text-xs">col-span-4</code> grid, Role ID + Name + Is Admin checkbox.
|
|
949
|
-
</Typography>
|
|
950
|
-
<div className={`rounded-lg border w-full max-w-xl ${defaultBorderMixin}`}>
|
|
951
|
-
<div className="px-6 pt-6 pb-2">
|
|
952
|
-
<Typography variant="h4">Role</Typography>
|
|
953
|
-
</div>
|
|
954
|
-
<div className="px-6 py-4">
|
|
955
|
-
<div className="grid grid-cols-12 gap-4">
|
|
956
|
-
<div className="col-span-12 sm:col-span-4">
|
|
957
|
-
<TextField name="id" required value="editor" onChange={() => {}} label="Role ID" disabled/>
|
|
958
|
-
</div>
|
|
959
|
-
<div className="col-span-12 sm:col-span-4">
|
|
960
|
-
<TextField name="name" required value="Editor" onChange={() => {}} label="Role Name"/>
|
|
961
|
-
</div>
|
|
962
|
-
<div className="col-span-12 sm:col-span-4 flex items-start pt-2">
|
|
963
|
-
<label className="flex items-center gap-2 cursor-pointer mt-3">
|
|
964
|
-
<Checkbox checked={false} onCheckedChange={() => {}}/>
|
|
965
|
-
<span className="font-medium">Is Admin</span>
|
|
966
|
-
</label>
|
|
967
|
-
</div>
|
|
968
|
-
</div>
|
|
969
|
-
</div>
|
|
970
|
-
<div className="flex items-center justify-end gap-2 px-6 pb-6">
|
|
971
|
-
<Button variant="text">Cancel</Button>
|
|
972
|
-
<LoadingButton variant="filled" loading={false}>Update</LoadingButton>
|
|
973
|
-
</div>
|
|
974
|
-
</div>
|
|
975
|
-
</SectionBlock>
|
|
976
|
-
|
|
977
|
-
{/* Footer */}
|
|
978
|
-
<div className="px-6 py-8">
|
|
979
|
-
<Typography variant="caption" color="secondary">
|
|
980
|
-
Hidden debug reference — <code className="font-mono text-xs">/debug/ui</code>. Not linked from sidebar.
|
|
981
|
-
</Typography>
|
|
982
|
-
</div>
|
|
983
891
|
</div>
|
|
984
892
|
</div>
|
|
985
893
|
);
|