@vendure-io/ui 1.3.0 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +5 -5
  2. package/package.json +10 -5
  3. package/src/components/{ui → atoms}/alert-dialog.tsx +4 -4
  4. package/src/components/{ui → atoms}/badge.tsx +6 -3
  5. package/src/components/{ui → atoms}/button-group.tsx +1 -2
  6. package/src/components/{ui → atoms}/button.tsx +8 -2
  7. package/src/components/{ui → atoms}/calendar.tsx +1 -1
  8. package/src/components/{ui → atoms}/card.tsx +2 -3
  9. package/src/components/{ui → atoms}/carousel.tsx +1 -1
  10. package/src/components/atoms/checkbox.tsx +29 -0
  11. package/src/components/{ui → atoms}/combobox.tsx +3 -4
  12. package/src/components/{ui → atoms}/command.tsx +2 -2
  13. package/src/components/{ui → atoms}/context-menu.tsx +1 -1
  14. package/src/components/{ui → atoms}/dialog.tsx +4 -4
  15. package/src/components/{ui → atoms}/drawer.tsx +3 -3
  16. package/src/components/{ui → atoms}/dropdown-menu.tsx +3 -2
  17. package/src/components/{ui → atoms}/empty.tsx +1 -1
  18. package/src/components/{ui → atoms}/field.tsx +2 -2
  19. package/src/components/{ui → atoms}/hover-card.tsx +1 -1
  20. package/src/components/{ui → atoms}/input-group.tsx +3 -4
  21. package/src/components/{ui → atoms}/input-otp.tsx +0 -1
  22. package/src/components/{ui → atoms}/input.tsx +0 -1
  23. package/src/components/{ui → atoms}/item.tsx +2 -2
  24. package/src/components/{ui → atoms}/menubar.tsx +3 -4
  25. package/src/components/{ui → atoms}/native-select.tsx +0 -1
  26. package/src/components/{ui → atoms}/navigation-menu.tsx +7 -4
  27. package/src/components/{ui → atoms}/pagination.tsx +1 -1
  28. package/src/components/{ui → atoms}/popover.tsx +2 -2
  29. package/src/components/{ui → atoms}/select.tsx +22 -4
  30. package/src/components/{ui → atoms}/sheet.tsx +4 -4
  31. package/src/components/{ui → atoms}/sidebar.tsx +6 -6
  32. package/src/components/atoms/skeleton.tsx +16 -0
  33. package/src/components/{ui → atoms}/slider.tsx +0 -1
  34. package/src/components/{ui → atoms}/sonner.tsx +1 -1
  35. package/src/components/{ui → atoms}/switch.tsx +0 -1
  36. package/src/components/{ui → atoms}/tabs.tsx +6 -4
  37. package/src/components/{ui → atoms}/textarea.tsx +0 -1
  38. package/src/components/{ui → atoms}/toggle-group.tsx +3 -3
  39. package/src/components/{ui → atoms}/toggle.tsx +0 -1
  40. package/src/components/{ui → atoms}/tooltip.tsx +2 -1
  41. package/src/components/molecules/anonymized-token.tsx +170 -0
  42. package/src/components/molecules/chip.tsx +85 -0
  43. package/src/components/{custom → molecules}/combobox-free-text.tsx +7 -3
  44. package/src/components/molecules/confirm-dialog.tsx +108 -0
  45. package/src/components/molecules/copyable-text.tsx +102 -0
  46. package/src/components/molecules/data-table/data-table-bulk-actions.tsx +69 -0
  47. package/src/components/molecules/data-table/data-table-column-header.tsx +61 -0
  48. package/src/components/molecules/data-table/data-table-filters.tsx +198 -0
  49. package/src/components/molecules/data-table/data-table-helpers.tsx +73 -0
  50. package/src/components/molecules/data-table/data-table-types.tsx +241 -0
  51. package/src/components/molecules/data-table/data-table-view-options.tsx +73 -0
  52. package/src/components/molecules/data-table/data-table.tsx +500 -0
  53. package/src/components/molecules/data-table/list-header.tsx +53 -0
  54. package/src/components/molecules/data-table/table-pagination.tsx +263 -0
  55. package/src/components/molecules/date-time.tsx +73 -0
  56. package/src/components/molecules/description-list.tsx +120 -0
  57. package/src/components/molecules/format-provider.tsx +46 -0
  58. package/src/components/molecules/id-chip.tsx +79 -0
  59. package/src/components/molecules/illustrations/access-denied.tsx +55 -0
  60. package/src/components/molecules/illustrations/empty-collection.tsx +66 -0
  61. package/src/components/molecules/illustrations/empty-database.tsx +44 -0
  62. package/src/components/molecules/illustrations/empty-media.tsx +68 -0
  63. package/src/components/molecules/illustrations/error.tsx +64 -0
  64. package/src/components/molecules/illustrations/first-run.tsx +55 -0
  65. package/src/components/molecules/illustrations/illustration-types.tsx +9 -0
  66. package/src/components/molecules/illustrations/no-activity.tsx +49 -0
  67. package/src/components/molecules/illustrations/no-deployments.tsx +49 -0
  68. package/src/components/molecules/illustrations/no-documents.tsx +67 -0
  69. package/src/components/molecules/illustrations/no-keys.tsx +50 -0
  70. package/src/components/molecules/illustrations/no-logs.tsx +53 -0
  71. package/src/components/molecules/illustrations/no-members.tsx +56 -0
  72. package/src/components/molecules/illustrations/no-notifications.tsx +52 -0
  73. package/src/components/molecules/illustrations/no-orders.tsx +48 -0
  74. package/src/components/molecules/illustrations/no-plugins.tsx +72 -0
  75. package/src/components/molecules/illustrations/no-results.tsx +69 -0
  76. package/src/components/molecules/illustrations/not-found.tsx +48 -0
  77. package/src/components/molecules/illustrations/offline.tsx +43 -0
  78. package/src/components/molecules/illustrations/pending-approval.tsx +56 -0
  79. package/src/components/molecules/illustrations/upload-dropzone.tsx +59 -0
  80. package/src/components/molecules/money.tsx +91 -0
  81. package/src/components/{custom → molecules}/multi-select.tsx +2 -2
  82. package/src/components/molecules/page-header.tsx +80 -0
  83. package/src/components/molecules/password-input.tsx +47 -0
  84. package/src/components/molecules/relative-time.tsx +81 -0
  85. package/src/components/molecules/stat-card.tsx +134 -0
  86. package/src/components/molecules/state-views/empty-state.tsx +75 -0
  87. package/src/components/molecules/state-views/error-state.tsx +91 -0
  88. package/src/components/molecules/state-views/loading-state.tsx +80 -0
  89. package/src/components/molecules/status-badge.tsx +100 -0
  90. package/src/hooks/use-copy.ts +51 -0
  91. package/src/lib/base-ui.ts +1 -1
  92. package/src/lib/format-relative.ts +41 -0
  93. package/src/lib/state-dictionary.ts +137 -0
  94. package/src/components/ui/checkbox.tsx +0 -30
  95. package/src/components/ui/skeleton.tsx +0 -13
  96. /package/src/components/{ui → atoms}/accordion.tsx +0 -0
  97. /package/src/components/{ui → atoms}/alert.tsx +0 -0
  98. /package/src/components/{ui → atoms}/aspect-ratio.tsx +0 -0
  99. /package/src/components/{ui → atoms}/avatar.tsx +0 -0
  100. /package/src/components/{ui → atoms}/breadcrumb.tsx +0 -0
  101. /package/src/components/{ui → atoms}/chart.tsx +0 -0
  102. /package/src/components/{ui → atoms}/collapsible.tsx +0 -0
  103. /package/src/components/{ui → atoms}/direction.tsx +0 -0
  104. /package/src/components/{ui → atoms}/kbd.tsx +0 -0
  105. /package/src/components/{ui → atoms}/label.tsx +0 -0
  106. /package/src/components/{ui → atoms}/progress.tsx +0 -0
  107. /package/src/components/{ui → atoms}/radio-group.tsx +0 -0
  108. /package/src/components/{ui → atoms}/resizable.tsx +0 -0
  109. /package/src/components/{ui → atoms}/scroll-area.tsx +0 -0
  110. /package/src/components/{ui → atoms}/separator.tsx +0 -0
  111. /package/src/components/{ui → atoms}/spinner.tsx +0 -0
  112. /package/src/components/{ui → atoms}/table.tsx +0 -0
