betterstart-cli 0.0.116 → 0.0.118
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/templates/init/admin-globals.css +20 -0
- package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-grid-row.tsx +33 -1
- package/dist/assets/adapters/next/templates/init/components/shared/media/media-gallery-dialog.tsx +3 -3
- package/dist/assets/adapters/next/templates/init/components/shared/media/media-preview.tsx +3 -1
- package/dist/assets/adapters/next/templates/init/hooks/use-copy-to-clipboard.ts +1 -3
- package/dist/assets/adapters/next/templates/init/hooks/use-field-error-visible.ts +25 -0
- package/dist/assets/adapters/next/templates/init/hooks/use-media.ts +1 -1
- package/dist/assets/adapters/next/templates/init/hooks/use-upload.ts +11 -5
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/cleanup-audit-logs.ts +1 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/query-audit-logs.ts +2 -2
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/record-audit-event.ts +1 -2
- package/dist/assets/adapters/next/templates/init/lib/actions/auth/client.ts +4 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/get-entity-versions.ts +5 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/forms/get-all-form-settings.ts +1 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/media/create-media.ts +2 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media-bulk.ts +1 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media.ts +1 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/media/update-media.ts +2 -4
- package/dist/assets/adapters/next/templates/init/lib/actions/profile/change-own-password.ts +1 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/profile/update-email.ts +1 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-files.ts +1 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-media-from-url.ts +16 -6
- package/dist/assets/adapters/next/templates/init/lib/actions/users/change-user-password.ts +1 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/users/create-user.ts +2 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/users/delete-user.ts +1 -0
- package/dist/assets/adapters/next/templates/init/lib/actions/users/types.ts +1 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/users/update-user-role.ts +1 -0
- package/dist/assets/adapters/next/templates/init/lib/db/core/schema.ts +12 -4
- package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/registry.ts +4 -4
- package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/runner.ts +3 -7
- package/dist/assets/adapters/next/templates/init/pages/container-layout.tsx +3 -0
- package/dist/assets/adapters/next/templates/init/pages/dashboard-page.tsx +78 -76
- package/dist/assets/adapters/next/templates/init/pages/forgot-password-form.tsx +5 -8
- package/dist/assets/adapters/next/templates/init/pages/forgot-password-page-skeleton.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/pages/login-form.tsx +7 -9
- package/dist/assets/adapters/next/templates/init/pages/login-page-skeleton.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/pages/reset-password-form.tsx +8 -16
- package/dist/assets/adapters/next/templates/init/pages/reset-password-page-skeleton.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-detail-row.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-table.tsx +1 -6
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-table.tsx +2 -7
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-table.tsx +1 -6
- package/dist/assets/adapters/next/templates/init/pages/users/users-table.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/public/placeholder.png +0 -0
- package/dist/assets/adapters/next/templates/init/types/index.ts +2 -0
- package/dist/assets/adapters/next/templates/init/utils/audit/normalize-comparable-value.ts +4 -2
- package/dist/assets/adapters/next/templates/init/utils/date/format-action-date.ts +12 -0
- package/dist/assets/adapters/next/templates/init/utils/dev-mode/dev-mode-json-schemas.ts +66 -0
- package/dist/assets/adapters/next/templates/init/utils/dev-mode/parse-dev-mode-lifecycle-hooks.ts +11 -0
- package/dist/assets/adapters/next/templates/init/utils/dev-mode/parse-dev-mode-snippets.ts +9 -0
- package/dist/assets/adapters/next/templates/init/utils/editor/set-task-item-checked.ts +13 -0
- package/dist/assets/adapters/next/templates/init/utils/editor/update-nodes-attr.ts +2 -1
- package/dist/assets/adapters/next/templates/init/utils/email/email-theme.ts +13 -0
- package/dist/assets/adapters/next/templates/init/utils/email/render-form-submission-rows.ts +3 -2
- package/dist/assets/adapters/next/templates/init/utils/email/render-notification-email.ts +7 -6
- package/dist/assets/adapters/next/templates/init/utils/email/render-thank-you-email.ts +5 -4
- package/dist/assets/adapters/next/templates/init/utils/error/read-string-property.ts +4 -2
- package/dist/assets/adapters/next/templates/init/utils/error/recognize.ts +2 -4
- package/dist/assets/adapters/next/templates/init/utils/error/to-action-error.ts +0 -1
- package/dist/assets/adapters/next/templates/init/utils/form/clone-default-value.ts +4 -2
- package/dist/assets/adapters/next/templates/init/utils/shared/is-record.ts +3 -0
- package/dist/assets/adapters/next/templates/init/utils/table/default-get-id.ts +3 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/editor-toolbar.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/slash-command-menu.tsx +5 -3
- package/dist/assets/shared-assets/react-admin/custom/content-editor/source-mode.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/removable-image-node/removable-image-node.tsx +3 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/task-item-node/task-item-node-extension.tsx +6 -15
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu.tsx +1 -6
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/list-dropdown-menu/list-dropdown-menu.tsx +1 -6
- package/dist/assets/shared-assets/react-admin/custom/date-range-picker.tsx +9 -2
- package/dist/assets/shared-assets/react-admin/custom/gallery-field.tsx +3 -3
- package/dist/assets/shared-assets/react-admin/custom/media-field.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/custom/nested-object-list-field.tsx +3 -1
- package/dist/assets/shared-assets/react-admin/custom/progressive-blur.tsx +3 -1
- package/dist/assets/shared-assets/react-admin/ui/dropdown-menu.tsx +20 -23
- package/dist/assets/shared-assets/react-admin/ui/form.tsx +6 -3
- package/dist/assets/shared-assets/react-admin/ui/navigation-menu.tsx +1 -1
- package/dist/{chunk-SG4U6EQY.js → chunk-BNHFSHPE.js} +14 -1
- package/dist/chunk-BNHFSHPE.js.map +1 -0
- package/dist/cli.js +962 -633
- package/dist/cli.js.map +1 -1
- package/dist/{read-namespaced-template-D2CD4Q7U.js → read-namespaced-template-WYIGUH7S.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-SG4U6EQY.js.map +0 -1
- /package/dist/{read-namespaced-template-D2CD4Q7U.js.map → read-namespaced-template-WYIGUH7S.js.map} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FormEmailDeliveryInput } from '@admin/utils/email/form-email-delivery-input'
|
|
2
|
+
import { emailTheme } from '@admin/utils/email/email-theme'
|
|
2
3
|
import { escapeHtml } from '@admin/utils/email/escape-html'
|
|
3
4
|
import { renderFormSubmissionRows } from '@admin/utils/email/render-form-submission-rows'
|
|
4
5
|
|
|
@@ -10,15 +11,15 @@ export function renderNotificationEmail(input: FormEmailDeliveryInput): string {
|
|
|
10
11
|
|
|
11
12
|
return `<!doctype html>
|
|
12
13
|
<html>
|
|
13
|
-
<body style="margin:0;background
|
|
14
|
-
<div style="margin:0 auto;max-width
|
|
15
|
-
<div style="border-radius:12px;background
|
|
16
|
-
<div style="background
|
|
17
|
-
<p style="margin:0;color
|
|
14
|
+
<body style="margin:0;background:${emailTheme.pageBackground};font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;color:${emailTheme.text};">
|
|
15
|
+
<div style="margin:0 auto;max-width:${emailTheme.contentWidth};padding:40px 20px;">
|
|
16
|
+
<div style="border-radius:12px;background:${emailTheme.surface};border:1px solid ${emailTheme.border};overflow:hidden;">
|
|
17
|
+
<div style="background:${emailTheme.headerBackground};color:${emailTheme.inverseText};padding:24px 28px;">
|
|
18
|
+
<p style="margin:0;color:${emailTheme.mutedInverseText};font-size:13px;line-height:20px;">${formName}</p>
|
|
18
19
|
<h1 style="margin:4px 0 0;font-size:24px;line-height:32px;">New ${formLabel} submission</h1>
|
|
19
20
|
</div>
|
|
20
21
|
<div style="padding:24px 28px;">
|
|
21
|
-
<p style="margin:0 0 20px;color
|
|
22
|
+
<p style="margin:0 0 20px;color:${emailTheme.mutedText};font-size:14px;line-height:20px;">Submitted at ${submittedAt}</p>
|
|
22
23
|
<table cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;width:100%;">
|
|
23
24
|
<tbody>
|
|
24
25
|
${rows}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FormEmailDeliveryInput } from '@admin/utils/email/form-email-delivery-input'
|
|
2
|
+
import { emailTheme } from '@admin/utils/email/email-theme'
|
|
2
3
|
import { escapeHtml } from '@admin/utils/email/escape-html'
|
|
3
4
|
|
|
4
5
|
export function renderThankYouEmail(input: FormEmailDeliveryInput): string {
|
|
@@ -6,11 +7,11 @@ export function renderThankYouEmail(input: FormEmailDeliveryInput): string {
|
|
|
6
7
|
|
|
7
8
|
return `<!doctype html>
|
|
8
9
|
<html>
|
|
9
|
-
<body style="margin:0;background
|
|
10
|
-
<div style="margin:0 auto;max-width
|
|
11
|
-
<div style="border-radius:12px;background
|
|
10
|
+
<body style="margin:0;background:${emailTheme.pageBackground};font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;color:${emailTheme.text};">
|
|
11
|
+
<div style="margin:0 auto;max-width:${emailTheme.compactWidth};padding:40px 20px;">
|
|
12
|
+
<div style="border-radius:12px;background:${emailTheme.surface};padding:32px;border:1px solid ${emailTheme.border};">
|
|
12
13
|
<h1 style="margin:0 0 16px;font-size:24px;line-height:32px;">Thank you</h1>
|
|
13
|
-
<p style="margin:0;color
|
|
14
|
+
<p style="margin:0;color:${emailTheme.bodyText};font-size:16px;line-height:24px;">We received your ${formLabel} submission and will get back to you shortly.</p>
|
|
14
15
|
</div>
|
|
15
16
|
</div>
|
|
16
17
|
</body>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { isRecord } from '@admin/utils/shared/is-record'
|
|
2
|
+
|
|
1
3
|
export function readStringProperty(value: unknown, key: string): string | undefined {
|
|
2
|
-
if (
|
|
3
|
-
const property =
|
|
4
|
+
if (!isRecord(value)) return undefined
|
|
5
|
+
const property = value[key]
|
|
4
6
|
return typeof property === 'string' ? property : undefined
|
|
5
7
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readStringProperty } from '@admin/utils/error/read-string-property'
|
|
2
|
+
import { isRecord } from '@admin/utils/shared/is-record'
|
|
2
3
|
|
|
3
4
|
const POSTGRES_MESSAGES: Record<string, string> = {
|
|
4
5
|
'23502': 'A required value is missing.',
|
|
@@ -13,10 +14,7 @@ const AUTH_MESSAGES: Record<string, string> = {
|
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export function recognize(error: unknown): string | undefined {
|
|
16
|
-
const authCode = readStringProperty(
|
|
17
|
-
(error as { body?: unknown } | null)?.body ?? undefined,
|
|
18
|
-
'code'
|
|
19
|
-
)
|
|
17
|
+
const authCode = readStringProperty(isRecord(error) ? error.body : undefined, 'code')
|
|
20
18
|
if (authCode && AUTH_MESSAGES[authCode]) return AUTH_MESSAGES[authCode]
|
|
21
19
|
|
|
22
20
|
const sqlState = readStringProperty(error, 'code')
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { isRecord } from '@admin/utils/shared/is-record'
|
|
2
|
+
|
|
1
3
|
export function cloneDefaultValue(value: unknown): unknown {
|
|
2
4
|
if (Array.isArray(value)) return value.map(cloneDefaultValue)
|
|
3
5
|
|
|
4
|
-
if (value
|
|
5
|
-
const clonedEntries = Object.entries(value
|
|
6
|
+
if (isRecord(value)) {
|
|
7
|
+
const clonedEntries = Object.entries(value).map(
|
|
6
8
|
([key, childValue]) => [key, cloneDefaultValue(childValue)] as const
|
|
7
9
|
)
|
|
8
10
|
return Object.fromEntries(clonedEntries)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RowData } from '@tanstack/react-table'
|
|
2
|
+
import { isRecord } from '@admin/utils/shared/is-record'
|
|
2
3
|
|
|
3
4
|
export function defaultGetId<TData extends RowData>(row: TData): string | null | undefined {
|
|
4
|
-
|
|
5
|
-
return typeof id === 'string' ? id : null
|
|
5
|
+
if (!isRecord(row)) return null
|
|
6
|
+
return typeof row.id === 'string' ? row.id : null
|
|
6
7
|
}
|
|
@@ -15,7 +15,7 @@ export function EditorToolbar({
|
|
|
15
15
|
role="toolbar"
|
|
16
16
|
aria-label={ariaLabel}
|
|
17
17
|
className={cn(
|
|
18
|
-
'sticky top-0 z-10 flex min-h-12 w-full items-center gap-1 overflow-x-auto overscroll-x-contain border-b border-border bg-card px-2 [scrollbar-width:none] max-
|
|
18
|
+
'sticky top-0 z-10 flex min-h-12 w-full items-center gap-1 overflow-x-auto overscroll-x-contain border-b border-border bg-card px-2 [scrollbar-width:none] max-xs:absolute max-xs:top-auto max-xs:h-[calc(2.75rem+env(safe-area-inset-bottom,0px))] max-xs:flex-nowrap max-xs:justify-start max-xs:border-t max-xs:border-b-0 max-xs:pb-[env(safe-area-inset-bottom,0px)] [&::-webkit-scrollbar]:hidden',
|
|
19
19
|
className
|
|
20
20
|
)}
|
|
21
21
|
>
|
|
@@ -33,6 +33,10 @@ export function SlashCommandMenu({
|
|
|
33
33
|
searchQuery: string
|
|
34
34
|
}) {
|
|
35
35
|
const activeItemRef = React.useRef<HTMLDivElement | null>(null)
|
|
36
|
+
|
|
37
|
+
function assignActiveItem(node: HTMLDivElement | null) {
|
|
38
|
+
activeItemRef.current = node
|
|
39
|
+
}
|
|
36
40
|
const searchInputRef = React.useRef<HTMLInputElement | null>(null)
|
|
37
41
|
const activeCommandId = commands[activeIndex]?.id
|
|
38
42
|
|
|
@@ -159,9 +163,7 @@ export function SlashCommandMenu({
|
|
|
159
163
|
index={index}
|
|
160
164
|
key={command.id}
|
|
161
165
|
data-active={isActive ? 'true' : undefined}
|
|
162
|
-
ref={
|
|
163
|
-
if (isActive) activeItemRef.current = node
|
|
164
|
-
}}
|
|
166
|
+
ref={isActive ? assignActiveItem : undefined}
|
|
165
167
|
onMouseDown={(event) => event.preventDefault()}
|
|
166
168
|
onMouseEnter={() => onActiveIndexChange(index)}
|
|
167
169
|
value={command}
|
|
@@ -120,7 +120,7 @@ export function SourceMode({
|
|
|
120
120
|
return (
|
|
121
121
|
<div
|
|
122
122
|
className={cn(
|
|
123
|
-
'content-editor-wrapper relative flex max-h-[90vh] min-h-
|
|
123
|
+
'content-editor-wrapper relative flex max-h-[90vh] min-h-source-editor resize-y flex-col overflow-hidden rounded-md border bg-background',
|
|
124
124
|
{ 'opacity-50': disabled },
|
|
125
125
|
className
|
|
126
126
|
)}
|
|
@@ -14,6 +14,8 @@ import { cn } from '@admin/utils/shared/cn'
|
|
|
14
14
|
import { NodeViewWrapper } from '@tiptap/react'
|
|
15
15
|
import NextImage from 'next/image'
|
|
16
16
|
|
|
17
|
+
const EDITOR_IMAGE_SIZES = '768px'
|
|
18
|
+
|
|
17
19
|
export const RemovableImageNode: React.FC<NodeViewProps> = (props) => {
|
|
18
20
|
const { editor, node } = props
|
|
19
21
|
const src = getStringAttr(node.attrs.src)
|
|
@@ -118,7 +120,7 @@ export const RemovableImageNode: React.FC<NodeViewProps> = (props) => {
|
|
|
118
120
|
alt={alt}
|
|
119
121
|
title={title || undefined}
|
|
120
122
|
fill
|
|
121
|
-
sizes=
|
|
123
|
+
sizes={EDITOR_IMAGE_SIZES}
|
|
122
124
|
unoptimized
|
|
123
125
|
className="!m-0 !h-full !w-full !max-w-full object-contain"
|
|
124
126
|
onLoad={handleImageLoad}
|
|
@@ -5,6 +5,7 @@ import { getTaskItemCheckboxLabel } from '@admin/utils/editor/get-task-item-chec
|
|
|
5
5
|
import { hasOwnAttribute } from '@admin/utils/editor/has-own-attribute'
|
|
6
6
|
import { isTaskItemChecked } from '@admin/utils/editor/is-task-item-checked'
|
|
7
7
|
import { setElementAttribute } from '@admin/utils/editor/set-element-attribute'
|
|
8
|
+
import { setTaskItemChecked } from '@admin/utils/editor/set-task-item-checked'
|
|
8
9
|
import { getRenderedAttributes } from '@tiptap/core'
|
|
9
10
|
import { TaskItem } from '@tiptap/extension-list'
|
|
10
11
|
import { createRoot } from 'react-dom/client'
|
|
@@ -20,7 +21,7 @@ export const ContentEditorTaskItem = TaskItem.extend({
|
|
|
20
21
|
const checkboxMount = document.createElement('span')
|
|
21
22
|
const content = document.createElement('div')
|
|
22
23
|
const checkboxRoot = createRoot(checkboxMount)
|
|
23
|
-
const staticAttributes = this.options.HTMLAttributes
|
|
24
|
+
const staticAttributes: Record<string, unknown> = this.options.HTMLAttributes
|
|
24
25
|
|
|
25
26
|
checkboxContainer.contentEditable = 'false'
|
|
26
27
|
checkboxContainer.className = 'content-editor-task-item-checkbox'
|
|
@@ -52,17 +53,7 @@ export const ContentEditorTaskItem = TaskItem.extend({
|
|
|
52
53
|
editor
|
|
53
54
|
.chain()
|
|
54
55
|
.focus(undefined, { scrollIntoView: false })
|
|
55
|
-
.command(({ tr }) =>
|
|
56
|
-
const position = getPos()
|
|
57
|
-
if (typeof position !== 'number') return false
|
|
58
|
-
|
|
59
|
-
const taskItem = tr.doc.nodeAt(position)
|
|
60
|
-
tr.setNodeMarkup(position, undefined, {
|
|
61
|
-
...taskItem?.attrs,
|
|
62
|
-
checked
|
|
63
|
-
})
|
|
64
|
-
return true
|
|
65
|
-
})
|
|
56
|
+
.command(({ tr }) => setTaskItemChecked(tr, getPos(), checked))
|
|
66
57
|
.run()
|
|
67
58
|
return
|
|
68
59
|
}
|
|
@@ -89,7 +80,7 @@ export const ContentEditorTaskItem = TaskItem.extend({
|
|
|
89
80
|
listItem.dataset.checked = String(renderedChecked)
|
|
90
81
|
}
|
|
91
82
|
|
|
92
|
-
applyAttributes(HTMLAttributes
|
|
83
|
+
applyAttributes(HTMLAttributes)
|
|
93
84
|
renderCheckbox()
|
|
94
85
|
|
|
95
86
|
let prevRenderedAttributeKeys = new Set(Object.keys(HTMLAttributes))
|
|
@@ -104,10 +95,10 @@ export const ContentEditorTaskItem = TaskItem.extend({
|
|
|
104
95
|
renderedChecked = isTaskItemChecked(updatedNode)
|
|
105
96
|
|
|
106
97
|
const extensionAttributes = editor.extensionManager.attributes
|
|
107
|
-
const newHTMLAttributes = getRenderedAttributes(
|
|
98
|
+
const newHTMLAttributes: Record<string, unknown> = getRenderedAttributes(
|
|
108
99
|
updatedNode,
|
|
109
100
|
extensionAttributes
|
|
110
|
-
)
|
|
101
|
+
)
|
|
111
102
|
const newKeys = new Set(Object.keys(newHTMLAttributes))
|
|
112
103
|
|
|
113
104
|
prevRenderedAttributeKeys.forEach((key) => {
|
|
@@ -93,12 +93,7 @@ export function HeadingDropdownMenu({
|
|
|
93
93
|
}
|
|
94
94
|
></DropdownMenuTrigger>
|
|
95
95
|
|
|
96
|
-
<DropdownMenuContent
|
|
97
|
-
align="start"
|
|
98
|
-
className="w-auto min-w-40"
|
|
99
|
-
finalFocus={false}
|
|
100
|
-
portalled={false}
|
|
101
|
-
>
|
|
96
|
+
<DropdownMenuContent align="start" className="w-auto min-w-40" finalFocus={false}>
|
|
102
97
|
<DropdownMenuGroup>
|
|
103
98
|
{levels.map((level) => (
|
|
104
99
|
<HeadingDropdownMenuItem key={`heading-${level}`} editor={editor} level={level} />
|
|
@@ -83,12 +83,7 @@ export function ListDropdownMenu({
|
|
|
83
83
|
<ChevronDownIcon className="tiptap-button-dropdown-small" />
|
|
84
84
|
</DropdownMenuTrigger>
|
|
85
85
|
|
|
86
|
-
<DropdownMenuContent
|
|
87
|
-
align="start"
|
|
88
|
-
className="w-auto min-w-40"
|
|
89
|
-
finalFocus={false}
|
|
90
|
-
portalled={false}
|
|
91
|
-
>
|
|
86
|
+
<DropdownMenuContent align="start" className="w-auto min-w-40" finalFocus={false}>
|
|
92
87
|
<DropdownMenuGroup>
|
|
93
88
|
{filteredLists.map((option) => (
|
|
94
89
|
<ListDropdownMenuItem
|
|
@@ -132,14 +132,21 @@ export function DateRangePicker({
|
|
|
132
132
|
>
|
|
133
133
|
<PopoverTrigger
|
|
134
134
|
render={
|
|
135
|
-
<Button
|
|
135
|
+
<Button
|
|
136
|
+
variant="outline"
|
|
137
|
+
className={cn('w-date-range-trigger', className)}
|
|
138
|
+
disabled={disabled}
|
|
139
|
+
/>
|
|
136
140
|
}
|
|
137
141
|
>
|
|
138
142
|
<CalendarIcon />
|
|
139
143
|
<span className="min-w-0 flex-1 truncate text-left tabular-nums">{triggerLabel}</span>
|
|
140
144
|
<ChevronDown />
|
|
141
145
|
</PopoverTrigger>
|
|
142
|
-
<PopoverContent
|
|
146
|
+
<PopoverContent
|
|
147
|
+
className="w-date-range-popover gap-0 overflow-hidden rounded-sm p-0"
|
|
148
|
+
align="start"
|
|
149
|
+
>
|
|
143
150
|
<Calendar
|
|
144
151
|
mode="range"
|
|
145
152
|
month={calendarMonth}
|
|
@@ -189,7 +189,7 @@ export function GalleryField({
|
|
|
189
189
|
>
|
|
190
190
|
<CarouselContent className="-ml-3">
|
|
191
191
|
{canAdd && !disabled ? (
|
|
192
|
-
<CarouselItem className="basis-
|
|
192
|
+
<CarouselItem className="basis-gallery-item pl-3">
|
|
193
193
|
<Card className="h-full" onClick={() => setOpen(true)}>
|
|
194
194
|
<CardContent className="flex cursor-pointer flex-col p-2">
|
|
195
195
|
<div className="flex aspect-square size-full flex-col items-center justify-center gap-1 overflow-hidden rounded-sm border border-border bg-background text-muted-foreground transition-colors hover:text-foreground">
|
|
@@ -208,7 +208,7 @@ export function GalleryField({
|
|
|
208
208
|
{value.map((id) => {
|
|
209
209
|
const item = mediaMap.get(id)
|
|
210
210
|
return (
|
|
211
|
-
<CarouselItem key={id} className="basis-
|
|
211
|
+
<CarouselItem key={id} className="basis-gallery-item pl-3">
|
|
212
212
|
<SortableGalleryItem id={id} disabled={disabled}>
|
|
213
213
|
{item ? (
|
|
214
214
|
<MediaField
|
|
@@ -243,7 +243,7 @@ export function GalleryField({
|
|
|
243
243
|
</div>
|
|
244
244
|
<DragOverlay>
|
|
245
245
|
{activeId ? (
|
|
246
|
-
<div className="w-
|
|
246
|
+
<div className="w-gallery-item scale-[0.98] cursor-grabbing opacity-95">
|
|
247
247
|
{activeItem ? (
|
|
248
248
|
<MediaField
|
|
249
249
|
value={activeId}
|
|
@@ -102,7 +102,7 @@ export function MediaField({
|
|
|
102
102
|
data-media-field-action="true"
|
|
103
103
|
variant="outline"
|
|
104
104
|
onClick={handleChangeImage}
|
|
105
|
-
className="w-
|
|
105
|
+
className="w-media-thumb border-primary/10"
|
|
106
106
|
>
|
|
107
107
|
Change
|
|
108
108
|
</Button>
|
|
@@ -111,7 +111,7 @@ export function MediaField({
|
|
|
111
111
|
data-media-field-action="true"
|
|
112
112
|
variant="default"
|
|
113
113
|
onClick={handleRemove}
|
|
114
|
-
className="w-
|
|
114
|
+
className="w-media-thumb"
|
|
115
115
|
>
|
|
116
116
|
Remove
|
|
117
117
|
</Button>
|
|
@@ -13,6 +13,7 @@ import { FormDescription, FormField, FormItem, FormLabel } from '@admin/componen
|
|
|
13
13
|
import { cloneDefaultValue } from '@admin/utils/form/clone-default-value'
|
|
14
14
|
import { createListItemKey } from '@admin/utils/form/create-list-item-key'
|
|
15
15
|
import { cn } from '@admin/utils/shared/cn'
|
|
16
|
+
import { isRecord } from '@admin/utils/shared/is-record'
|
|
16
17
|
import { Plus, X } from 'lucide-react'
|
|
17
18
|
import { useFormContext, useWatch } from 'react-hook-form'
|
|
18
19
|
|
|
@@ -75,7 +76,8 @@ export function NestedObjectListField({
|
|
|
75
76
|
if (!isExpandedItemValid) return
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
const
|
|
79
|
+
const clonedDefaultValue = cloneDefaultValue(defaultValue)
|
|
80
|
+
const nextValue = isRecord(clonedDefaultValue) ? clonedDefaultValue : {}
|
|
79
81
|
const nextItems = [...items, nextValue]
|
|
80
82
|
setValue(name, nextItems, {
|
|
81
83
|
shouldDirty: true,
|
|
@@ -5,6 +5,8 @@ import { usePageBoundaryBlurVisibility } from '@admin/hooks/use-page-boundary-bl
|
|
|
5
5
|
import { cn } from '@admin/utils/shared/cn'
|
|
6
6
|
import { motion } from 'motion/react'
|
|
7
7
|
|
|
8
|
+
const DEFAULT_PROGRESSIVE_BLUR_HEIGHT = '150px'
|
|
9
|
+
|
|
8
10
|
type ProgressiveBlurProps = React.ComponentProps<typeof motion.div> & {
|
|
9
11
|
backgroundColor?: string
|
|
10
12
|
position?: 'top' | 'bottom'
|
|
@@ -18,7 +20,7 @@ function ProgressiveBlur({
|
|
|
18
20
|
style,
|
|
19
21
|
backgroundColor = 'var(--background)',
|
|
20
22
|
position = 'top',
|
|
21
|
-
height =
|
|
23
|
+
height = DEFAULT_PROGRESSIVE_BLUR_HEIGHT,
|
|
22
24
|
blurAmount = '0',
|
|
23
25
|
scrollAware = true,
|
|
24
26
|
...props
|
|
@@ -22,33 +22,30 @@ function DropdownMenuContent({
|
|
|
22
22
|
alignOffset = 0,
|
|
23
23
|
side = 'bottom',
|
|
24
24
|
sideOffset = 4,
|
|
25
|
-
portalled = true,
|
|
26
25
|
className,
|
|
27
26
|
...props
|
|
28
27
|
}: MenuPrimitive.Popup.Props &
|
|
29
|
-
Pick<MenuPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
</MenuPrimitive.
|
|
28
|
+
Pick<MenuPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) {
|
|
29
|
+
return (
|
|
30
|
+
<MenuPrimitive.Portal>
|
|
31
|
+
<MenuPrimitive.Positioner
|
|
32
|
+
className="isolate z-50 outline-none"
|
|
33
|
+
align={align}
|
|
34
|
+
alignOffset={alignOffset}
|
|
35
|
+
side={side}
|
|
36
|
+
sideOffset={sideOffset}
|
|
37
|
+
>
|
|
38
|
+
<MenuPrimitive.Popup
|
|
39
|
+
data-slot="dropdown-menu-content"
|
|
40
|
+
className={cn(
|
|
41
|
+
'cn-menu-target cn-menu-translucent z-50 max-h-(--available-height) w-(--anchor-width) min-w-48 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-2xl bg-popover p-1 text-popover-foreground shadow-2xl ring-1 ring-foreground/5 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95',
|
|
42
|
+
className
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
</MenuPrimitive.Positioner>
|
|
47
|
+
</MenuPrimitive.Portal>
|
|
49
48
|
)
|
|
50
|
-
|
|
51
|
-
return portalled ? <MenuPrimitive.Portal>{content}</MenuPrimitive.Portal> : content
|
|
52
49
|
}
|
|
53
50
|
|
|
54
51
|
function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import type { ControllerProps, FieldPath, FieldValues } from 'react-hook-form'
|
|
5
5
|
import { Label } from '@admin/components/ui/label'
|
|
6
|
+
import { useFieldErrorVisible } from '@admin/hooks/use-field-error-visible'
|
|
6
7
|
import { cn } from '@admin/utils/shared/cn'
|
|
7
8
|
import { Controller, FormProvider, useFormContext } from 'react-hook-form'
|
|
8
9
|
|
|
@@ -33,7 +34,8 @@ const FormField = <
|
|
|
33
34
|
const useFormField = () => {
|
|
34
35
|
const fieldContext = React.useContext(FormFieldContext)
|
|
35
36
|
const itemContext = React.useContext(FormItemContext)
|
|
36
|
-
const
|
|
37
|
+
const form = useFormContext()
|
|
38
|
+
const isErrorVisible = useFieldErrorVisible(form, fieldContext?.name ?? '')
|
|
37
39
|
|
|
38
40
|
if (!fieldContext) {
|
|
39
41
|
throw new Error('useFormField should be used within <FormField>')
|
|
@@ -43,7 +45,7 @@ const useFormField = () => {
|
|
|
43
45
|
throw new Error('useFormField should be used within <FormItem>')
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
const fieldState = getFieldState(fieldContext.name, formState)
|
|
48
|
+
const fieldState = form.getFieldState(fieldContext.name, form.formState)
|
|
47
49
|
|
|
48
50
|
const { id } = itemContext
|
|
49
51
|
|
|
@@ -53,7 +55,8 @@ const useFormField = () => {
|
|
|
53
55
|
formItemId: `${id}-form-item`,
|
|
54
56
|
formDescriptionId: `${id}-form-item-description`,
|
|
55
57
|
formMessageId: `${id}-form-item-message`,
|
|
56
|
-
...fieldState
|
|
58
|
+
...fieldState,
|
|
59
|
+
error: isErrorVisible ? fieldState.error : undefined
|
|
57
60
|
}
|
|
58
61
|
}
|
|
59
62
|
|
|
@@ -108,7 +108,7 @@ function NavigationMenuPositioner({
|
|
|
108
108
|
)}
|
|
109
109
|
{...props}
|
|
110
110
|
>
|
|
111
|
-
<NavigationMenuPrimitive.Popup className="data-[ending-style]:easing-[ease]
|
|
111
|
+
<NavigationMenuPrimitive.Popup className="data-[ending-style]:easing-[ease] relative h-(--popup-height) w-(--popup-width) origin-(--transform-origin) rounded-2xl bg-popover text-popover-foreground shadow ring-1 ring-foreground/5 transition-[opacity,transform,width,height,scale,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] outline-none data-ending-style:scale-90 data-ending-style:opacity-0 data-ending-style:duration-150 data-starting-style:scale-90 data-starting-style:opacity-0 xs:w-(--popup-width)">
|
|
112
112
|
<NavigationMenuPrimitive.Viewport className="relative size-full overflow-hidden" />
|
|
113
113
|
</NavigationMenuPrimitive.Popup>
|
|
114
114
|
</NavigationMenuPrimitive.Positioner>
|
|
@@ -12,6 +12,7 @@ var CLI_PACKAGE_NAME = "betterstart-cli";
|
|
|
12
12
|
var REDACTED = "[redacted]";
|
|
13
13
|
|
|
14
14
|
// constants/paths.ts
|
|
15
|
+
var ADMIN_CONTAINER_ROUTE_GROUP = "(container)";
|
|
15
16
|
var BETTERSTART_DIR = ".betterstart";
|
|
16
17
|
var CONFIG_FILE_NAME = "betterstart.config.ts";
|
|
17
18
|
var DEVELOPMENT_ENV_FILES = [
|
|
@@ -181,6 +182,14 @@ function safeWriteFile(filePath, content, force = false) {
|
|
|
181
182
|
fs.writeFileSync(filePath, content, "utf-8");
|
|
182
183
|
return true;
|
|
183
184
|
}
|
|
185
|
+
function safeCopyFile(src, dest, force = false) {
|
|
186
|
+
if (!force && fs.existsSync(dest)) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
ensureDir(path.dirname(dest));
|
|
190
|
+
fs.copyFileSync(src, dest);
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
184
193
|
function createGeneratedFile(filePath, content) {
|
|
185
194
|
return {
|
|
186
195
|
path: filePath.split(path.sep).join("/"),
|
|
@@ -498,6 +507,7 @@ var R2_ENV_KEYS = [
|
|
|
498
507
|
"BETTERSTART_R2_BUCKET_NAME",
|
|
499
508
|
"BETTERSTART_R2_PUBLIC_URL"
|
|
500
509
|
];
|
|
510
|
+
var PUBLIC_ASSET_FILE_NAMES = ["placeholder.png"];
|
|
501
511
|
var PROXY_FILE_NAME = "proxy.ts";
|
|
502
512
|
var PROXY_CONVENTION_FILE_NAMES = [
|
|
503
513
|
"proxy.ts",
|
|
@@ -693,6 +703,7 @@ function applyAdminNamespaceToContent(content, namespaceValue) {
|
|
|
693
703
|
}
|
|
694
704
|
|
|
695
705
|
export {
|
|
706
|
+
ADMIN_CONTAINER_ROUTE_GROUP,
|
|
696
707
|
BETTERSTART_DIR,
|
|
697
708
|
CONFIG_FILE_NAME,
|
|
698
709
|
LOCKFILE_MAP,
|
|
@@ -728,6 +739,7 @@ export {
|
|
|
728
739
|
hashContent,
|
|
729
740
|
ensureDir,
|
|
730
741
|
safeWriteFile,
|
|
742
|
+
safeCopyFile,
|
|
731
743
|
createGeneratedFile,
|
|
732
744
|
toStrictJson,
|
|
733
745
|
parseDotenvFile,
|
|
@@ -761,6 +773,7 @@ export {
|
|
|
761
773
|
TIPTAP_CONTENT_EDITOR_DIRECTORIES,
|
|
762
774
|
RAILWAY_BUCKET_ENV_KEYS,
|
|
763
775
|
R2_ENV_KEYS,
|
|
776
|
+
PUBLIC_ASSET_FILE_NAMES,
|
|
764
777
|
PROXY_FILE_NAME,
|
|
765
778
|
PROXY_CONVENTION_FILE_NAMES,
|
|
766
779
|
REMOVABLE_NAMESPACE_PATTERN,
|
|
@@ -779,4 +792,4 @@ export {
|
|
|
779
792
|
replaceAdminDashToken,
|
|
780
793
|
applyAdminNamespaceToContent
|
|
781
794
|
};
|
|
782
|
-
//# sourceMappingURL=chunk-
|
|
795
|
+
//# sourceMappingURL=chunk-BNHFSHPE.js.map
|