betterstart-cli 0.0.12 → 0.0.14
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/assets/adapters/next/plugins/blog/plugin.ts +1 -1
- package/dist/assets/adapters/next/plugins/blog/schemas/menus.json +155 -0
- package/dist/assets/adapters/next/plugins/blog/schemas/posts.json +2 -7
- package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar.tsx +9 -3
- package/dist/assets/adapters/next/templates/init/components/layouts/sidebar-branding.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-grid.tsx +107 -0
- package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table.tsx +58 -45
- package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/lifecycle-hooks-tab.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/dev-mode-integrate.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/entity-filters-bar.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-versions-drawer.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/page-header.tsx +20 -17
- package/dist/assets/adapters/next/templates/init/components/shared/sort-indicator.tsx +7 -3
- package/dist/assets/adapters/next/templates/init/data/navigation.ts +4 -1
- package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-slash-menu.ts +28 -2
- package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor.ts +22 -1
- package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-table-button.ts +85 -0
- package/dist/assets/adapters/next/templates/init/hooks/use-audit-log.ts +23 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/cleanup-audit-logs.ts +63 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/get-audit-logs.ts +122 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/index.ts +19 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/record-audit-event.ts +37 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/register.ts +13 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/request-metadata.ts +37 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/types.ts +77 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/forms/upsert-form-settings.ts +3 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/media/create-media.ts +19 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media-bulk.ts +23 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media.ts +21 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/media/update-media.ts +23 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/profile/update-email.ts +17 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-files.ts +3 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-media-from-url.ts +3 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/users/create-user.ts +19 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/users/delete-user.ts +23 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/users/update-user-role.ts +23 -1
- package/dist/assets/adapters/next/templates/init/lib/db/core/schema.ts +49 -0
- package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/index.ts +6 -1
- package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/register.ts +3 -0
- package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/registry.ts +36 -1
- package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/runner.ts +117 -12
- package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/types.ts +35 -1
- package/dist/assets/adapters/next/templates/init/pages/audit-log/audit-log-detail-drawer.tsx +104 -0
- package/dist/assets/adapters/next/templates/init/pages/audit-log/audit-log-detail-row.tsx +15 -0
- package/dist/assets/adapters/next/templates/init/pages/audit-log/audit-log-page-content.tsx +565 -0
- package/dist/assets/adapters/next/templates/init/pages/audit-log/audit-log-page-skeleton.tsx +7 -0
- package/dist/assets/adapters/next/templates/init/pages/audit-log/audit-log-page.tsx +14 -0
- package/dist/assets/adapters/next/templates/init/pages/users/users-page-content.tsx +83 -2
- package/dist/assets/adapters/next/templates/init/pages/users/users-table.tsx +126 -78
- package/dist/assets/adapters/next/templates/init/utils/audit/audit.ts +54 -0
- package/dist/assets/adapters/next/templates/init/utils/editor/tiptap.ts +7 -32
- package/dist/assets/adapters/next/templates/init/utils/form/list-field.ts +17 -0
- package/dist/assets/adapters/next/templates/init/utils/user/user.ts +70 -0
- package/dist/assets/shared-assets/react-admin/custom/content-editor/horizontal-rule-button.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/index.tsx +6 -0
- package/dist/assets/shared-assets/react-admin/custom/content-editor/main-toolbar-content.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/math-button.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/math-editor-controls.tsx +27 -40
- package/dist/assets/shared-assets/react-admin/custom/content-editor/math-popover-button.tsx +0 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/mobile-toolbar-content.tsx +4 -4
- package/dist/assets/shared-assets/react-admin/custom/content-editor/mode-toggle-button.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/selection-bubble-menu.tsx +45 -8
- package/dist/assets/shared-assets/react-admin/custom/content-editor/slash-command-menu.tsx +153 -27
- package/dist/assets/shared-assets/react-admin/custom/content-editor/source-mode-dropdown-button.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/source-mode.tsx +9 -11
- package/dist/assets/shared-assets/react-admin/custom/content-editor/table-bubble-menu.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/table-button.tsx +24 -67
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/blockquote-button/blockquote-button.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/code-block-button/code-block-button.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover-button.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover-content.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover.tsx +11 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/source-color-highlight-popover.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu-item.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu.tsx +9 -4
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-button.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-control-popover.tsx +5 -12
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-main.tsx +19 -45
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-popover.tsx +2 -3
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/list-dropdown-menu/list-dropdown-menu-item.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/list-dropdown-menu/list-dropdown-menu.tsx +9 -4
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/mark-button/mark-button.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/undo-redo-button/undo-redo-button.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/date-range-picker.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/custom/dynamic-list-field.tsx +20 -8
- package/dist/assets/shared-assets/react-admin/custom/media-gallery-field.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/nested-object-list-field.tsx +211 -0
- package/dist/assets/shared-assets/react-admin/schema.json +136 -23
- package/dist/assets/shared-assets/react-admin/ui/button.tsx +18 -18
- package/dist/assets/shared-assets/react-admin/ui/card.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/checkbox.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/combobox.tsx +27 -3
- package/dist/assets/shared-assets/react-admin/ui/drawer.tsx +9 -5
- package/dist/assets/shared-assets/react-admin/ui/dropdown-menu.tsx +27 -12
- package/dist/assets/shared-assets/react-admin/ui/form.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/sidebar.tsx +4 -4
- package/dist/cli.js +5396 -2385
- package/dist/cli.js.map +1 -1
- package/package.json +10 -2
|
@@ -8,7 +8,7 @@ export const blogPlugin: BetterstartPluginDefinition = {
|
|
|
8
8
|
version: '1.0.0',
|
|
9
9
|
dependencies: [],
|
|
10
10
|
conflicts: [],
|
|
11
|
-
schemaFiles: ['posts.json'],
|
|
11
|
+
schemaFiles: ['posts.json', 'menus.json'],
|
|
12
12
|
files: [],
|
|
13
13
|
packageDependencies: ['katex', 'markdown-it@^13.0.2', 'markdown-it-dollarmath', 'sanitize-html'],
|
|
14
14
|
devDependencies: ['@types/markdown-it@13', '@types/sanitize-html'],
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "menus",
|
|
3
|
+
"label": "Menus",
|
|
4
|
+
"description": "Manage Menus",
|
|
5
|
+
"icon": "Menu",
|
|
6
|
+
"navGroup": {
|
|
7
|
+
"label": "General",
|
|
8
|
+
"position": 0
|
|
9
|
+
},
|
|
10
|
+
"navPosition": 1,
|
|
11
|
+
"slot": {
|
|
12
|
+
"main": {
|
|
13
|
+
"fields": [
|
|
14
|
+
{
|
|
15
|
+
"name": "title",
|
|
16
|
+
"type": "string",
|
|
17
|
+
"label": "Title",
|
|
18
|
+
"required": true
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "slug",
|
|
22
|
+
"type": "string",
|
|
23
|
+
"label": "Slug",
|
|
24
|
+
"hint": "URL-friendly identifier (auto-generated from title)"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "items",
|
|
28
|
+
"type": "list",
|
|
29
|
+
"label": "Items",
|
|
30
|
+
"hint": "Items in the navigation menu",
|
|
31
|
+
"fields": [
|
|
32
|
+
{
|
|
33
|
+
"name": "parentFields",
|
|
34
|
+
"type": "group",
|
|
35
|
+
"columns": 2,
|
|
36
|
+
"fields": [
|
|
37
|
+
{
|
|
38
|
+
"name": "label",
|
|
39
|
+
"type": "string",
|
|
40
|
+
"label": "Label",
|
|
41
|
+
"required": true
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "href",
|
|
45
|
+
"type": "string",
|
|
46
|
+
"label": "Href",
|
|
47
|
+
"required": true
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "openInNewTab",
|
|
53
|
+
"type": "boolean",
|
|
54
|
+
"label": "Open in New Tab",
|
|
55
|
+
"hint": "Open this link in a new browser tab",
|
|
56
|
+
"default": false
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "subItems",
|
|
60
|
+
"type": "list",
|
|
61
|
+
"label": "Sub Menu Items",
|
|
62
|
+
"fields": [
|
|
63
|
+
{
|
|
64
|
+
"name": "subItemFields",
|
|
65
|
+
"type": "group",
|
|
66
|
+
"columns": 2,
|
|
67
|
+
"fields": [
|
|
68
|
+
{
|
|
69
|
+
"name": "subItemLabel",
|
|
70
|
+
"type": "string",
|
|
71
|
+
"label": "Label",
|
|
72
|
+
"required": true
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"name": "subItemHref",
|
|
76
|
+
"type": "string",
|
|
77
|
+
"label": "Href",
|
|
78
|
+
"required": true
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "subItemOpenInNewTab",
|
|
84
|
+
"type": "boolean",
|
|
85
|
+
"label": "Open in New Tab",
|
|
86
|
+
"hint": "Open this link in a new browser tab",
|
|
87
|
+
"default": false
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
"sidebar": {
|
|
96
|
+
"fields": [
|
|
97
|
+
{
|
|
98
|
+
"name": "generalSidebar",
|
|
99
|
+
"type": "section",
|
|
100
|
+
"heading": {
|
|
101
|
+
"icon": "bolt",
|
|
102
|
+
"title": "General"
|
|
103
|
+
},
|
|
104
|
+
"fields": [
|
|
105
|
+
{
|
|
106
|
+
"name": "description",
|
|
107
|
+
"type": "text",
|
|
108
|
+
"label": "Description",
|
|
109
|
+
"hint": "Internal note describing this menu's purpose"
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"columns": [
|
|
117
|
+
{
|
|
118
|
+
"accessorKey": "title",
|
|
119
|
+
"header": "Title",
|
|
120
|
+
"type": "text",
|
|
121
|
+
"sortable": true,
|
|
122
|
+
"size": "xl"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"accessorKey": "published",
|
|
126
|
+
"header": "Status",
|
|
127
|
+
"type": "boolean",
|
|
128
|
+
"sortable": true,
|
|
129
|
+
"size": "sm"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"accessorKey": "updatedAt",
|
|
133
|
+
"header": "Updated",
|
|
134
|
+
"type": "date",
|
|
135
|
+
"sortable": true,
|
|
136
|
+
"size": "sm"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"accessorKey": "createdAt",
|
|
140
|
+
"header": "Created",
|
|
141
|
+
"type": "date",
|
|
142
|
+
"sortable": true,
|
|
143
|
+
"size": "sm"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"actions": {
|
|
147
|
+
"create": true,
|
|
148
|
+
"edit": true,
|
|
149
|
+
"delete": true,
|
|
150
|
+
"draft": true
|
|
151
|
+
},
|
|
152
|
+
"search": {
|
|
153
|
+
"fields": ["title"]
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "posts",
|
|
3
3
|
"label": "Posts",
|
|
4
|
-
"description": "Manage blog posts
|
|
4
|
+
"description": "Manage blog posts",
|
|
5
5
|
"icon": "FileText",
|
|
6
6
|
"navGroup": {
|
|
7
|
-
"label": "
|
|
7
|
+
"label": "Collections",
|
|
8
8
|
"position": 0
|
|
9
9
|
},
|
|
10
10
|
"navPosition": 0,
|
|
@@ -160,10 +160,5 @@
|
|
|
160
160
|
},
|
|
161
161
|
"search": {
|
|
162
162
|
"fields": ["title", "excerpt"]
|
|
163
|
-
},
|
|
164
|
-
"autoSlugify": {
|
|
165
|
-
"enabled": true,
|
|
166
|
-
"sourceField": "title",
|
|
167
|
-
"targetField": "slug"
|
|
168
163
|
}
|
|
169
164
|
}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from '@admin/components/ui/sidebar'
|
|
12
12
|
import { adminNavigation } from '@admin/data/navigation'
|
|
13
13
|
import { groupAdminNavigationItems } from '@admin/utils/navigation/sidebar'
|
|
14
|
-
import { Settings, Users } from 'lucide-react'
|
|
14
|
+
import { History, Settings, Users } from 'lucide-react'
|
|
15
15
|
import type { ComponentProps } from 'react'
|
|
16
16
|
import { Fragment, Suspense } from 'react'
|
|
17
17
|
import { SidebarBrandingRsc } from './admin-sidebar-branding-rsc'
|
|
@@ -35,7 +35,7 @@ export function AdminSidebar(props: ComponentProps<typeof Sidebar>) {
|
|
|
35
35
|
<Fragment key={group.label ?? '_ungrouped'}>
|
|
36
36
|
<SidebarGroup className="py-0">
|
|
37
37
|
{group.label && <SidebarGroupLabel>{group.label}</SidebarGroupLabel>}
|
|
38
|
-
<SidebarMenu className="gap-
|
|
38
|
+
<SidebarMenu className="gap-0.5">
|
|
39
39
|
{group.items.map((item) => (
|
|
40
40
|
<SidebarMenuItem key={item.href}>
|
|
41
41
|
<SidebarNavLink href={item.href}>
|
|
@@ -51,7 +51,7 @@ export function AdminSidebar(props: ComponentProps<typeof Sidebar>) {
|
|
|
51
51
|
|
|
52
52
|
<SidebarGroup className="mt-auto gap-2 px-0">
|
|
53
53
|
<Separator />
|
|
54
|
-
<SidebarMenu className="px-2 gap-
|
|
54
|
+
<SidebarMenu className="px-2 gap-0.5">
|
|
55
55
|
<SidebarMenuItem>
|
|
56
56
|
<SidebarNavLink href="/admin/users">
|
|
57
57
|
<Users strokeWidth={2} />
|
|
@@ -64,6 +64,12 @@ export function AdminSidebar(props: ComponentProps<typeof Sidebar>) {
|
|
|
64
64
|
<span>Settings</span>
|
|
65
65
|
</SidebarNavLink>
|
|
66
66
|
</SidebarMenuItem>
|
|
67
|
+
<SidebarMenuItem>
|
|
68
|
+
<SidebarNavLink href="/admin/system/audit-log">
|
|
69
|
+
<History strokeWidth={2} />
|
|
70
|
+
<span>Audit Log</span>
|
|
71
|
+
</SidebarNavLink>
|
|
72
|
+
</SidebarMenuItem>
|
|
67
73
|
</SidebarMenu>
|
|
68
74
|
</SidebarGroup>
|
|
69
75
|
</SidebarContent>
|
|
@@ -20,7 +20,7 @@ export function SidebarBranding({ initialData }: SidebarBrandingProps) {
|
|
|
20
20
|
return <BrandingSkeleton />
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const dashboardName = settings?.
|
|
23
|
+
const dashboardName = settings?.title ?? admin.name
|
|
24
24
|
const dashboardLogo = settings?.dashboardLogo || DEFAULT_LOGO_URL
|
|
25
25
|
|
|
26
26
|
return (
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { cn } from '@admin/utils/shared/cn'
|
|
4
|
+
import type * as React from 'react'
|
|
5
|
+
|
|
6
|
+
type DataGridProps = React.ComponentProps<'div'> & {
|
|
7
|
+
containerClassName?: string
|
|
8
|
+
gridTemplateColumns: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const dataGridTableRole = { role: 'table' } as const
|
|
12
|
+
const dataGridRowGroupRole = { role: 'rowgroup' } as const
|
|
13
|
+
const dataGridRowRole = { role: 'row' } as const
|
|
14
|
+
const dataGridColumnHeaderRole = { role: 'columnheader' } as const
|
|
15
|
+
const dataGridCellRole = { role: 'cell' } as const
|
|
16
|
+
|
|
17
|
+
function DataGrid({
|
|
18
|
+
className,
|
|
19
|
+
containerClassName,
|
|
20
|
+
gridTemplateColumns,
|
|
21
|
+
style,
|
|
22
|
+
...props
|
|
23
|
+
}: DataGridProps) {
|
|
24
|
+
return (
|
|
25
|
+
<div
|
|
26
|
+
data-slot="data-grid-container"
|
|
27
|
+
className={cn('relative min-w-0 overflow-auto', containerClassName)}
|
|
28
|
+
>
|
|
29
|
+
<div
|
|
30
|
+
{...dataGridTableRole}
|
|
31
|
+
data-slot="data-grid"
|
|
32
|
+
className={cn('grid min-w-full text-sm', className)}
|
|
33
|
+
style={{ ...style, gridTemplateColumns }}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function DataGridHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
{...dataGridRowGroupRole}
|
|
44
|
+
data-slot="data-grid-header"
|
|
45
|
+
className={cn('contents', className)}
|
|
46
|
+
{...props}
|
|
47
|
+
/>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function DataGridBody({ className, ...props }: React.ComponentProps<'div'>) {
|
|
52
|
+
return (
|
|
53
|
+
<div
|
|
54
|
+
{...dataGridRowGroupRole}
|
|
55
|
+
data-slot="data-grid-body"
|
|
56
|
+
className={cn('contents', className)}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function DataGridRow({ className, style, ...props }: React.ComponentProps<'div'>) {
|
|
63
|
+
return (
|
|
64
|
+
<div
|
|
65
|
+
{...dataGridRowRole}
|
|
66
|
+
data-slot="data-grid-row"
|
|
67
|
+
className={cn(
|
|
68
|
+
'grid border-b transition-colors has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted',
|
|
69
|
+
className
|
|
70
|
+
)}
|
|
71
|
+
style={{ ...style, gridColumn: '1 / -1', gridTemplateColumns: 'subgrid' }}
|
|
72
|
+
tabIndex={-1}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function DataGridHead({ className, ...props }: React.ComponentProps<'div'>) {
|
|
79
|
+
return (
|
|
80
|
+
<div
|
|
81
|
+
{...dataGridColumnHeaderRole}
|
|
82
|
+
data-slot="data-grid-head"
|
|
83
|
+
className={cn(
|
|
84
|
+
'grid h-10 items-center px-3 text-left font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0',
|
|
85
|
+
className
|
|
86
|
+
)}
|
|
87
|
+
tabIndex={-1}
|
|
88
|
+
{...props}
|
|
89
|
+
/>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function DataGridCell({ className, ...props }: React.ComponentProps<'div'>) {
|
|
94
|
+
return (
|
|
95
|
+
<div
|
|
96
|
+
{...dataGridCellRole}
|
|
97
|
+
data-slot="data-grid-cell"
|
|
98
|
+
className={cn(
|
|
99
|
+
'grid min-h-10 items-center px-3 py-1.5 whitespace-nowrap [&:has([role=checkbox])]:pr-0',
|
|
100
|
+
className
|
|
101
|
+
)}
|
|
102
|
+
{...props}
|
|
103
|
+
/>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export { DataGrid, DataGridHeader, DataGridBody, DataGridHead, DataGridRow, DataGridCell }
|
package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table.tsx
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from '@admin/components/
|
|
4
|
+
DataGrid,
|
|
5
|
+
DataGridBody,
|
|
6
|
+
DataGridCell,
|
|
7
|
+
DataGridHead,
|
|
8
|
+
DataGridHeader,
|
|
9
|
+
DataGridRow
|
|
10
|
+
} from '@admin/components/shared/data-table/data-grid'
|
|
11
11
|
import { useTableUtils } from '@admin/hooks/use-table-utils'
|
|
12
12
|
import { cn } from '@admin/utils/shared/cn'
|
|
13
13
|
import {
|
|
@@ -108,19 +108,18 @@ export function DataTable<TData extends RowData, TValue>({
|
|
|
108
108
|
}
|
|
109
109
|
})
|
|
110
110
|
registerTable(table)
|
|
111
|
+
const gridTemplateColumns = table
|
|
112
|
+
.getVisibleLeafColumns()
|
|
113
|
+
.map((column) => `${column.getSize()}px`)
|
|
114
|
+
.join(' ')
|
|
111
115
|
|
|
112
116
|
return (
|
|
113
117
|
<div className="space-y-6 pb-24">
|
|
114
|
-
<div ref={tableContainerRef} className="overflow-hidden material-sm border-border">
|
|
115
|
-
<
|
|
116
|
-
<
|
|
117
|
-
{table.getVisibleLeafColumns().map((column) => (
|
|
118
|
-
<col key={column.id} style={{ width: column.getSize() }} />
|
|
119
|
-
))}
|
|
120
|
-
</colgroup>
|
|
121
|
-
<TableHeader>
|
|
118
|
+
<div ref={tableContainerRef} className="min-w-0 overflow-hidden material-sm border-border">
|
|
119
|
+
<DataGrid gridTemplateColumns={gridTemplateColumns} style={{ width: table.getTotalSize() }}>
|
|
120
|
+
<DataGridHeader>
|
|
122
121
|
{table.getHeaderGroups().map((headerGroup) => (
|
|
123
|
-
<
|
|
122
|
+
<DataGridRow key={headerGroup.id}>
|
|
124
123
|
{headerGroup.headers.map((header, headerIndex) => {
|
|
125
124
|
const meta = header.column.columnDef.meta as Record<string, unknown> | undefined
|
|
126
125
|
const resizeLabel =
|
|
@@ -131,12 +130,15 @@ export function DataTable<TData extends RowData, TValue>({
|
|
|
131
130
|
const canResizeColumn =
|
|
132
131
|
header.column.getCanResize() && nextHeader?.column.getCanResize() === true
|
|
133
132
|
return (
|
|
134
|
-
<
|
|
133
|
+
<DataGridHead
|
|
135
134
|
key={header.id}
|
|
136
|
-
className={cn(
|
|
137
|
-
'
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
className={cn(
|
|
136
|
+
'group/resize-header relative overflow-hidden text-foreground',
|
|
137
|
+
{
|
|
138
|
+
'text-center': meta?.align === 'center',
|
|
139
|
+
'text-right': meta?.align === 'right'
|
|
140
|
+
}
|
|
141
|
+
)}
|
|
140
142
|
data-column-id={header.column.id}
|
|
141
143
|
onMouseEnter={() => setHoveredColumnId(header.column.id)}
|
|
142
144
|
onMouseLeave={() =>
|
|
@@ -144,7 +146,6 @@ export function DataTable<TData extends RowData, TValue>({
|
|
|
144
146
|
current === header.column.id ? null : current
|
|
145
147
|
)
|
|
146
148
|
}
|
|
147
|
-
style={{ width: header.getSize() }}
|
|
148
149
|
>
|
|
149
150
|
{header.isPlaceholder
|
|
150
151
|
? null
|
|
@@ -166,32 +167,42 @@ export function DataTable<TData extends RowData, TValue>({
|
|
|
166
167
|
<GripVertical aria-hidden="true" className="size-3.5 text-foreground" />
|
|
167
168
|
</button>
|
|
168
169
|
) : null}
|
|
169
|
-
</
|
|
170
|
+
</DataGridHead>
|
|
170
171
|
)
|
|
171
172
|
})}
|
|
172
|
-
</
|
|
173
|
+
</DataGridRow>
|
|
173
174
|
))}
|
|
174
|
-
</
|
|
175
|
-
<
|
|
175
|
+
</DataGridHeader>
|
|
176
|
+
<DataGridBody>
|
|
176
177
|
{isPending ? (
|
|
177
|
-
<
|
|
178
|
-
<
|
|
178
|
+
<DataGridRow>
|
|
179
|
+
<DataGridCell
|
|
180
|
+
className="flex h-24 items-center justify-center text-center"
|
|
181
|
+
style={{ gridColumn: '1 / -1' }}
|
|
182
|
+
>
|
|
179
183
|
<div className="text-muted-foreground">{loadingMessage}</div>
|
|
180
|
-
</
|
|
181
|
-
</
|
|
184
|
+
</DataGridCell>
|
|
185
|
+
</DataGridRow>
|
|
182
186
|
) : error ? (
|
|
183
|
-
<
|
|
184
|
-
<
|
|
187
|
+
<DataGridRow>
|
|
188
|
+
<DataGridCell
|
|
189
|
+
className="flex h-24 items-center justify-center text-center"
|
|
190
|
+
style={{ gridColumn: '1 / -1' }}
|
|
191
|
+
>
|
|
185
192
|
<div className="text-destructive">Error: {error.message}</div>
|
|
186
|
-
</
|
|
187
|
-
</
|
|
193
|
+
</DataGridCell>
|
|
194
|
+
</DataGridRow>
|
|
188
195
|
) : table.getRowModel().rows?.length ? (
|
|
189
196
|
table.getRowModel().rows.map((row) => (
|
|
190
|
-
<
|
|
197
|
+
<DataGridRow
|
|
198
|
+
key={row.id}
|
|
199
|
+
className="hover:bg-muted/50"
|
|
200
|
+
data-state={row.getIsSelected() ? 'selected' : undefined}
|
|
201
|
+
>
|
|
191
202
|
{row.getVisibleCells().map((cell) => {
|
|
192
203
|
const meta = cell.column.columnDef.meta as Record<string, unknown> | undefined
|
|
193
204
|
return (
|
|
194
|
-
<
|
|
205
|
+
<DataGridCell
|
|
195
206
|
key={cell.id}
|
|
196
207
|
className={cn({
|
|
197
208
|
'text-center': meta?.align === 'center',
|
|
@@ -204,23 +215,25 @@ export function DataTable<TData extends RowData, TValue>({
|
|
|
204
215
|
current === cell.column.id ? null : current
|
|
205
216
|
)
|
|
206
217
|
}
|
|
207
|
-
style={{ width: cell.column.getSize() }}
|
|
208
218
|
>
|
|
209
219
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
210
|
-
</
|
|
220
|
+
</DataGridCell>
|
|
211
221
|
)
|
|
212
222
|
})}
|
|
213
|
-
</
|
|
223
|
+
</DataGridRow>
|
|
214
224
|
))
|
|
215
225
|
) : (
|
|
216
|
-
<
|
|
217
|
-
<
|
|
226
|
+
<DataGridRow>
|
|
227
|
+
<DataGridCell
|
|
228
|
+
className="flex h-24 items-center justify-center text-center"
|
|
229
|
+
style={{ gridColumn: '1 / -1' }}
|
|
230
|
+
>
|
|
218
231
|
{emptyMessage}
|
|
219
|
-
</
|
|
220
|
-
</
|
|
232
|
+
</DataGridCell>
|
|
233
|
+
</DataGridRow>
|
|
221
234
|
)}
|
|
222
|
-
</
|
|
223
|
-
</
|
|
235
|
+
</DataGridBody>
|
|
236
|
+
</DataGrid>
|
|
224
237
|
</div>
|
|
225
238
|
|
|
226
239
|
<DataTablePagination
|
package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/lifecycle-hooks-tab.tsx
CHANGED
|
@@ -54,7 +54,7 @@ export function LifecycleHooksTab({ lifecycleHooks }: LifecycleHooksTabProps) {
|
|
|
54
54
|
if (!firstHook) {
|
|
55
55
|
return (
|
|
56
56
|
<div className="flex min-h-80 items-center justify-center rounded-lg border border-dashed border-border px-6 text-center text-sm text-muted-foreground">
|
|
57
|
-
Lifecycle hook examples are generated for entity
|
|
57
|
+
Lifecycle hook examples are generated for entity and form schemas.
|
|
58
58
|
</div>
|
|
59
59
|
)
|
|
60
60
|
}
|
|
@@ -50,7 +50,7 @@ export function DevModeIntegrateButton({
|
|
|
50
50
|
<DrawerTrigger asChild>
|
|
51
51
|
<Button type="button" variant="outline">
|
|
52
52
|
<Code2 data-icon="inline-start" />
|
|
53
|
-
<span className="hidden sm:inline">
|
|
53
|
+
<span className="hidden sm:inline">Dev Mode</span>
|
|
54
54
|
</Button>
|
|
55
55
|
</DrawerTrigger>
|
|
56
56
|
<DrawerContent className="w-full overflow-hidden data-[vaul-drawer-direction=right]:sm:max-w-2xl data-[vaul-drawer-direction=right]:lg:max-w-4xl">
|
|
@@ -44,7 +44,7 @@ export function EntityVersionsDrawer({
|
|
|
44
44
|
return (
|
|
45
45
|
<Drawer direction="right" open={open} onOpenChange={onOpenChange} modal>
|
|
46
46
|
<DrawerContent className="h-full sm:max-w-lg">
|
|
47
|
-
<DrawerHeader
|
|
47
|
+
<DrawerHeader>
|
|
48
48
|
<DrawerTitle>Versions</DrawerTitle>
|
|
49
49
|
<DrawerDescription>
|
|
50
50
|
Review previous {entityType} versions and restore a saved state.
|
|
@@ -22,22 +22,25 @@ export function PageHeader({
|
|
|
22
22
|
const router = useRouter()
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
|
-
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
25
|
+
<>
|
|
26
|
+
<header className="fixed top-0 border-t right-0 left-(--admin-shell-content-left) z-20 grid h-14 grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center border-b border-border/80 px-4 bg-sidebar transition-[left] duration-200 ease-linear">
|
|
27
|
+
<div className="flex w-full items-center justify-start gap-2">
|
|
28
|
+
{hasBackButton && (
|
|
29
|
+
<Button variant="ghost" size="icon" onClick={() => router.back()}>
|
|
30
|
+
<ChevronLeft className="size-4" />
|
|
31
|
+
</Button>
|
|
32
|
+
)}
|
|
33
|
+
</div>
|
|
34
|
+
<div className="flex min-w-0 items-center justify-center gap-2">
|
|
35
|
+
<h2 className="truncate text-sm font-medium tracking-tight">{title}</h2>
|
|
36
|
+
</div>
|
|
37
|
+
<div className="flex w-full min-w-0 items-center justify-end gap-2">
|
|
38
|
+
{children && children}
|
|
39
|
+
{search && search}
|
|
40
|
+
{actions && actions}
|
|
41
|
+
</div>
|
|
42
|
+
</header>
|
|
43
|
+
<div className="h-14 shrink-0" aria-hidden="true" />
|
|
44
|
+
</>
|
|
42
45
|
)
|
|
43
46
|
}
|
|
@@ -16,9 +16,13 @@ export function SortIndicator({ direction }: { direction: false | 'asc' | 'desc'
|
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
18
|
<Icon
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
aria-hidden="true"
|
|
20
|
+
className={cn(
|
|
21
|
+
'size-4 shrink-0 text-muted-foreground opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-visible:opacity-100 group-hover/resize-header:opacity-100',
|
|
22
|
+
{
|
|
23
|
+
'text-foreground': direction !== false
|
|
24
|
+
}
|
|
25
|
+
)}
|
|
22
26
|
/>
|
|
23
27
|
)
|
|
24
28
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AdminNavigationItem } from '@admin/types/navigation'
|
|
2
2
|
import { House, ImagePlay } from 'lucide-react'
|
|
3
|
+
import { menusNav } from './navigation/menus'
|
|
3
4
|
import { postsNav } from './navigation/posts'
|
|
4
5
|
|
|
5
6
|
export type { AdminNavigationItem } from '@admin/types/navigation'
|
|
@@ -9,12 +10,14 @@ const coreNav: AdminNavigationItem[] = [
|
|
|
9
10
|
label: 'Overview',
|
|
10
11
|
href: '/admin',
|
|
11
12
|
icon: House,
|
|
13
|
+
group: 'General',
|
|
12
14
|
position: 0
|
|
13
15
|
},
|
|
14
16
|
{
|
|
15
17
|
label: 'Media',
|
|
16
18
|
href: '/admin/media',
|
|
17
19
|
icon: ImagePlay,
|
|
20
|
+
group: 'General',
|
|
18
21
|
position: 1
|
|
19
22
|
}
|
|
20
23
|
]
|
|
@@ -26,7 +29,7 @@ function comparePositions(a?: number, b?: number): number {
|
|
|
26
29
|
return 0
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
const combinedNavigation = [...coreNav, ...postsNav]
|
|
32
|
+
const combinedNavigation = [...coreNav, ...menusNav, ...postsNav]
|
|
30
33
|
|
|
31
34
|
const dashboard = combinedNavigation.find((item) => item.href === '/admin')
|
|
32
35
|
const others = combinedNavigation.filter((item) => item.href !== '/admin')
|