@viliha/vui-ui 1.1.8 → 1.3.0

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 (138) hide show
  1. package/AGENT.md +79 -9
  2. package/README.md +60 -0
  3. package/bin/vui.mjs +211 -0
  4. package/package.json +10 -2
  5. package/src/record-view.tsx +59 -17
  6. package/template/.env.example +20 -0
  7. package/template/app/(app)/branches/branches-table.tsx +69 -0
  8. package/template/app/(app)/branches/page.tsx +13 -0
  9. package/template/app/(app)/businesses/businesses-table.tsx +39 -0
  10. package/template/app/(app)/businesses/page.tsx +13 -0
  11. package/template/app/(app)/calendar/page.tsx +725 -0
  12. package/template/app/(app)/charts/charts-content.tsx +190 -0
  13. package/template/app/(app)/charts/layout.tsx +8 -0
  14. package/template/app/(app)/charts/page.tsx +44 -0
  15. package/template/app/(app)/chat/layout.tsx +14 -0
  16. package/template/app/(app)/chat/page.tsx +311 -0
  17. package/template/app/(app)/components/layout.tsx +8 -0
  18. package/template/app/(app)/components/page.tsx +464 -0
  19. package/template/app/(app)/crm/companies/companies-table.tsx +56 -0
  20. package/template/app/(app)/crm/companies/page.tsx +13 -0
  21. package/template/app/(app)/crm/opportunities/opportunities-board.tsx +359 -0
  22. package/template/app/(app)/crm/opportunities/page.tsx +13 -0
  23. package/template/app/(app)/crm/people/page.tsx +13 -0
  24. package/template/app/(app)/crm/people/people-table.tsx +50 -0
  25. package/template/app/(app)/dashboard/layout.tsx +8 -0
  26. package/template/app/(app)/dashboard/page.tsx +239 -0
  27. package/template/app/(app)/departments/departments-table.tsx +55 -0
  28. package/template/app/(app)/departments/page.tsx +13 -0
  29. package/template/app/(app)/employees/employees-table.tsx +64 -0
  30. package/template/app/(app)/employees/page.tsx +13 -0
  31. package/template/app/(app)/forms/layout.tsx +8 -0
  32. package/template/app/(app)/forms/page.tsx +388 -0
  33. package/template/app/(app)/layout.tsx +74 -0
  34. package/template/app/(app)/markets/markets-table.tsx +76 -0
  35. package/template/app/(app)/markets/page.tsx +13 -0
  36. package/template/app/(app)/organizations/edit/page.tsx +72 -0
  37. package/template/app/(app)/organizations/new/page.tsx +46 -0
  38. package/template/app/(app)/organizations/organizations-config.tsx +97 -0
  39. package/template/app/(app)/organizations/organizations-table.tsx +42 -0
  40. package/template/app/(app)/organizations/page.tsx +13 -0
  41. package/template/app/(app)/settings/layout.tsx +8 -0
  42. package/template/app/(app)/settings/page.tsx +255 -0
  43. package/template/app/(app)/steps/page.tsx +263 -0
  44. package/template/app/(app)/support/layout.tsx +14 -0
  45. package/template/app/(app)/support/page.tsx +345 -0
  46. package/template/app/(app)/system/cities/cities-table.tsx +34 -0
  47. package/template/app/(app)/system/cities/page.tsx +13 -0
  48. package/template/app/(app)/system/countries/countries-table.tsx +34 -0
  49. package/template/app/(app)/system/countries/page.tsx +13 -0
  50. package/template/app/(app)/system/currencies/currencies-table.tsx +34 -0
  51. package/template/app/(app)/system/currencies/page.tsx +13 -0
  52. package/template/app/(app)/system/languages/languages-table.tsx +32 -0
  53. package/template/app/(app)/system/languages/page.tsx +13 -0
  54. package/template/app/(app)/system/regions/page.tsx +13 -0
  55. package/template/app/(app)/system/regions/regions-table.tsx +32 -0
  56. package/template/app/(app)/users/page.tsx +13 -0
  57. package/template/app/(app)/users/users-table.tsx +97 -0
  58. package/template/app/_components/app-sidebar.tsx +565 -0
  59. package/template/app/_components/auth.tsx +184 -0
  60. package/template/app/_components/breadcrumbs.tsx +26 -0
  61. package/template/app/_components/global-search.tsx +209 -0
  62. package/template/app/_components/logo.tsx +49 -0
  63. package/template/app/_components/nav-config.ts +138 -0
  64. package/template/app/_components/open-tabs.tsx +530 -0
  65. package/template/app/_components/quick-actions.tsx +140 -0
  66. package/template/app/_components/route-meta.ts +137 -0
  67. package/template/app/_components/set-page-title.tsx +15 -0
  68. package/template/app/_components/showcase.tsx +29 -0
  69. package/template/app/_components/stat-card.tsx +56 -0
  70. package/template/app/_components/theme-toggle.tsx +46 -0
  71. package/template/app/_components/top-bar.tsx +109 -0
  72. package/template/app/_components/user-menu.tsx +109 -0
  73. package/template/app/_components/wordmark.tsx +45 -0
  74. package/template/app/apple-icon.png +0 -0
  75. package/template/app/auth/forgot-password/page.tsx +102 -0
  76. package/template/app/auth/layout.tsx +43 -0
  77. package/template/app/auth/page.tsx +13 -0
  78. package/template/app/auth/reset-password/page.tsx +108 -0
  79. package/template/app/auth/signin/page.tsx +238 -0
  80. package/template/app/auth/signup/page.tsx +159 -0
  81. package/template/app/auth/verify/page.tsx +86 -0
  82. package/template/app/error.tsx +56 -0
  83. package/template/app/globals.css +6 -0
  84. package/template/app/icon.png +0 -0
  85. package/template/app/icon.svg +4 -0
  86. package/template/app/layout.tsx +103 -0
  87. package/template/app/not-found.tsx +29 -0
  88. package/template/app/onboarding/layout.tsx +31 -0
  89. package/template/app/onboarding/page.tsx +399 -0
  90. package/template/app/page.tsx +13 -0
  91. package/template/app/register-business/layout.tsx +30 -0
  92. package/template/app/register-business/page.tsx +234 -0
  93. package/template/components/ui/accordion.tsx +66 -0
  94. package/template/components/ui/alert-dialog.tsx +196 -0
  95. package/template/components/ui/alert.tsx +66 -0
  96. package/template/components/ui/aspect-ratio.tsx +11 -0
  97. package/template/components/ui/avatar.tsx +109 -0
  98. package/template/components/ui/badge.tsx +48 -0
  99. package/template/components/ui/breadcrumb.tsx +109 -0
  100. package/template/components/ui/button.tsx +64 -0
  101. package/template/components/ui/calendar.tsx +220 -0
  102. package/template/components/ui/card.tsx +92 -0
  103. package/template/components/ui/checkbox.tsx +32 -0
  104. package/template/components/ui/collapsible.tsx +33 -0
  105. package/template/components/ui/command.tsx +184 -0
  106. package/template/components/ui/dialog.tsx +158 -0
  107. package/template/components/ui/dropdown-menu.tsx +257 -0
  108. package/template/components/ui/form.tsx +167 -0
  109. package/template/components/ui/hover-card.tsx +44 -0
  110. package/template/components/ui/input-otp.tsx +77 -0
  111. package/template/components/ui/input.tsx +21 -0
  112. package/template/components/ui/label.tsx +24 -0
  113. package/template/components/ui/popover.tsx +89 -0
  114. package/template/components/ui/progress.tsx +31 -0
  115. package/template/components/ui/radio-group.tsx +45 -0
  116. package/template/components/ui/scroll-area.tsx +58 -0
  117. package/template/components/ui/select.tsx +190 -0
  118. package/template/components/ui/separator.tsx +28 -0
  119. package/template/components/ui/sheet.tsx +143 -0
  120. package/template/components/ui/skeleton.tsx +13 -0
  121. package/template/components/ui/slider.tsx +63 -0
  122. package/template/components/ui/sonner.tsx +40 -0
  123. package/template/components/ui/switch.tsx +35 -0
  124. package/template/components/ui/table.tsx +116 -0
  125. package/template/components/ui/tabs.tsx +91 -0
  126. package/template/components/ui/textarea.tsx +18 -0
  127. package/template/components/ui/toggle-group.tsx +83 -0
  128. package/template/components/ui/toggle.tsx +47 -0
  129. package/template/components/ui/tooltip.tsx +57 -0
  130. package/template/lib/auth-demo.ts +94 -0
  131. package/template/lib/crm-data.ts +80 -0
  132. package/template/lib/demo-data.ts +267 -0
  133. package/template/lib/mock-data.ts +169 -0
  134. package/template/lib/org-store.ts +50 -0
  135. package/template/lib/seo.ts +188 -0
  136. package/template/lib/utils.ts +3 -0
  137. package/template/next.config.mjs +13 -0
  138. package/template/postcss.config.mjs +7 -0
