betterstart-cli 0.0.102 → 0.0.104

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 (147) hide show
  1. package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/index.ts +0 -5
  2. package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/send-test-webhook.ts +1 -1
  3. package/dist/assets/adapters/next/templates/renderers/commands/init/banner-art.ts +7 -0
  4. package/dist/assets/adapters/next/templates/renderers/commands/init/verify-database-reachable.ts +30 -0
  5. package/dist/assets/adapters/next/templates/renderers/commands/seed/build-seed-script.ts +171 -0
  6. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-authorship-alias-block.ts +4 -0
  7. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-authorship-data-fields.ts +4 -0
  8. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-format-action-date-source.ts +18 -0
  9. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-read-select-option-type.ts +6 -0
  10. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-relationship-data-types.ts +25 -0
  11. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-result-mapping.ts +62 -0
  12. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/generate-populate-list-rels-function.ts +50 -0
  13. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/build-restore-many-to-many-statements.ts +27 -0
  14. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/build-select-option-types.ts +37 -0
  15. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-bulk-sort-order-content.ts +93 -0
  16. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-create-content.ts +157 -0
  17. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-create-select-option-content.ts +134 -0
  18. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-delete-bulk-content.ts +85 -0
  19. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-delete-content.ts +66 -0
  20. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-distinct-files.ts +45 -0
  21. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-by-id-content.ts +55 -0
  22. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-by-slug-content.ts +55 -0
  23. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-plural-content.ts +106 -0
  24. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-select-options-content.ts +55 -0
  25. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-versions-content.ts +19 -0
  26. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-m2m-files.ts +151 -0
  27. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-restore-content.ts +123 -0
  28. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-update-content.ts +187 -0
  29. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-resolve-media-function.ts +40 -0
  30. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-slug-helpers.ts +73 -0
  31. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-version-snapshot-helpers.ts +104 -0
  32. package/dist/assets/adapters/next/templates/renderers/generators/actions/lifecycle-hook-emissions/lifecycle-context.ts +22 -0
  33. package/dist/assets/adapters/next/templates/renderers/generators/actions/lifecycle-hook-emissions/lifecycle-hook-import.ts +4 -0
  34. package/dist/assets/adapters/next/templates/renderers/generators/actions/markdown-renderer.ts +411 -0
  35. package/dist/assets/adapters/next/templates/renderers/generators/actions/select-fields-resolver.ts +99 -0
  36. package/dist/assets/adapters/next/templates/renderers/generators/actions/single-actions/generate-single-actions.ts +292 -0
  37. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-authorship-value.ts +8 -0
  38. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-column-def.ts +297 -0
  39. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-first-column-def.ts +483 -0
  40. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-image-cell-media.ts +38 -0
  41. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-image-element.ts +22 -0
  42. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-relationship-label.ts +26 -0
  43. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-select-label.ts +17 -0
  44. package/dist/assets/adapters/next/templates/renderers/generators/columns/custom-cell.ts +24 -0
  45. package/dist/assets/adapters/next/templates/renderers/generators/columns/generate-columns.ts +55 -0
  46. package/dist/assets/adapters/next/templates/renderers/generators/create-page.ts +16 -0
  47. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-database.ts +5 -0
  48. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-junction-table.ts +27 -0
  49. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-select-options-table.ts +35 -0
  50. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-table-definition.ts +25 -0
  51. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/build-entity-dev-mode-snippets.ts +180 -0
  52. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/build-form-dev-mode-snippets.ts +97 -0
  53. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/build-single-dev-mode-snippets.ts +60 -0
  54. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/create-dev-mode-integration-artifact.ts +89 -0
  55. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/lifecycle-hook-code.ts +55 -0
  56. package/dist/assets/adapters/next/templates/renderers/generators/edit-page.ts +33 -0
  57. package/dist/assets/adapters/next/templates/renderers/generators/email-template/generate-email-template.ts +248 -0
  58. package/dist/assets/adapters/next/templates/renderers/generators/email-template/generate-field-value.ts +31 -0
  59. package/dist/assets/adapters/next/templates/renderers/generators/emitted-helpers.ts +16 -0
  60. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/generate-icon-postfix.ts +27 -0
  61. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-boolean-field.ts +47 -0
  62. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-creatable-select-field.ts +122 -0
  63. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-date-field.ts +47 -0
  64. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-default-field.ts +53 -0
  65. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-gallery-field.ts +46 -0
  66. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-group-field.ts +16 -0
  67. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-icon-field.ts +31 -0
  68. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-markdown-field.ts +50 -0
  69. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-media-field.ts +47 -0
  70. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-multi-relationship-field.ts +91 -0
  71. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-multi-select-field.ts +219 -0
  72. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-number-field.ts +48 -0
  73. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-richtext-field.ts +50 -0
  74. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-select-field.ts +61 -0
  75. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-separator-field.ts +16 -0
  76. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-single-relationship-field.ts +93 -0
  77. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-textarea-field.ts +53 -0
  78. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-list-field.ts +163 -0
  79. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-nested-field.ts +164 -0
  80. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-nested-object-list-field.ts +59 -0
  81. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-text-input-field.ts +27 -0
  82. package/dist/assets/adapters/next/templates/renderers/generators/form/form-entity/generate-form.ts +822 -0
  83. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/build-default-value-from-sync-functions.ts +41 -0
  84. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/build-ui-imports.ts +58 -0
  85. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/generate-default-value.ts +67 -0
  86. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/generate-nested-list-default-value.ts +13 -0
  87. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/label-with-description.ts +14 -0
  88. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/render-tabs-trigger.ts +18 -0
  89. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/select-read-values-expression.ts +21 -0
  90. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-creatable-select-handlers.ts +67 -0
  91. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-creatable-select-state.ts +29 -0
  92. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-field-array-hooks.ts +13 -0
  93. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-fields-jsx.ts +30 -0
  94. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/generate-card-component.ts +129 -0
  95. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/generate-single-form.ts +66 -0
  96. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-columns/generate-column-def.ts +72 -0
  97. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-columns/generate-columns.ts +89 -0
  98. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-page/generate-page.ts +23 -0
  99. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-page-content.ts +246 -0
  100. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-submission-drawer.ts +216 -0
  101. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-table.ts +273 -0
  102. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-actions/exclusive-date-upper-bound-helper.ts +11 -0
  103. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-actions/generate-form-actions.ts +505 -0
  104. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-multistep/build-component-source.ts +197 -0
  105. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/build-field-error-helper.ts +16 -0
  106. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/error-message-line.ts +13 -0
  107. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-field-jsx.ts +226 -0
  108. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-file-upload-field-jsx.ts +41 -0
  109. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-list-field-jsx.ts +160 -0
  110. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-multiselect-field-jsx.ts +40 -0
  111. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-number-field-jsx.ts +41 -0
  112. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-text-field-jsx.ts +39 -0
  113. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/label-with-description-line.ts +14 -0
  114. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-single/build-single-step-form-component-source.ts +100 -0
  115. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-database.ts +29 -0
  116. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-hook.ts +142 -0
  117. package/dist/assets/adapters/next/templates/renderers/generators/hook/generate-hook.ts +169 -0
  118. package/dist/assets/adapters/next/templates/renderers/generators/hook/generate-single-hook.ts +30 -0
  119. package/dist/assets/adapters/next/templates/renderers/generators/navigation-extract.ts +19 -0
  120. package/dist/assets/adapters/next/templates/renderers/generators/page-content/generate-page-content.ts +419 -0
  121. package/dist/assets/adapters/next/templates/renderers/generators/page.ts +24 -0
  122. package/dist/assets/adapters/next/templates/renderers/generators/row-actions-emitters/build-delete-dialog-source.ts +108 -0
  123. package/dist/assets/adapters/next/templates/renderers/generators/row-actions-emitters/build-row-actions-source.ts +61 -0
  124. package/dist/assets/adapters/next/templates/renderers/generators/single-page.ts +59 -0
  125. package/dist/assets/adapters/next/templates/renderers/generators/sortable-header/build-sort-label-expr.ts +9 -0
  126. package/dist/assets/adapters/next/templates/renderers/generators/sortable-header/build-sortable-header-button-jsx.ts +20 -0
  127. package/dist/assets/adapters/next/templates/renderers/generators/sortable-header/build-sortable-header-def.ts +14 -0
  128. package/dist/assets/adapters/next/templates/renderers/generators/table.ts +284 -0
  129. package/dist/assets/adapters/next/templates/renderers/generators/thankyou-email-template.ts +110 -0
  130. package/dist/assets/adapters/next/templates/renderers/generators/webhook-events/render-extract.ts +14 -0
  131. package/dist/assets/adapters/next/templates/renderers/init/scaffolders/next-config/create-next-config-template.ts +48 -0
  132. package/dist/assets/adapters/next/templates/renderers/init/scaffolders/tailwind/admin-shadow-input-utility.ts +9 -0
  133. package/dist/assets/adapters/next/templates/renderers/init/scaffolders/tailwind/admin-theme-block.ts +42 -0
  134. package/dist/assets/adapters/next/templates/renderers/init/templates/app/admin.ts +12 -0
  135. package/dist/assets/adapters/next/templates/renderers/integration-runtime/render-core-email-provider.ts +27 -0
  136. package/dist/assets/adapters/next/templates/renderers/integration-runtime/render-core-storage-provider.ts +27 -0
  137. package/dist/assets/adapters/next/templates/renderers/snapshots/barrels/render-db-barrel.ts +8 -0
  138. package/dist/assets/adapters/next/templates/renderers/snapshots/barrels/render-navigation-barrel.ts +63 -0
  139. package/dist/assets/adapters/next/templates/renderers/snapshots/barrels/render-webhook-events-barrel.ts +16 -0
  140. package/dist/{chunk-TIJEHWRF.js → chunk-OYU73Q2W.js} +1 -50
  141. package/dist/chunk-OYU73Q2W.js.map +1 -0
  142. package/dist/cli.js +8903 -4025
  143. package/dist/cli.js.map +1 -1
  144. package/dist/{read-namespaced-template-UXU7OCY3.js → read-namespaced-template-EIH2NPDJ.js} +2 -2
  145. package/package.json +1 -1
  146. package/dist/chunk-TIJEHWRF.js.map +0 -1
  147. /package/dist/{read-namespaced-template-UXU7OCY3.js.map → read-namespaced-template-EIH2NPDJ.js.map} +0 -0