@@ -0,0 +1,66 @@
1
+ import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
2
+ import { cn } from '@vendure-io/ui/lib/utils';
3
+
4
+ /**
5
+ * An open, hollow box with its flaps folded back and a dashed "what goes
6
+ * here" outline floating above. The default for "nothing exists yet" —
7
+ * first-run lists, collections, catalogs. Not for a filtered/searched miss
8
+ * (use `NoResultsIllustration`).
9
+ */
10
+ function EmptyCollectionIllustration({ className, size = 160 }: IllustrationProps) {
11
+ return (
12
+ <svg
13
+ viewBox="0 0 160 120"
14
+ width={size}
15
+ height={(size * 120) / 160}
16
+ fill="none"
17
+ strokeWidth={1.5}
18
+ strokeLinecap="round"
19
+ strokeLinejoin="round"
20
+ aria-hidden="true"
21
+ focusable="false"
22
+ className={cn('shrink-0', className)}
23
+ >
24
+ <ellipse cx="80" cy="104" rx="30" ry="5" className="fill-muted" />
25
+
26
+ {/* open flaps, behind the box front */}
27
+ <polygon points="45,58 30,34 62,34 65,58" className="fill-muted stroke-muted-foreground" />
28
+ <polygon points="115,58 130,34 98,34 95,58" className="fill-muted stroke-muted-foreground" />
29
+
30
+ {/* hollow interior */}
31
+ <ellipse
32
+ cx="80"
33
+ cy="64"
34
+ rx="27"
35
+ ry="5"
36
+ className="fill-background stroke-border"
37
+ strokeDasharray="3 3"
38
+ />
39
+
40
+ {/* box body */}
41
+ <path
42
+ d="M45,58 L115,58 L115,86 C115,88 113.5,89 112,89 L48,89 C46.5,89 45,88 45,86 Z"
43
+ className="fill-surface stroke-muted-foreground"
44
+ />
45
+
46
+ {/* floating "what belongs here" outline */}
47
+ <rect
48
+ x="64"
49
+ y="12"
50
+ width="32"
51
+ height="24"
52
+ rx="3"
53
+ className="stroke-border"
54
+ strokeDasharray="3 4"
55
+ />
56
+
57
+ {/* sparkle — the one brand accent */}
58
+ <polygon
59
+ points="104,10 105.5,14.5 110,16 105.5,17.5 104,22 102.5,17.5 98,16 102.5,14.5"
60
+ className="fill-brand"
61
+ />
62
+ </svg>
63
+ );
64
+ }
65
+
66
+ export { EmptyCollectionIllustration };
@@ -0,0 +1,44 @@
1
+ import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
2
+ import { cn } from '@vendure-io/ui/lib/utils';
3
+
4
+ /**
5
+ * A database cylinder with a solid rim but dashed walls and dividing bands —
6
+ * a shell with nothing provisioned inside. For no database provisioned yet,
7
+ * or no backups exist. Not for a generic empty list (use
8
+ * `EmptyCollectionIllustration`).
9
+ */
10
+ function EmptyDatabaseIllustration({ className, size = 160 }: IllustrationProps) {
11
+ return (
12
+ <svg
13
+ viewBox="0 0 160 120"
14
+ width={size}
15
+ height={(size * 120) / 160}
16
+ fill="none"
17
+ strokeWidth={1.5}
18
+ strokeLinecap="round"
19
+ strokeLinejoin="round"
20
+ aria-hidden="true"
21
+ focusable="false"
22
+ className={cn('shrink-0', className)}
23
+ >
24
+ <ellipse cx="80" cy="104" rx="28" ry="5" className="fill-muted" />
25
+
26
+ {/* rim — the only solid, present surface */}
27
+ <ellipse cx="80" cy="34" rx="24" ry="8" className="fill-surface stroke-muted-foreground" />
28
+
29
+ {/* walls, empty */}
30
+ <line x1="56" y1="34" x2="56" y2="82" className="stroke-border" strokeDasharray="3 4" />
31
+ <line x1="104" y1="34" x2="104" y2="82" className="stroke-border" strokeDasharray="3 4" />
32
+
33
+ {/* dividing bands, nothing stacked between them */}
34
+ <path d="M56,50 A24,8 0 0,0 104,50" className="stroke-border" strokeDasharray="3 4" />
35
+ <path d="M56,66 A24,8 0 0,0 104,66" className="stroke-border" strokeDasharray="3 4" />
36
+ <path d="M56,82 A24,8 0 0,0 104,82" className="stroke-border" strokeDasharray="3 4" />
37
+
38
+ {/* status dot — the one brand accent */}
39
+ <circle cx="100" cy="28" r="4" className="fill-brand" />
40
+ </svg>
41
+ );
42
+ }
43
+
44
+ export { EmptyDatabaseIllustration };
@@ -0,0 +1,68 @@
1
+ import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
2
+ import { cn } from '@vendure-io/ui/lib/utils';
3
+
4
+ /**
5
+ * A photo tile with a sun-over-mountains glyph, floated in front of one or
6
+ * two dashed placeholder tiles. For an empty asset/media library or an
7
+ * empty folder in an asset browser. Not for a generic empty list (use
8
+ * `EmptyCollectionIllustration`) or a drag-to-upload target (use
9
+ * `UploadDropzoneIllustration`).
10
+ */
11
+ function EmptyMediaIllustration({ className, size = 160 }: IllustrationProps) {
12
+ return (
13
+ <svg
14
+ viewBox="0 0 160 120"
15
+ width={size}
16
+ height={(size * 120) / 160}
17
+ fill="none"
18
+ strokeWidth={1.5}
19
+ strokeLinecap="round"
20
+ strokeLinejoin="round"
21
+ aria-hidden="true"
22
+ focusable="false"
23
+ className={cn('shrink-0', className)}
24
+ >
25
+ <ellipse cx="80" cy="104" rx="28" ry="5" className="fill-muted" />
26
+
27
+ {/* empty slots, behind the tile in front */}
28
+ <rect
29
+ x="36"
30
+ y="28"
31
+ width="40"
32
+ height="30"
33
+ rx="3"
34
+ className="stroke-border"
35
+ strokeDasharray="3 4"
36
+ transform="rotate(-6 56 43)"
37
+ />
38
+ <rect
39
+ x="94"
40
+ y="30"
41
+ width="34"
42
+ height="26"
43
+ rx="3"
44
+ className="stroke-border"
45
+ strokeDasharray="3 4"
46
+ transform="rotate(5 111 43)"
47
+ />
48
+
49
+ {/* photo tile */}
50
+ <rect
51
+ x="48"
52
+ y="34"
53
+ width="64"
54
+ height="46"
55
+ rx="3"
56
+ className="fill-surface stroke-muted-foreground"
57
+ />
58
+
59
+ {/* sun — the one brand accent */}
60
+ <circle cx="64" cy="48" r="4" className="fill-brand" />
61
+
62
+ {/* mountains */}
63
+ <path d="M52,74 L66,58 L76,68 L86,52 L104,74" className="stroke-muted-foreground" />
64
+ </svg>
65
+ );
66
+ }
67
+
68
+ export { EmptyMediaIllustration };
@@ -0,0 +1,64 @@
1
+ import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
2
+ import { cn } from '@vendure-io/ui/lib/utils';
3
+
4
+ /**
5
+ * Two cable connectors that don't meet, with a dashed gap and a spark where
6
+ * the connection failed. The `ErrorState` default — deliberately neutral, not
7
+ * destructive-tinted; the "this failed" weight comes from the state view's
8
+ * `role="alert"` and copy, not the illustration.
9
+ */
10
+ function ErrorIllustration({ className, size = 160 }: IllustrationProps) {
11
+ return (
12
+ <svg
13
+ viewBox="0 0 160 120"
14
+ width={size}
15
+ height={(size * 120) / 160}
16
+ fill="none"
17
+ strokeWidth={1.5}
18
+ strokeLinecap="round"
19
+ strokeLinejoin="round"
20
+ aria-hidden="true"
21
+ focusable="false"
22
+ className={cn('shrink-0', className)}
23
+ >
24
+ <ellipse cx="80" cy="104" rx="30" ry="5" className="fill-muted" />
25
+
26
+ {/* left plug + trailing cable */}
27
+ <path d="M20,60 Q6,60 6,44" className="stroke-muted-foreground" />
28
+ <rect
29
+ x="20"
30
+ y="50"
31
+ width="36"
32
+ height="20"
33
+ rx="4"
34
+ className="fill-surface stroke-muted-foreground"
35
+ />
36
+ <rect x="54" y="56" width="10" height="3" rx="1.5" className="fill-muted-foreground" />
37
+ <rect x="54" y="63" width="10" height="3" rx="1.5" className="fill-muted-foreground" />
38
+
39
+ {/* right socket + trailing cable */}
40
+ <path d="M140,60 Q154,60 154,44" className="stroke-muted-foreground" />
41
+ <rect
42
+ x="104"
43
+ y="50"
44
+ width="36"
45
+ height="20"
46
+ rx="4"
47
+ className="fill-surface stroke-muted-foreground"
48
+ />
49
+ <rect x="98" y="56" width="8" height="3" rx="1.5" className="fill-background stroke-border" />
50
+ <rect x="98" y="63" width="8" height="3" rx="1.5" className="fill-background stroke-border" />
51
+
52
+ {/* the gap */}
53
+ <line x1="66" y1="60" x2="94" y2="60" className="stroke-border" strokeDasharray="2 5" />
54
+
55
+ {/* spark — the one brand accent */}
56
+ <polygon
57
+ points="80,52 81.5,58.5 88,60 81.5,61.5 80,68 78.5,61.5 72,60 78.5,58.5"
58
+ className="fill-brand"
59
+ />
60
+ </svg>
61
+ );
62
+ }
63
+
64
+ export { ErrorIllustration };
@@ -0,0 +1,55 @@
1
+ import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
2
+ import { cn } from '@vendure-io/ui/lib/utils';
3
+
4
+ /**
5
+ * A rocket lifting off on a dashed motion trail, with a lit porthole and two
6
+ * drifting sparkles. For genuine first-run/onboarding moments — a feature
7
+ * with nothing set up yet, not a filtered or failed view.
8
+ */
9
+ function FirstRunIllustration({ className, size = 160 }: IllustrationProps) {
10
+ return (
11
+ <svg
12
+ viewBox="0 0 160 120"
13
+ width={size}
14
+ height={(size * 120) / 160}
15
+ fill="none"
16
+ strokeWidth={1.5}
17
+ strokeLinecap="round"
18
+ strokeLinejoin="round"
19
+ aria-hidden="true"
20
+ focusable="false"
21
+ className={cn('shrink-0', className)}
22
+ >
23
+ <ellipse cx="80" cy="104" rx="26" ry="5" className="fill-muted" />
24
+
25
+ {/* motion trail */}
26
+ <path d="M70,100 Q66,80 74,60" className="stroke-border" strokeDasharray="3 4" />
27
+ <path d="M90,100 Q94,80 86,60" className="stroke-border" strokeDasharray="3 4" />
28
+
29
+ {/* body */}
30
+ <path
31
+ d="M80,26 C90,36 92,50 90,66 L70,66 C68,50 70,36 80,26 Z"
32
+ className="fill-surface stroke-muted-foreground"
33
+ />
34
+ <polygon points="70,66 60,78 70,72" className="fill-muted-foreground" />
35
+ <polygon points="90,66 100,78 90,72" className="fill-muted-foreground" />
36
+ <path d="M74,66 L80,80 L86,66" className="stroke-border" strokeDasharray="2 3" />
37
+
38
+ {/* porthole — the one brand accent */}
39
+ <circle cx="80" cy="44" r="7" className="fill-brand" />
40
+ <circle cx="77.5" cy="42" r="1.6" className="fill-surface" />
41
+
42
+ {/* drifting sparkles, neutral */}
43
+ <polygon
44
+ points="46,28 47.5,32.5 52,34 47.5,35.5 46,40 44.5,35.5 40,34 44.5,32.5"
45
+ className="fill-muted-foreground"
46
+ />
47
+ <polygon
48
+ points="118,48 119,51 122,52 119,53 118,56 117,53 114,52 117,51"
49
+ className="fill-muted-foreground"
50
+ />
51
+ </svg>
52
+ );
53
+ }
54
+
55
+ export { FirstRunIllustration };
@@ -0,0 +1,9 @@
1
+ // Pure type module for the illustrations set. Kept runtime-free so every
2
+ // illustration file can import it without pulling in unrelated JSX.
3
+
4
+ export interface IllustrationProps {
5
+ /** Extra classes applied to the root `<svg>` (e.g. to resize or reposition). */
6
+ className?: string;
7
+ /** Width in px. Height follows the fixed 160×120 (4:3) aspect ratio. Defaults to 160. */
8
+ size?: number;
9
+ }
@@ -0,0 +1,49 @@
1
+ import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
2
+ import { cn } from '@vendure-io/ui/lib/utils';
3
+
4
+ /**
5
+ * A vertical timeline rail with dashed, hollow nodes and faint dashed row
6
+ * lines beside them — the rail exists but no entries have landed on it yet.
7
+ * For audit logs / history / timeline views with nothing recorded — pass as
8
+ * `illustration` to `EmptyState`. For a generic empty list with no timeline
9
+ * shape, use `EmptyCollectionIllustration` instead.
10
+ */
11
+ function NoActivityIllustration({ className, size = 160 }: IllustrationProps) {
12
+ return (
13
+ <svg
14
+ viewBox="0 0 160 120"
15
+ width={size}
16
+ height={(size * 120) / 160}
17
+ fill="none"
18
+ strokeWidth={1.5}
19
+ strokeLinecap="round"
20
+ strokeLinejoin="round"
21
+ aria-hidden="true"
22
+ focusable="false"
23
+ className={cn('shrink-0', className)}
24
+ >
25
+ <ellipse cx="80" cy="104" rx="28" ry="5" className="fill-muted" />
26
+
27
+ {/* the timeline rail itself — present, just nothing on it */}
28
+ <line x1="50" y1="26" x2="50" y2="88" className="stroke-muted-foreground" />
29
+
30
+ {/* nodes, hollow — no entries recorded at any of them */}
31
+ <circle cx="50" cy="32" r="5" className="stroke-muted-foreground" strokeDasharray="3 4" />
32
+ <circle cx="50" cy="58" r="5" className="stroke-muted-foreground" strokeDasharray="3 4" />
33
+ <circle cx="50" cy="84" r="5" className="stroke-muted-foreground" strokeDasharray="3 4" />
34
+
35
+ {/* newest node — the one brand accent */}
36
+ <circle cx="50" cy="32" r="2" className="fill-brand" />
37
+
38
+ {/* faint row placeholders beside each node, waiting for content */}
39
+ <line x1="64" y1="29" x2="106" y2="29" className="stroke-border" strokeDasharray="2 5" />
40
+ <line x1="64" y1="36" x2="90" y2="36" className="stroke-border" strokeDasharray="2 5" />
41
+ <line x1="64" y1="55" x2="114" y2="55" className="stroke-border" strokeDasharray="2 5" />
42
+ <line x1="64" y1="62" x2="96" y2="62" className="stroke-border" strokeDasharray="2 5" />
43
+ <line x1="64" y1="81" x2="102" y2="81" className="stroke-border" strokeDasharray="2 5" />
44
+ <line x1="64" y1="88" x2="84" y2="88" className="stroke-border" strokeDasharray="2 5" />
45
+ </svg>
46
+ );
47
+ }
48
+
49
+ export { NoActivityIllustration };
@@ -0,0 +1,49 @@
1
+ import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
2
+ import { cn } from '@vendure-io/ui/lib/utils';
3
+
4
+ /**
5
+ * A grounded server box with a dashed arrow trailing upward into empty space
6
+ * — nothing has shipped yet. For an environment that has never been deployed
7
+ * or an empty deployment history, not a genuine product onboarding moment
8
+ * (use `FirstRunIllustration`) or a failed deploy (use `ErrorIllustration`).
9
+ */
10
+ function NoDeploymentsIllustration({ className, size = 160 }: IllustrationProps) {
11
+ return (
12
+ <svg
13
+ viewBox="0 0 160 120"
14
+ width={size}
15
+ height={(size * 120) / 160}
16
+ fill="none"
17
+ strokeWidth={1.5}
18
+ strokeLinecap="round"
19
+ strokeLinejoin="round"
20
+ aria-hidden="true"
21
+ focusable="false"
22
+ className={cn('shrink-0', className)}
23
+ >
24
+ <ellipse cx="80" cy="104" rx="28" ry="5" className="fill-muted" />
25
+
26
+ {/* server box */}
27
+ <rect
28
+ x="58"
29
+ y="64"
30
+ width="44"
31
+ height="28"
32
+ rx="4"
33
+ className="fill-surface stroke-muted-foreground"
34
+ />
35
+
36
+ {/* rack lines */}
37
+ <line x1="64" y1="74" x2="96" y2="74" className="stroke-border" />
38
+ <line x1="64" y1="84" x2="96" y2="84" className="stroke-border" />
39
+
40
+ {/* dashed trail, nothing deployed yet */}
41
+ <path d="M80,64 Q78,46 80,30" className="stroke-border" strokeDasharray="3 4" />
42
+
43
+ {/* arrowhead — the one brand accent */}
44
+ <polygon points="80,20 74,30 86,30" className="fill-brand" />
45
+ </svg>
46
+ );
47
+ }
48
+
49
+ export { NoDeploymentsIllustration };
@@ -0,0 +1,67 @@
1
+ import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
2
+ import { cn } from '@vendure-io/ui/lib/utils';
3
+
4
+ /**
5
+ * A single document with a folded corner and a seal, with dashed "ghost"
6
+ * pages stacked behind it that never got filled in. For licenses, invoices,
7
+ * or certificates that haven't been issued yet. Not for a generic empty list
8
+ * (use `EmptyCollectionIllustration`) or a 404 (use `NotFoundIllustration`).
9
+ */
10
+ function NoDocumentsIllustration({ className, size = 160 }: IllustrationProps) {
11
+ return (
12
+ <svg
13
+ viewBox="0 0 160 120"
14
+ width={size}
15
+ height={(size * 120) / 160}
16
+ fill="none"
17
+ strokeWidth={1.5}
18
+ strokeLinecap="round"
19
+ strokeLinejoin="round"
20
+ aria-hidden="true"
21
+ focusable="false"
22
+ className={cn('shrink-0', className)}
23
+ >
24
+ <ellipse cx="80" cy="104" rx="27" ry="5" className="fill-muted" />
25
+
26
+ {/* ghost pages, never issued */}
27
+ <rect
28
+ x="65"
29
+ y="20"
30
+ width="42"
31
+ height="56"
32
+ rx="2"
33
+ className="stroke-border"
34
+ strokeDasharray="2 5"
35
+ />
36
+ <rect
37
+ x="62"
38
+ y="23"
39
+ width="42"
40
+ height="56"
41
+ rx="2"
42
+ className="stroke-border"
43
+ strokeDasharray="3 4"
44
+ />
45
+
46
+ {/* document, folded corner */}
47
+ <rect
48
+ x="59"
49
+ y="26"
50
+ width="42"
51
+ height="56"
52
+ rx="2"
53
+ className="fill-surface stroke-muted-foreground"
54
+ />
55
+ <polygon points="101,26 101,36 91,26" className="fill-muted stroke-border" />
56
+
57
+ {/* seal ribbon, hanging off the bottom edge */}
58
+ <path d="M75,74 L75,96 L80,90 L85,96 L85,74 Z" className="fill-muted stroke-border" />
59
+
60
+ {/* seal — the one brand accent */}
61
+ <circle cx="80" cy="74" r="8" className="fill-surface stroke-muted-foreground" />
62
+ <circle cx="80" cy="74" r="2.5" className="fill-brand" />
63
+ </svg>
64
+ );
65
+ }
66
+
67
+ export { NoDocumentsIllustration };
@@ -0,0 +1,50 @@
1
+ import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
2
+ import { cn } from '@vendure-io/ui/lib/utils';
3
+
4
+ /**
5
+ * A single key resting on the ground, its bow-hole the only spark of color,
6
+ * beneath a dashed keyring loop with nothing hung on it yet. For empty states
7
+ * before any API key, access token, or registry token has been created —
8
+ * pair with `EmptyState`. Not for a permission/authorization failure (use
9
+ * `AccessDeniedIllustration`).
10
+ */
11
+ function NoKeysIllustration({ className, size = 160 }: IllustrationProps) {
12
+ return (
13
+ <svg
14
+ viewBox="0 0 160 120"
15
+ width={size}
16
+ height={(size * 120) / 160}
17
+ fill="none"
18
+ strokeWidth={1.5}
19
+ strokeLinecap="round"
20
+ strokeLinejoin="round"
21
+ aria-hidden="true"
22
+ focusable="false"
23
+ className={cn('shrink-0', className)}
24
+ >
25
+ <ellipse cx="80" cy="104" rx="30" ry="5" className="fill-muted" />
26
+
27
+ {/* keyring, empty — nothing hung on it yet */}
28
+ <circle cx="80" cy="40" r="18" className="stroke-border" strokeDasharray="3 4" />
29
+ <path d="M80,58 L80,72" className="stroke-border" strokeDasharray="2 4" />
30
+
31
+ {/* key, resting: bow + shaft + teeth */}
32
+ <circle cx="56" cy="88" r="13" className="fill-surface stroke-muted-foreground" />
33
+ <rect
34
+ x="67"
35
+ y="84"
36
+ width="50"
37
+ height="8"
38
+ rx="1"
39
+ className="fill-surface stroke-muted-foreground"
40
+ />
41
+ <rect x="102" y="92" width="5" height="6" className="fill-surface stroke-muted-foreground" />
42
+ <rect x="111" y="92" width="5" height="10" className="fill-surface stroke-muted-foreground" />
43
+
44
+ {/* bow hole — the one brand accent */}
45
+ <circle cx="56" cy="88" r="4" className="fill-brand" />
46
+ </svg>
47
+ );
48
+ }
49
+
50
+ export { NoKeysIllustration };
@@ -0,0 +1,53 @@
1
+ import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
2
+ import { cn } from '@vendure-io/ui/lib/utils';
3
+
4
+ /**
5
+ * A terminal window with a title bar and a few dashed, empty log lines below
6
+ * a blinking prompt caret waiting for output. For an empty log stream or
7
+ * console with nothing captured yet — pass as `illustration` to `EmptyState`.
8
+ * Not for a generic error (use `ErrorIllustration`).
9
+ */
10
+ function NoLogsIllustration({ className, size = 160 }: IllustrationProps) {
11
+ return (
12
+ <svg
13
+ viewBox="0 0 160 120"
14
+ width={size}
15
+ height={(size * 120) / 160}
16
+ fill="none"
17
+ strokeWidth={1.5}
18
+ strokeLinecap="round"
19
+ strokeLinejoin="round"
20
+ aria-hidden="true"
21
+ focusable="false"
22
+ className={cn('shrink-0', className)}
23
+ >
24
+ <ellipse cx="80" cy="104" rx="30" ry="5" className="fill-muted" />
25
+
26
+ {/* terminal window */}
27
+ <rect
28
+ x="26"
29
+ y="22"
30
+ width="108"
31
+ height="68"
32
+ rx="4"
33
+ className="fill-surface stroke-muted-foreground"
34
+ />
35
+
36
+ {/* title bar, with window dots */}
37
+ <line x1="26" y1="36" x2="134" y2="36" className="stroke-border" />
38
+ <circle cx="34" cy="29" r="2" className="fill-muted-foreground" />
39
+ <circle cx="42" cy="29" r="2" className="fill-muted-foreground" />
40
+ <circle cx="50" cy="29" r="2" className="fill-muted-foreground" />
41
+
42
+ {/* empty log lines — nothing captured yet */}
43
+ <line x1="38" y1="50" x2="96" y2="50" className="stroke-border" strokeDasharray="3 4" />
44
+ <line x1="38" y1="60" x2="112" y2="60" className="stroke-border" strokeDasharray="3 4" />
45
+ <line x1="38" y1="70" x2="80" y2="70" className="stroke-border" strokeDasharray="3 4" />
46
+
47
+ {/* prompt caret, blinking on an empty line — the one brand accent */}
48
+ <rect x="38" y="78" width="8" height="10" rx="1" className="fill-brand" />
49
+ </svg>
50
+ );
51
+ }
52
+
53
+ export { NoLogsIllustration };
@@ -0,0 +1,56 @@
1
+ import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
2
+ import { cn } from '@vendure-io/ui/lib/utils';
3
+
4
+ /**
5
+ * Two solid avatar chips (head + shoulders) beside one dashed, empty avatar
6
+ * slot topped with a "+" badge — an open seat waiting to be filled. For a
7
+ * team/members list that's empty or awaiting invites — pass as `illustration`
8
+ * to `EmptyState` alongside an "Invite a teammate" action. Not for a
9
+ * customer/people search that came up empty (use `NoResultsIllustration`).
10
+ */
11
+ function NoMembersIllustration({ className, size = 160 }: IllustrationProps) {
12
+ return (
13
+ <svg
14
+ viewBox="0 0 160 120"
15
+ width={size}
16
+ height={(size * 120) / 160}
17
+ fill="none"
18
+ strokeWidth={1.5}
19
+ strokeLinecap="round"
20
+ strokeLinejoin="round"
21
+ aria-hidden="true"
22
+ focusable="false"
23
+ className={cn('shrink-0', className)}
24
+ >
25
+ <ellipse cx="80" cy="104" rx="30" ry="5" className="fill-muted" />
26
+
27
+ {/* two team members, already seated */}
28
+ <circle cx="42" cy="46" r="9" className="fill-surface stroke-muted-foreground" />
29
+ <path
30
+ d="M29,82 L29,67 A13,13 0 0,1 55,67 L55,82 Z"
31
+ className="fill-surface stroke-muted-foreground"
32
+ />
33
+ <circle cx="74" cy="46" r="9" className="fill-surface stroke-muted-foreground" />
34
+ <path
35
+ d="M61,82 L61,67 A13,13 0 0,1 87,67 L87,82 Z"
36
+ className="fill-surface stroke-muted-foreground"
37
+ />
38
+
39
+ {/* open seat, dashed and empty */}
40
+ <circle cx="112" cy="46" r="9" className="stroke-muted-foreground" strokeDasharray="3 4" />
41
+ <path
42
+ d="M99,82 L99,67 A13,13 0 0,1 125,67 L125,82 Z"
43
+ className="stroke-muted-foreground"
44
+ strokeDasharray="3 4"
45
+ />
46
+
47
+ {/* invite badge — the one brand accent */}
48
+ <polygon
49
+ points="122,32 126,32 126,36 130,36 130,40 126,40 126,44 122,44 122,40 118,40 118,36 122,36"
50
+ className="fill-brand"
51
+ />
52
+ </svg>
53
+ );
54
+ }
55
+
56
+ export { NoMembersIllustration };