@@ -0,0 +1,34 @@
1
+ "use client";
2
+
3
+ import {
4
+ BookmarkIcon as Flag,
5
+ CodeIcon as Hash,
6
+ GlobeIcon as Globe,
7
+ } from "@radix-ui/react-icons";
8
+
9
+ import { RecordView, type RecordField } from "@viliha/vui-ui/record-view";
10
+ import { countries, type Country } from "@/lib/mock-data";
11
+
12
+ const fields: RecordField<Country>[] = [
13
+ { key: "name", label: "Name", editable: true, required: true, group: "General", hideInTable: true },
14
+ { key: "code", label: "Code", icon: Hash, editable: true, group: "General" },
15
+ { key: "region", label: "Region", icon: Globe, editable: true, width: 220, group: "General" },
16
+ ];
17
+
18
+ export function CountriesTable() {
19
+ return (
20
+ <RecordView
21
+ title="Countries"
22
+ singular="Country"
23
+ icon={Flag}
24
+ fields={fields}
25
+ initialData={countries}
26
+ getPrimary={(row) => ({
27
+ title: row.name,
28
+ subtitle: row.code,
29
+ initials: row.code.slice(0, 2).toUpperCase(),
30
+ })}
31
+ makeEmptyRow={() => ({ id: Date.now(), name: "", code: "", region: "" })}
32
+ />
33
+ );
34
+ }
@@ -0,0 +1,13 @@
1
+ import { pageMeta } from "@/lib/seo";
2
+
3
+ import { CountriesTable } from "./countries-table";
4
+
5
+ export const metadata = pageMeta("/system/countries");
6
+
7
+ export default function CountriesPage() {
8
+ return (
9
+ <main className="h-full">
10
+ <CountriesTable />
11
+ </main>
12
+ );
13
+ }
@@ -0,0 +1,34 @@
1
+ "use client";
2
+
3
+ import {
4
+ CodeIcon as Hash,
5
+ TokensIcon as Banknote,
6
+ TokensIcon as Coins,
7
+ } from "@radix-ui/react-icons";
8
+
9
+ import { RecordView, type RecordField } from "@viliha/vui-ui/record-view";
10
+ import { currencies, type Currency } from "@/lib/mock-data";
11
+
12
+ const fields: RecordField<Currency>[] = [
13
+ { key: "name", label: "Name", editable: true, required: true, group: "General", hideInTable: true },
14
+ { key: "code", label: "Code", icon: Hash, editable: true, group: "General" },
15
+ { key: "symbol", label: "Symbol", icon: Banknote, editable: true, group: "General" },
16
+ ];
17
+
18
+ export function CurrenciesTable() {
19
+ return (
20
+ <RecordView
21
+ title="Currencies"
22
+ singular="Currency"
23
+ icon={Coins}
24
+ fields={fields}
25
+ initialData={currencies}
26
+ getPrimary={(row) => ({
27
+ title: row.name,
28
+ subtitle: row.code,
29
+ initials: row.code.slice(0, 2).toUpperCase(),
30
+ })}
31
+ makeEmptyRow={() => ({ id: Date.now(), name: "", code: "", symbol: "" })}
32
+ />
33
+ );
34
+ }
@@ -0,0 +1,13 @@
1
+ import { pageMeta } from "@/lib/seo";
2
+
3
+ import { CurrenciesTable } from "./currencies-table";
4
+
5
+ export const metadata = pageMeta("/system/currencies");
6
+
7
+ export default function CurrenciesPage() {
8
+ return (
9
+ <main className="h-full">
10
+ <CurrenciesTable />
11
+ </main>
12
+ );
13
+ }
@@ -0,0 +1,32 @@
1
+ "use client";
2
+
3
+ import {
4
+ CodeIcon as Hash,
5
+ TextIcon as LanguagesIcon,
6
+ } from "@radix-ui/react-icons";
7
+
8
+ import { RecordView, type RecordField } from "@viliha/vui-ui/record-view";
9
+ import { languages, type Language } from "@/lib/mock-data";
10
+
11
+ const fields: RecordField<Language>[] = [
12
+ { key: "name", label: "Name", editable: true, required: true, group: "General", hideInTable: true },
13
+ { key: "code", label: "Code", icon: Hash, editable: true, group: "General" },
14
+ ];
15
+
16
+ export function LanguagesTable() {
17
+ return (
18
+ <RecordView
19
+ title="Languages"
20
+ singular="Language"
21
+ icon={LanguagesIcon}
22
+ fields={fields}
23
+ initialData={languages}
24
+ getPrimary={(row) => ({
25
+ title: row.name,
26
+ subtitle: row.code,
27
+ initials: row.code.slice(0, 2).toUpperCase(),
28
+ })}
29
+ makeEmptyRow={() => ({ id: Date.now(), name: "", code: "" })}
30
+ />
31
+ );
32
+ }
@@ -0,0 +1,13 @@
1
+ import { pageMeta } from "@/lib/seo";
2
+
3
+ import { LanguagesTable } from "./languages-table";
4
+
5
+ export const metadata = pageMeta("/system/languages");
6
+
7
+ export default function LanguagesPage() {
8
+ return (
9
+ <main className="h-full">
10
+ <LanguagesTable />
11
+ </main>
12
+ );
13
+ }
@@ -0,0 +1,13 @@
1
+ import { pageMeta } from "@/lib/seo";
2
+
3
+ import { RegionsTable } from "./regions-table";
4
+
5
+ export const metadata = pageMeta("/system/regions");
6
+
7
+ export default function RegionsPage() {
8
+ return (
9
+ <main className="h-full">
10
+ <RegionsTable />
11
+ </main>
12
+ );
13
+ }
@@ -0,0 +1,32 @@
1
+ "use client";
2
+
3
+ import {
4
+ CodeIcon as Hash,
5
+ GlobeIcon as Globe,
6
+ } from "@radix-ui/react-icons";
7
+
8
+ import { RecordView, type RecordField } from "@viliha/vui-ui/record-view";
9
+ import { regions, type Region } from "@/lib/mock-data";
10
+
11
+ const fields: RecordField<Region>[] = [
12
+ { key: "name", label: "Name", editable: true, required: true, group: "General", hideInTable: true },
13
+ { key: "code", label: "Code", icon: Hash, editable: true, group: "General" },
14
+ ];
15
+
16
+ export function RegionsTable() {
17
+ return (
18
+ <RecordView
19
+ title="Regions"
20
+ singular="Region"
21
+ icon={Globe}
22
+ fields={fields}
23
+ initialData={regions}
24
+ getPrimary={(row) => ({
25
+ title: row.name,
26
+ subtitle: row.code,
27
+ initials: row.code.slice(0, 2).toUpperCase(),
28
+ })}
29
+ makeEmptyRow={() => ({ id: Date.now(), name: "", code: "" })}
30
+ />
31
+ );
32
+ }
@@ -0,0 +1,13 @@
1
+ import { pageMeta } from "@/lib/seo";
2
+
3
+ import { UsersTable } from "./users-table";
4
+
5
+ export const metadata = pageMeta("/users");
6
+
7
+ export default function UsersPage() {
8
+ return (
9
+ <main className="h-full">
10
+ <UsersTable />
11
+ </main>
12
+ );
13
+ }
@@ -0,0 +1,97 @@
1
+ "use client";
2
+
3
+ import {
4
+ CardStackIcon as CreditCard,
5
+ CodeIcon as Hash,
6
+ DotFilledIcon as CircleDot,
7
+ EnvelopeClosedIcon as Mail,
8
+ TokensIcon as Banknote,
9
+ } from "@radix-ui/react-icons";
10
+
11
+ import { Badge } from "@viliha/vui-ui/badge";
12
+ import { RecordView, type RecordField } from "@viliha/vui-ui/record-view";
13
+
14
+ type Payment = {
15
+ id: string;
16
+ amount: number;
17
+ status: "pending" | "processing" | "success" | "failed";
18
+ email: string;
19
+ };
20
+
21
+ const data: Payment[] = [
22
+ { id: "p_001", amount: 199, status: "success", email: "ava@example.com" },
23
+ { id: "p_002", amount: 49, status: "pending", email: "haruto@example.com" },
24
+ { id: "p_003", amount: 899, status: "processing", email: "lena@example.com" },
25
+ { id: "p_004", amount: 1299, status: "success", email: "chidi@example.com" },
26
+ { id: "p_005", amount: 12, status: "failed", email: "mia@example.com" },
27
+ ];
28
+
29
+ const statusVariant: Record<
30
+ Payment["status"],
31
+ "success" | "warning" | "secondary" | "destructive"
32
+ > = {
33
+ success: "success",
34
+ processing: "secondary",
35
+ pending: "warning",
36
+ failed: "destructive",
37
+ };
38
+
39
+ const fields: RecordField<Payment>[] = [
40
+ { key: "email", label: "Email", icon: Mail, editable: true, required: true, copyable: true, width: 240, group: "General", hideInTable: true },
41
+ {
42
+ key: "id",
43
+ label: "Payment ID",
44
+ icon: Hash,
45
+ group: "General",
46
+ render: (row) => <span className="font-mono">{row.id}</span>,
47
+ },
48
+ {
49
+ key: "status",
50
+ label: "Status",
51
+ icon: CircleDot,
52
+ group: "General",
53
+ render: (row) => (
54
+ <Badge variant={statusVariant[row.status]} className="capitalize">
55
+ {row.status}
56
+ </Badge>
57
+ ),
58
+ },
59
+ {
60
+ key: "amount",
61
+ label: "Amount",
62
+ icon: Banknote,
63
+ align: "right",
64
+ group: "System",
65
+ render: (row) => (
66
+ <span className="tabular-nums">
67
+ {new Intl.NumberFormat("en-US", {
68
+ style: "currency",
69
+ currency: "USD",
70
+ }).format(row.amount)}
71
+ </span>
72
+ ),
73
+ },
74
+ ];
75
+
76
+ export function UsersTable() {
77
+ return (
78
+ <RecordView
79
+ title="Payments"
80
+ singular="Payment"
81
+ icon={CreditCard}
82
+ fields={fields}
83
+ initialData={data}
84
+ getPrimary={(row) => ({
85
+ title: row.email,
86
+ subtitle: row.id,
87
+ initials: row.email.slice(0, 2).toUpperCase(),
88
+ })}
89
+ makeEmptyRow={(): Payment => ({
90
+ id: `p_${Date.now()}`,
91
+ amount: 0,
92
+ status: "pending",
93
+ email: "",
94
+ })}
95
+ />
96
+ );
97
+ }