@@ -0,0 +1,14 @@
1
+ export function renderBuildSortableHeaderDefTemplate({
2
+ sortLabelExpr,
3
+ sortableHeaderButtonJsx
4
+ }: {
5
+ sortLabelExpr: string
6
+ sortableHeaderButtonJsx: string
7
+ }): string {
8
+ return `header: ({ column }) => {
9
+ ${sortLabelExpr}
10
+ return (
11
+ ${sortableHeaderButtonJsx}
12
+ )
13
+ }`
14
+ }
@@ -0,0 +1,284 @@
1
+ export function renderTableClientModuleTemplate({
2
+ hasEditRouterImport,
3
+ plural,
4
+ schemaName,
5
+ singular,
6
+ actionImportPath,
7
+ filterProps,
8
+ filterParams,
9
+ hasEditRouterSetup,
10
+ camelPlural,
11
+ schemaLabel,
12
+ hasEditEnabled,
13
+ hasEditRowClickHandler
14
+ }: {
15
+ hasEditRouterImport: string
16
+ plural: string
17
+ schemaName: string
18
+ singular: string
19
+ actionImportPath: string
20
+ filterProps: string
21
+ filterParams: string
22
+ hasEditRouterSetup: string
23
+ camelPlural: string
24
+ schemaLabel: string
25
+ hasEditEnabled: string
26
+ hasEditRowClickHandler: string
27
+ }): string {
28
+ return `'use client'
29
+
30
+ import {
31
+ DataTablePagination,
32
+ } from '@admin/components/shared/data-table/data-table-pagination'
33
+ import {
34
+ DataGrid,
35
+ DataGridBody,
36
+ DataGridCell,
37
+ DataGridHead,
38
+ DataGridHeader,
39
+ DataGridRow
40
+ } from '@admin/components/shared/data-table/data-grid'
41
+ import {
42
+ type ColumnDef,
43
+ flexRender,
44
+ getCoreRowModel,
45
+ useReactTable
46
+ } from '@tanstack/react-table'
47
+ import { GripVertical } from 'lucide-react'
48
+ import { parseAsInteger, parseAsString, useQueryStates } from 'nuqs'
49
+ ${hasEditRouterImport}import { use${plural} } from '@admin/hooks/use-${schemaName}'
50
+ import type { ${singular} } from '@admin/actions/${actionImportPath}'
51
+ import { useTableUtils } from '@admin/hooks/use-table-utils'
52
+ import { cn } from '@admin/utils/shared/cn'
53
+
54
+ interface ${plural}TableProps<TValue> extends React.HTMLAttributes<HTMLDivElement> {
55
+ columns: ColumnDef<${singular}, TValue>[]
56
+ selectedIds: string[]
57
+ setSelectedIds: (ids: string[]) => void
58
+ search?: string
59
+ ${filterProps}
60
+ }
61
+
62
+ export function ${plural}Table<TValue>({ columns, selectedIds, setSelectedIds, search, ${filterParams}, className }: ${plural}TableProps<TValue>) {
63
+ const defaultPageSize = 20
64
+ ${hasEditRouterSetup} const [{
65
+ page: pageIndex,
66
+ size: pageSize,
67
+ sort: sortField,
68
+ dir: sortDir
69
+ }, setTableQuery] = useQueryStates({
70
+ page: parseAsInteger.withDefault(0),
71
+ size: parseAsInteger.withDefault(defaultPageSize),
72
+ sort: parseAsString.withDefault(''),
73
+ dir: parseAsString.withDefault('')
74
+ })
75
+
76
+ const safePageIndex = Number.isFinite(pageIndex) && pageIndex > 0 ? pageIndex : 0
77
+ const safePageSize = pageSize === -1 || (Number.isFinite(pageSize) && pageSize > 0) ? pageSize : defaultPageSize
78
+ const { data, error, isPending } = use${plural}(search, ${filterParams}, safePageIndex, safePageSize, sortField || undefined, (sortDir as 'asc' | 'desc') || undefined)
79
+
80
+ const tableData = data?.${camelPlural} ?? []
81
+ const totalRows = data?.total ?? 0
82
+ const effectivePageSize = safePageSize === -1 ? totalRows : safePageSize
83
+ const pageCount = effectivePageSize > 0 ? Math.ceil(totalRows / effectivePageSize) : 1
84
+ const shouldShowPagination = totalRows > defaultPageSize
85
+
86
+ const {
87
+ columnSizing,
88
+ handleColumnSizingChange,
89
+ handlePaginationChange,
90
+ handleRowSelectionChange,
91
+ handleSortingChange,
92
+ hoveredColumnId,
93
+ registerTable,
94
+ resetColumnSizingToContainer,
95
+ rowSelection,
96
+ setHoveredColumnId,
97
+ sorting,
98
+ tableContainerRef
99
+ } = useTableUtils<${singular}>({
100
+ data: tableData,
101
+ selectedIds,
102
+ onSelectedIdsChange: setSelectedIds,
103
+ pageIndex: safePageIndex,
104
+ pageSize: effectivePageSize,
105
+ setPageIndex: (nextPageIndex) => setTableQuery({ page: nextPageIndex }),
106
+ setSortingParams: ({
107
+ pageIndex: nextPageIndex,
108
+ sortDir: nextSortDir,
109
+ sortField: nextSortField
110
+ }) => setTableQuery({
111
+ page: nextPageIndex,
112
+ sort: nextSortField,
113
+ dir: nextSortDir
114
+ }),
115
+ sortField,
116
+ sortDir
117
+ })
118
+
119
+ const table = useReactTable({
120
+ data: tableData,
121
+ columns,
122
+ columnResizeMode: 'onChange',
123
+ defaultColumn: {
124
+ minSize: 48,
125
+ size: 220
126
+ },
127
+ getCoreRowModel: getCoreRowModel(),
128
+ manualPagination: true,
129
+ manualSorting: true,
130
+ pageCount,
131
+ rowCount: totalRows,
132
+ onSortingChange: handleSortingChange,
133
+ onColumnSizingChange: handleColumnSizingChange,
134
+ onRowSelectionChange: handleRowSelectionChange,
135
+ onPaginationChange: handlePaginationChange,
136
+ state: {
137
+ sorting,
138
+ columnSizing,
139
+ rowSelection,
140
+ pagination: {
141
+ pageIndex: safePageIndex,
142
+ pageSize: effectivePageSize
143
+ }
144
+ }
145
+ })
146
+ registerTable(table)
147
+ const gridTemplateColumns = table
148
+ .getVisibleLeafColumns()
149
+ .map((column) => \`\${column.getSize()}px\`)
150
+ .join(' ')
151
+
152
+ return (
153
+ <div
154
+ className={cn("flex flex-col gap-6 pt-px pb-2 h-full", className)}
155
+ >
156
+ <DataGrid containerClassName="min-h-0 flex-1" containerRef={tableContainerRef} gridTemplateColumns={gridTemplateColumns} style={{ width: table.getTotalSize() }}>
157
+ <DataGridHeader>
158
+ {table.getHeaderGroups().map((headerGroup) => (
159
+ <DataGridRow key={headerGroup.id}>
160
+ {headerGroup.headers.map((header, headerIndex) => {
161
+ const meta = header.column.columnDef.meta as Record<string, unknown> | undefined
162
+ const resizeLabel = typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.column.id
163
+ const nextHeader = headerGroup.headers[headerIndex + 1]
164
+ const canResizeColumn = header.column.getCanResize() && nextHeader?.column.getCanResize() === true
165
+ return (
166
+ <DataGridHead
167
+ key={header.id}
168
+ className={cn('group/resize-header relative overflow-hidden', {
169
+ 'text-center': meta?.align === 'center',
170
+ 'text-right': meta?.align === 'right'
171
+ })}
172
+ data-column-id={header.column.id}
173
+ onMouseEnter={() => setHoveredColumnId(header.column.id)}
174
+ onMouseLeave={() => setHoveredColumnId((current) => (current === header.column.id ? null : current))}
175
+ >
176
+ {header.isPlaceholder
177
+ ? null
178
+ : flexRender(header.column.columnDef.header, header.getContext())}
179
+ {canResizeColumn ? (
180
+ <button
181
+ type="button"
182
+ aria-label={\`Resize \${resizeLabel} column\`}
183
+ className="group/resize-handle absolute right-0 top-0 z-10 flex h-full w-5 cursor-col-resize touch-none select-none items-center justify-center text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:text-foreground focus-visible:opacity-100 focus-visible:outline-none group-focus-within/resize-header:opacity-100 data-[column-hovered=true]:opacity-100 data-[resizing=true]:opacity-100"
184
+ data-resize-handle
185
+ data-column-hovered={hoveredColumnId === header.column.id ? 'true' : 'false'}
186
+ data-resizing={header.column.getIsResizing() ? 'true' : 'false'}
187
+ onDoubleClick={resetColumnSizingToContainer}
188
+ onMouseDown={header.getResizeHandler()}
189
+ onTouchStart={header.getResizeHandler()}
190
+ >
191
+ <GripVertical aria-hidden="true" className={cn('size-3.5', { 'text-ring': header.column.getIsResizing() })} />
192
+ </button>
193
+ ) : null}
194
+ </DataGridHead>
195
+ )
196
+ })}
197
+ </DataGridRow>
198
+ ))}
199
+ </DataGridHeader>
200
+ <DataGridBody>
201
+ {isPending ? (
202
+ <DataGridRow>
203
+ <DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
204
+ <div className="text-muted-foreground">Loading ${schemaLabel}…</div>
205
+ </DataGridCell>
206
+ </DataGridRow>
207
+ ) : error ? (
208
+ <DataGridRow>
209
+ <DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
210
+ <div className="text-destructive">Error loading ${schemaLabel}: {error.message}</div>
211
+ </DataGridCell>
212
+ </DataGridRow>
213
+ ) : table.getRowModel().rows?.length ? (
214
+ table.getRowModel().rows.map((row) => (
215
+ <DataGridRow
216
+ key={row.id}
217
+ className={cn('hover:bg-muted/50', {
218
+ 'cursor-pointer': ${hasEditEnabled}
219
+ })}
220
+ data-state={row.getIsSelected() ? 'selected' : undefined}${hasEditRowClickHandler}
221
+ >
222
+ {row.getVisibleCells().map((cell) => {
223
+ const meta = cell.column.columnDef.meta as Record<string, unknown> | undefined
224
+ return (
225
+ <DataGridCell
226
+ key={cell.id}
227
+ className={cn({
228
+ 'text-center': meta?.align === 'center',
229
+ 'text-right': meta?.align === 'right'
230
+ })}
231
+ data-column-id={cell.column.id}
232
+ onMouseEnter={() => setHoveredColumnId(cell.column.id)}
233
+ onMouseLeave={() => setHoveredColumnId((current) => (current === cell.column.id ? null : current))}
234
+ >
235
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
236
+ </DataGridCell>
237
+ )
238
+ })}
239
+ </DataGridRow>
240
+ ))
241
+ ) : (
242
+ <DataGridRow>
243
+ <DataGridCell className="flex h-24 items-center justify-center text-center" style={{ gridColumn: '1 / -1' }}>
244
+ No ${schemaLabel} found.
245
+ </DataGridCell>
246
+ </DataGridRow>
247
+ )}
248
+ </DataGridBody>
249
+ </DataGrid>
250
+
251
+ {shouldShowPagination ? (
252
+ <DataTablePagination
253
+ table={table}
254
+ paginationMode="controlled"
255
+ pageSize={safePageSize}
256
+ pageIndex={safePageIndex}
257
+ pageCount={pageCount}
258
+ setPageIndex={(nextPageIndex) => setTableQuery({ page: nextPageIndex })}
259
+ setPageSize={(nextPageSize) =>
260
+ setTableQuery({ page: 0, size: nextPageSize })
261
+ }
262
+ />
263
+ ) : null}
264
+ </div>
265
+ )
266
+ }
267
+ `
268
+ }
269
+
270
+ export function renderTableEditRowClickHandlerTemplate({
271
+ adminRoutePath,
272
+ schemaName
273
+ }: {
274
+ adminRoutePath: string
275
+ schemaName: string
276
+ }): string {
277
+ return `
278
+ onClick={(e) => {
279
+ const target = e.target as HTMLElement
280
+ if (!e.currentTarget.contains(target)) return
281
+ if (target.closest('button, a, input, [role="checkbox"]')) return
282
+ router.push(\`${adminRoutePath}/${schemaName}/\${row.original.id}/edit\`)
283
+ }}`
284
+ }
@@ -0,0 +1,110 @@
1
+ export function renderThankYouEmailTemplateGeneratedFunctionTemplate({
2
+ pascal,
3
+ toLowerCase
4
+ }: {
5
+ pascal: string
6
+ toLowerCase: string
7
+ }): string {
8
+ return `import { Body, Container, Head, Heading, Html, Preview, Section, Text } from '@react-email/components'
9
+
10
+ export function ${pascal}ThankYouEmail() {
11
+ return (
12
+ <Html>
13
+ <Head />
14
+ <Preview>Thank you for your ${toLowerCase} submission</Preview>
15
+ <Body style={main}>
16
+ <Container style={container}>
17
+ <Section style={header}>
18
+ <Text style={logoText}>BetterStart</Text>
19
+ </Section>
20
+
21
+ <Section style={body}>
22
+ <Heading style={h1}>Thank you!</Heading>
23
+ <Text style={paragraph}>
24
+ We received your ${toLowerCase} submission and will get back to you shortly.
25
+ </Text>
26
+ <Text style={paragraph}>
27
+ If you have any questions in the meantime, feel free to reply to this email.
28
+ </Text>
29
+ </Section>
30
+
31
+ <Section style={footer}>
32
+ <Text style={footerBrand}>BetterStart</Text>
33
+ </Section>
34
+ </Container>
35
+ </Body>
36
+ </Html>
37
+ )
38
+ }
39
+
40
+ const colors = {
41
+ primary: '#7c3aed',
42
+ background: '#f8fafc',
43
+ cardBg: '#ffffff',
44
+ text: '#1e293b',
45
+ textMuted: '#64748b',
46
+ border: '#e2e8f0',
47
+ }
48
+
49
+ const main = {
50
+ backgroundColor: colors.background,
51
+ fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
52
+ padding: '40px 20px',
53
+ }
54
+
55
+ const container = {
56
+ margin: '0 auto',
57
+ maxWidth: '600px',
58
+ }
59
+
60
+ const header = {
61
+ backgroundColor: colors.primary,
62
+ borderRadius: '12px 12px 0 0',
63
+ padding: '24px 32px',
64
+ textAlign: 'center' as const,
65
+ }
66
+
67
+ const logoText = {
68
+ color: '#ffffff',
69
+ fontSize: '24px',
70
+ fontWeight: '700' as const,
71
+ letterSpacing: '-0.02em',
72
+ margin: '0',
73
+ }
74
+
75
+ const body = {
76
+ backgroundColor: colors.cardBg,
77
+ padding: '40px 32px',
78
+ }
79
+
80
+ const h1 = {
81
+ color: colors.text,
82
+ fontSize: '24px',
83
+ fontWeight: '700' as const,
84
+ lineHeight: '32px',
85
+ margin: '0 0 16px',
86
+ }
87
+
88
+ const paragraph = {
89
+ color: colors.text,
90
+ fontSize: '16px',
91
+ lineHeight: '26px',
92
+ margin: '0 0 16px',
93
+ }
94
+
95
+ const footer = {
96
+ backgroundColor: colors.cardBg,
97
+ borderRadius: '0 0 12px 12px',
98
+ borderTop: \`1px solid \${colors.border}\`,
99
+ padding: '24px 32px',
100
+ textAlign: 'center' as const,
101
+ }
102
+
103
+ const footerBrand = {
104
+ color: colors.textMuted,
105
+ fontSize: '14px',
106
+ fontWeight: '600' as const,
107
+ margin: '0',
108
+ }
109
+ `
110
+ }
@@ -0,0 +1,14 @@
1
+ export function renderExtractImportsTemplate({
2
+ toCamelCase,
3
+ join
4
+ }: {
5
+ toCamelCase: string
6
+ join: string
7
+ }): string {
8
+ return `import type { WebhookEventSource } from '@admin/types/webhooks'
9
+
10
+ export const ${toCamelCase}WebhookEvents: WebhookEventSource = {
11
+ ${join}
12
+ }
13
+ `
14
+ }
@@ -0,0 +1,48 @@
1
+ export function renderCreateNextConfigTemplateImportsTemplate({
2
+ betterstartAssetHost
3
+ }: {
4
+ betterstartAssetHost: string
5
+ }): string {
6
+ return `import type { NextConfig } from 'next'
7
+
8
+ const nextConfig: NextConfig = {
9
+ cacheComponents: true,
10
+ devIndicators: false,
11
+ images: {
12
+ remotePatterns: [
13
+ {
14
+ protocol: 'https',
15
+ hostname: '${betterstartAssetHost}',
16
+ },
17
+ ],
18
+ },
19
+ }
20
+
21
+ export default nextConfig
22
+ `
23
+ }
24
+
25
+ export function renderCreateNextConfigTemplateImportsDetailsTemplate({
26
+ betterstartAssetHost
27
+ }: {
28
+ betterstartAssetHost: string
29
+ }): string {
30
+ return `import type { NextConfig } from 'next'
31
+
32
+ const nextConfig: NextConfig = {
33
+ experimental: {
34
+ useCache: true,
35
+ },
36
+ images: {
37
+ remotePatterns: [
38
+ {
39
+ protocol: 'https',
40
+ hostname: '${betterstartAssetHost}',
41
+ },
42
+ ],
43
+ },
44
+ }
45
+
46
+ export default nextConfig
47
+ `
48
+ }
@@ -0,0 +1,9 @@
1
+ export function renderAdminShadowInputUtility(): string {
2
+ return `
3
+ @utility shadow-input {
4
+ --admin-shadow-input: rgba(0, 0, 0, 0.02) 0px 4px 8px -2px;
5
+ --tw-shadow: var(--admin-shadow-input);
6
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow),
7
+ var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
8
+ }`
9
+ }
@@ -0,0 +1,42 @@
1
+ export function renderAdminThemeBlock(): string {
2
+ return `
3
+ @theme inline {
4
+ --color-background: var(--background);
5
+ --color-foreground: var(--foreground);
6
+ --color-card: var(--card);
7
+ --color-card-foreground: var(--card-foreground);
8
+ --color-popover: var(--popover);
9
+ --color-popover-foreground: var(--popover-foreground);
10
+ --color-primary: var(--primary);
11
+ --color-primary-foreground: var(--primary-foreground);
12
+ --color-secondary: var(--secondary);
13
+ --color-secondary-foreground: var(--secondary-foreground);
14
+ --color-muted: var(--muted);
15
+ --color-muted-foreground: var(--muted-foreground);
16
+ --color-accent: var(--accent);
17
+ --color-accent-foreground: var(--accent-foreground);
18
+ --color-destructive: var(--destructive);
19
+ --color-destructive-foreground: var(--destructive-foreground);
20
+ --color-border: var(--border);
21
+ --color-input: var(--input);
22
+ --color-input-border: var(--input-border);
23
+ --color-ring: var(--ring);
24
+ --color-chart-1: var(--chart-1);
25
+ --color-chart-2: var(--chart-2);
26
+ --color-chart-3: var(--chart-3);
27
+ --color-chart-4: var(--chart-4);
28
+ --color-chart-5: var(--chart-5);
29
+ --color-sidebar: var(--sidebar);
30
+ --color-sidebar-foreground: var(--sidebar-foreground);
31
+ --color-sidebar-primary: var(--sidebar-primary);
32
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
33
+ --color-sidebar-accent: var(--sidebar-accent);
34
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
35
+ --color-sidebar-border: var(--sidebar-border);
36
+ --color-sidebar-ring: var(--sidebar-ring);
37
+ --radius-sm: calc(var(--radius) - 4px);
38
+ --radius-md: calc(var(--radius) - 2px);
39
+ --radius-lg: var(--radius);
40
+ --radius-xl: calc(var(--radius) + 4px);
41
+ }`
42
+ }
@@ -0,0 +1,12 @@
1
+ export function renderAdminDataTemplateGeneratedValueTemplate({
2
+ namespaceCamel,
3
+ projectName
4
+ }: {
5
+ namespaceCamel: string
6
+ projectName: string
7
+ }): string {
8
+ return `export const ${namespaceCamel} = {
9
+ name: '${projectName}',
10
+ }
11
+ `
12
+ }
@@ -0,0 +1,27 @@
1
+ export function renderCoreEmailProviderContentTemplate({
2
+ activeProviderExportName
3
+ }: {
4
+ activeProviderExportName: string
5
+ }): string {
6
+ return ` if (${activeProviderExportName}.isConfigured()) {
7
+ return ${activeProviderExportName}
8
+ }
9
+
10
+ `
11
+ }
12
+
13
+ export function renderCoreEmailProviderGeneratedFunctionTemplate({
14
+ providerImport,
15
+ providerBranch
16
+ }: {
17
+ providerImport: string
18
+ providerBranch: string
19
+ }): string {
20
+ return `import { noneEmailProvider } from '@admin/actions/email/none'
21
+ ${providerImport}import type { AdminEmailProvider } from '@admin/actions/email/types'
22
+
23
+ export function getEmailProvider(): AdminEmailProvider {
24
+ ${providerBranch} return noneEmailProvider
25
+ }
26
+ `
27
+ }
@@ -0,0 +1,27 @@
1
+ export function renderCoreStorageProviderContentTemplate({
2
+ activeProviderExportName
3
+ }: {
4
+ activeProviderExportName: string
5
+ }): string {
6
+ return ` if (${activeProviderExportName}.isConfigured()) {
7
+ return ${activeProviderExportName}
8
+ }
9
+
10
+ `
11
+ }
12
+
13
+ export function renderCoreStorageProviderGeneratedFunctionTemplate({
14
+ providerImport,
15
+ providerBranch
16
+ }: {
17
+ providerImport: string
18
+ providerBranch: string
19
+ }): string {
20
+ return `import { localStorageProvider } from '@admin/actions/storage/local'
21
+ ${providerImport}import type { AdminStorageProvider } from '@admin/actions/storage/types'
22
+
23
+ export function getStorageProvider(): AdminStorageProvider {
24
+ ${providerBranch} return localStorageProvider
25
+ }
26
+ `
27
+ }
@@ -0,0 +1,8 @@
1
+ export function renderDbBarrelContentTemplate({
2
+ exportLinesContent
3
+ }: {
4
+ exportLinesContent: string
5
+ }): string {
6
+ return `export * from './core/schema'
7
+ ${exportLinesContent}`
8
+ }
@@ -0,0 +1,63 @@
1
+ export function renderNavigationBarrelImportsTemplate({
2
+ namespacePascal,
3
+ namespaceAlias,
4
+ extractImports,
5
+ namespaceRoutePath,
6
+ spreadLinesContent,
7
+ namespaceCamel
8
+ }: {
9
+ namespacePascal: string
10
+ namespaceAlias: string
11
+ extractImports: string
12
+ namespaceRoutePath: string
13
+ spreadLinesContent: string
14
+ namespaceCamel: string
15
+ }): string {
16
+ return `import { House, ImagePlay } from 'lucide-react'
17
+ import type { ${namespacePascal}NavigationItem } from '${namespaceAlias}/types/navigation'${extractImports}
18
+
19
+ export type { ${namespacePascal}NavigationItem } from '${namespaceAlias}/types/navigation'
20
+
21
+ const coreNav: ${namespacePascal}NavigationItem[] = [
22
+ {
23
+ label: 'Overview',
24
+ href: '${namespaceRoutePath}',
25
+ icon: House,
26
+ group: 'General',
27
+ position: 0,
28
+ },
29
+ {
30
+ label: 'Media',
31
+ href: '${namespaceRoutePath}/media',
32
+ icon: ImagePlay,
33
+ group: 'General',
34
+ position: 1,
35
+ },
36
+ ]
37
+
38
+ function comparePositions(a?: number, b?: number): number {
39
+ if (a != null && b != null) return a - b
40
+ if (a != null) return -1
41
+ if (b != null) return 1
42
+ return 0
43
+ }
44
+
45
+ const combinedNavigation = [
46
+ ...coreNav${spreadLinesContent}
47
+ ]
48
+
49
+ const dashboard = combinedNavigation.find((item) => item.href === '${namespaceRoutePath}')
50
+ const others = combinedNavigation.filter((item) => item.href !== '${namespaceRoutePath}')
51
+
52
+ others.sort((a, b) => {
53
+ if (!a.group && b.group) return -1
54
+ if (a.group && !b.group) return 1
55
+ if (a.group && b.group && a.group !== b.group) {
56
+ return comparePositions(a.groupPosition, b.groupPosition) || a.group.localeCompare(b.group)
57
+ }
58
+ return comparePositions(a.position, b.position) || a.label.localeCompare(b.label)
59
+ })
60
+
61
+ export const ${namespaceCamel}Navigation = [...(dashboard ? [dashboard] : []), ...others]
62
+ `
63
+ }
@@ -0,0 +1,16 @@
1
+ export function renderWebhookEventsBarrelImportsTemplate({
2
+ namespaceAlias,
3
+ extractImports,
4
+ entries
5
+ }: {
6
+ namespaceAlias: string
7
+ extractImports: string
8
+ entries: string
9
+ }): string {
10
+ return `import type { WebhookEventSource } from '${namespaceAlias}/types/webhooks'${extractImports}
11
+
12
+ export type { WebhookEventSource } from '${namespaceAlias}/types/webhooks'
13
+
14
+ export const webhookEventSources: WebhookEventSource[] = ${entries}
15
+ `
16
+ }