betterstart-cli 0.0.16 → 0.0.18

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 (30) hide show
  1. package/dist/assets/adapters/next/plugins/blog/schemas/menus.json +1 -0
  2. package/dist/assets/adapters/next/plugins/blog/schemas/posts.json +132 -99
  3. package/dist/assets/adapters/next/plugins/portfolio/plugin.ts +17 -0
  4. package/dist/assets/adapters/next/plugins/portfolio/schemas/portfolio.json +128 -0
  5. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/dev-mode-types.ts +2 -2
  6. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/snippets-tab.tsx +1 -0
  7. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode-integrate.tsx +1 -1
  8. package/dist/assets/adapters/next/templates/init/components/shared/media/media-delete-dialog.tsx +1 -1
  9. package/dist/assets/adapters/next/templates/init/components/shared/media/media-delete-drawer.tsx +1 -1
  10. package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-item.tsx +17 -7
  11. package/dist/assets/adapters/next/templates/init/data/navigation.ts +2 -1
  12. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-source-mode.tsx +3 -3
  13. package/dist/assets/adapters/next/templates/init/hooks/use-media.ts +2 -1
  14. package/dist/assets/adapters/next/templates/init/pages/profile/profile-form.tsx +3 -3
  15. package/dist/assets/adapters/next/templates/init/types/index.ts +7 -2
  16. package/dist/assets/shared-assets/react-admin/custom/content-editor/media-gallery-block.tsx +2 -2
  17. package/dist/assets/shared-assets/react-admin/custom/content-editor/table-add-controls.tsx +2 -2
  18. package/dist/assets/shared-assets/react-admin/custom/gallery-field.tsx +219 -40
  19. package/dist/assets/shared-assets/react-admin/custom/media-field-empty-state.tsx +99 -0
  20. package/dist/assets/shared-assets/react-admin/custom/media-field.tsx +181 -0
  21. package/dist/assets/shared-assets/react-admin/custom/sortable-gallery-item.tsx +38 -38
  22. package/dist/assets/shared-assets/react-admin/dependencies.ts +1 -0
  23. package/dist/assets/shared-assets/react-admin/schema.json +64 -2
  24. package/dist/assets/shared-assets/react-admin/ui/chart.tsx +1 -1
  25. package/dist/assets/shared-assets/react-admin/ui/pagination.tsx +1 -1
  26. package/dist/cli.js +562 -151
  27. package/dist/cli.js.map +1 -1
  28. package/package.json +1 -1
  29. package/dist/assets/shared-assets/react-admin/custom/gallery-thumbnail.tsx +0 -39
  30. package/dist/assets/shared-assets/react-admin/custom/media-gallery-field.tsx +0 -182
@@ -1,68 +1,68 @@
1
- import type { AdminMedia } from '@admin/types'
1
+ import { Button } from '@admin/components/ui/button'
2
+ import { Card, CardContent, CardFooter } from '@admin/components/ui/card'
3
+ import { Skeleton } from '@admin/components/ui/skeleton'
2
4
  import { useSortable } from '@dnd-kit/sortable'
3
5
  import { CSS } from '@dnd-kit/utilities'
4
- import { GripVertical, X } from 'lucide-react'
6
+ import { GripVertical } from 'lucide-react'
5
7
  import type * as React from 'react'
6
- import { GalleryThumbnail } from './gallery-thumbnail'
7
8
 
8
9
  export function SortableGalleryItem({
9
10
  id,
10
- media,
11
11
  disabled,
12
- onRemove
12
+ children
13
13
  }: {
14
14
  id: string
15
- media: AdminMedia | undefined
16
15
  disabled?: boolean
17
- onRemove: () => void
16
+ children: React.ReactNode
18
17
  }) {
19
18
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
20
19
  id,
21
20
  disabled
22
21
  })
23
22
 
24
- const style: React.CSSProperties = {
25
- transform: CSS.Transform.toString(transform),
26
- transition,
27
- opacity: isDragging ? 0.5 : 1
28
- }
29
-
30
23
  return (
31
24
  <div
32
25
  ref={setNodeRef}
33
- style={style}
34
- className="group relative aspect-square overflow-hidden rounded-lg border bg-muted"
26
+ data-gallery-dragging={isDragging ? 'true' : undefined}
27
+ style={{
28
+ transform: CSS.Translate.toString(transform),
29
+ transition: isDragging ? undefined : transition,
30
+ zIndex: isDragging ? 30 : undefined,
31
+ willChange: isDragging ? 'transform' : undefined
32
+ }}
33
+ className="group relative min-w-0 select-none [&[data-gallery-dragging=true]_[data-gallery-drag-handle]]:pointer-events-none [&[data-gallery-dragging=true]_[data-gallery-drag-handle]]:opacity-0 [&[data-gallery-dragging=true]_[data-media-field-action]]:pointer-events-none [&[data-gallery-dragging=true]_[data-media-field-action]]:opacity-0"
35
34
  >
35
+ <div
36
+ aria-hidden="true"
37
+ className="pointer-events-none absolute inset-0 opacity-0 transition-opacity group-data-[gallery-dragging=true]:opacity-100"
38
+ >
39
+ <Card className="h-full">
40
+ <CardContent className="p-2 flex flex-col">
41
+ <div className="flex size-full bg-background border border-border rounded-sm aspect-square overflow-hidden">
42
+ <Skeleton className="size-full" />
43
+ </div>
44
+ </CardContent>
45
+ <CardFooter>
46
+ <Skeleton className="h-4 w-3/4" />
47
+ </CardFooter>
48
+ </Card>
49
+ </div>
36
50
  {!disabled && (
37
- <div
51
+ <Button
38
52
  {...attributes}
39
53
  {...listeners}
40
- className="absolute left-1 top-1 z-10 cursor-grab rounded bg-background/80 p-0.5 opacity-0 transition-opacity group-hover:opacity-100 active:cursor-grabbing"
54
+ data-gallery-drag-handle
55
+ variant="outline"
56
+ size="icon-sm"
57
+ className="absolute right-1 top-1 z-10 cursor-grab touch-none opacity-0 transition-[opacity,transform] group-hover:opacity-100 active:scale-[0.96] active:cursor-grabbing border-primary/10"
41
58
  >
42
59
  <GripVertical className="size-3.5 text-foreground" />
43
- </div>
44
- )}
45
-
46
- {!disabled && (
47
- <button
48
- type="button"
49
- onClick={(e) => {
50
- e.stopPropagation()
51
- onRemove()
52
- }}
53
- className="absolute right-1 top-1 z-10 flex size-5 items-center justify-center rounded-full bg-destructive text-destructive-foreground opacity-0 transition-opacity group-hover:opacity-100"
54
- >
55
- <X className="size-3" />
56
- </button>
60
+ </Button>
57
61
  )}
58
62
 
59
- {media ? (
60
- <GalleryThumbnail media={media} />
61
- ) : (
62
- <div className="flex size-full items-center justify-center">
63
- <div className="size-4 animate-pulse rounded-full bg-muted-foreground/20" />
64
- </div>
65
- )}
63
+ <div className="relative transition-opacity group-data-[gallery-dragging=true]:opacity-0">
64
+ {children}
65
+ </div>
66
66
  </div>
67
67
  )
68
68
  }
@@ -4,6 +4,7 @@ export const REACT_ADMIN_DEPS = [
4
4
  '@codemirror/lang-javascript',
5
5
  '@codemirror/lang-json',
6
6
  '@codemirror/lang-markdown',
7
+ '@codemirror/state',
7
8
  '@codemirror/view',
8
9
  '@dnd-kit/core',
9
10
  '@dnd-kit/sortable',
@@ -4,7 +4,7 @@
4
4
  "title": "BetterStart Schema Definition",
5
5
  "description": "JSON Schema for validating custom schema files (courses.json, testimonials.json, instructors.json, events.json, etc.)",
6
6
  "type": "object",
7
- "required": ["name", "label"],
7
+ "required": ["type", "name", "label"],
8
8
  "additionalProperties": false,
9
9
  "properties": {
10
10
  "$schema": {
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "type": {
32
32
  "type": "string",
33
- "description": "Schema type: 'entity' for CRUD list (default), 'single' for singleton record (site settings, about page), or 'form' for public submission forms",
33
+ "description": "Schema type: 'entity' for CRUD list, 'single' for singleton record (site settings, about page), or 'form' for public submission forms",
34
34
  "enum": ["entity", "single", "form"]
35
35
  },
36
36
  "fields": {
@@ -157,6 +157,9 @@
157
157
  {
158
158
  "$ref": "#/$defs/stringField"
159
159
  },
160
+ {
161
+ "$ref": "#/$defs/emailField"
162
+ },
160
163
  {
161
164
  "$ref": "#/$defs/textField"
162
165
  },
@@ -423,6 +426,61 @@
423
426
  }
424
427
  }
425
428
  },
429
+ "emailField": {
430
+ "type": "object",
431
+ "description": "Email input field",
432
+ "required": ["name", "type"],
433
+ "additionalProperties": false,
434
+ "properties": {
435
+ "name": {
436
+ "type": "string"
437
+ },
438
+ "type": {
439
+ "const": "email"
440
+ },
441
+ "label": {
442
+ "type": "string"
443
+ },
444
+ "required": {
445
+ "type": "boolean"
446
+ },
447
+ "length": {
448
+ "type": "integer",
449
+ "description": "Maximum character length",
450
+ "minimum": 1,
451
+ "maximum": 65535
452
+ },
453
+ "hint": {
454
+ "type": "string"
455
+ },
456
+ "placeholder": {
457
+ "type": "string",
458
+ "description": "Placeholder text displayed in the email input"
459
+ },
460
+ "default": {
461
+ "type": "string"
462
+ },
463
+ "defaultValueFrom": {
464
+ "$ref": "#/$defs/defaultValueFrom"
465
+ },
466
+ "hasIcon": {
467
+ "type": "boolean",
468
+ "description": "Whether this field has an associated icon picker"
469
+ },
470
+ "hidden": {
471
+ "type": "boolean",
472
+ "description": "Whether this field is hidden from the form UI but still exists in the database"
473
+ },
474
+ "showWhen": {
475
+ "$ref": "#/$defs/showWhenCondition"
476
+ },
477
+ "height": {
478
+ "enum": ["auto", "fill"],
479
+ "default": "auto",
480
+ "description": "Generated field height behavior: auto size or fill remaining flexible space."
481
+ }
482
+ }
483
+ },
426
484
  "markdownField": {
427
485
  "type": "object",
428
486
  "description": "Rich text editor with markdown support",
@@ -1221,6 +1279,10 @@
1221
1279
  "type": "string",
1222
1280
  "description": "Tab display label"
1223
1281
  },
1282
+ "icon": {
1283
+ "type": "string",
1284
+ "description": "Lucide icon name rendered before the tab label"
1285
+ },
1224
1286
  "fields": {
1225
1287
  "type": "array",
1226
1288
  "description": "Fields within this tab",
@@ -2,13 +2,13 @@
2
2
 
3
3
  import { cn } from '@admin/utils/shared/cn'
4
4
  import * as React from 'react'
5
- import type { TooltipValueType } from 'recharts'
6
5
  import * as RechartsPrimitive from 'recharts'
7
6
 
8
7
  // Format: { THEME_NAME: CSS_SELECTOR }
9
8
  const THEMES = { light: '', dark: '.dark' } as const
10
9
 
11
10
  const INITIAL_DIMENSION = { width: 320, height: 200 } as const
11
+ type TooltipValueType = number | string | ReadonlyArray<number | string>
12
12
  type TooltipNameType = number | string
13
13
 
14
14
  export type ChartConfig = Record<
@@ -59,7 +59,7 @@ function PaginationPrevious({
59
59
  className={cn('pl-2!', className)}
60
60
  {...props}
61
61
  >
62
- <ChevronLeftIcon data-icon="inline-start" />
62
+ <ChevronLeftIcon />
63
63
  <span className="hidden sm:block">{text}</span>
64
64
  </PaginationLink>
65
65
  )