create-blitzpack 0.1.0 → 0.1.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 (259) hide show
  1. package/dist/index.js +35 -77
  2. package/package.json +5 -6
  3. package/template/.dockerignore +0 -59
  4. package/template/.github/workflows/ci.yml +0 -157
  5. package/template/.husky/pre-commit +0 -1
  6. package/template/.husky/pre-push +0 -1
  7. package/template/.lintstagedrc.cjs +0 -4
  8. package/template/.nvmrc +0 -1
  9. package/template/.prettierrc +0 -9
  10. package/template/.vscode/settings.json +0 -13
  11. package/template/CLAUDE.md +0 -175
  12. package/template/CONTRIBUTING.md +0 -32
  13. package/template/Dockerfile +0 -90
  14. package/template/GETTING_STARTED.md +0 -35
  15. package/template/LICENSE +0 -21
  16. package/template/README.md +0 -116
  17. package/template/apps/api/.dockerignore +0 -51
  18. package/template/apps/api/.env.local.example +0 -62
  19. package/template/apps/api/emails/account-deleted-email.tsx +0 -69
  20. package/template/apps/api/emails/components/email-layout.tsx +0 -154
  21. package/template/apps/api/emails/config.ts +0 -22
  22. package/template/apps/api/emails/password-changed-email.tsx +0 -88
  23. package/template/apps/api/emails/password-reset-email.tsx +0 -86
  24. package/template/apps/api/emails/verification-email.tsx +0 -85
  25. package/template/apps/api/emails/welcome-email.tsx +0 -70
  26. package/template/apps/api/package.json +0 -84
  27. package/template/apps/api/prisma/migrations/20251012111439_init/migration.sql +0 -13
  28. package/template/apps/api/prisma/migrations/20251018162629_add_better_auth_fields/migration.sql +0 -67
  29. package/template/apps/api/prisma/migrations/20251019142208_add_user_role_enum/migration.sql +0 -5
  30. package/template/apps/api/prisma/migrations/20251019182151_user_auth/migration.sql +0 -7
  31. package/template/apps/api/prisma/migrations/20251019211416_faster_session_lookup/migration.sql +0 -2
  32. package/template/apps/api/prisma/migrations/20251119124337_add_upload_model/migration.sql +0 -26
  33. package/template/apps/api/prisma/migrations/20251120071241_add_scope_to_account/migration.sql +0 -2
  34. package/template/apps/api/prisma/migrations/20251120072608_add_oauth_token_expiration_fields/migration.sql +0 -10
  35. package/template/apps/api/prisma/migrations/20251120144705_add_audit_logs/migration.sql +0 -29
  36. package/template/apps/api/prisma/migrations/20251127123614_remove_impersonated_by/migration.sql +0 -8
  37. package/template/apps/api/prisma/migrations/20251127125630_remove_audit_logs/migration.sql +0 -11
  38. package/template/apps/api/prisma/migrations/migration_lock.toml +0 -3
  39. package/template/apps/api/prisma/schema.prisma +0 -116
  40. package/template/apps/api/prisma/seed.ts +0 -159
  41. package/template/apps/api/prisma.config.ts +0 -14
  42. package/template/apps/api/src/app.ts +0 -377
  43. package/template/apps/api/src/common/logger.service.ts +0 -227
  44. package/template/apps/api/src/config/env.ts +0 -60
  45. package/template/apps/api/src/config/rate-limit.ts +0 -29
  46. package/template/apps/api/src/hooks/auth.ts +0 -122
  47. package/template/apps/api/src/plugins/auth.ts +0 -198
  48. package/template/apps/api/src/plugins/database.ts +0 -45
  49. package/template/apps/api/src/plugins/logger.ts +0 -33
  50. package/template/apps/api/src/plugins/multipart.ts +0 -16
  51. package/template/apps/api/src/plugins/scalar.ts +0 -20
  52. package/template/apps/api/src/plugins/schedule.ts +0 -52
  53. package/template/apps/api/src/plugins/services.ts +0 -66
  54. package/template/apps/api/src/plugins/swagger.ts +0 -56
  55. package/template/apps/api/src/routes/accounts.ts +0 -91
  56. package/template/apps/api/src/routes/admin-sessions.ts +0 -92
  57. package/template/apps/api/src/routes/metrics.ts +0 -71
  58. package/template/apps/api/src/routes/password.ts +0 -46
  59. package/template/apps/api/src/routes/sessions.ts +0 -53
  60. package/template/apps/api/src/routes/stats.ts +0 -38
  61. package/template/apps/api/src/routes/uploads-serve.ts +0 -27
  62. package/template/apps/api/src/routes/uploads.ts +0 -154
  63. package/template/apps/api/src/routes/users.ts +0 -114
  64. package/template/apps/api/src/routes/verification.ts +0 -90
  65. package/template/apps/api/src/server.ts +0 -34
  66. package/template/apps/api/src/services/accounts.service.ts +0 -125
  67. package/template/apps/api/src/services/authorization.service.ts +0 -162
  68. package/template/apps/api/src/services/email.service.ts +0 -170
  69. package/template/apps/api/src/services/file-storage.service.ts +0 -267
  70. package/template/apps/api/src/services/metrics.service.ts +0 -175
  71. package/template/apps/api/src/services/password.service.ts +0 -56
  72. package/template/apps/api/src/services/sessions.service.spec.ts +0 -134
  73. package/template/apps/api/src/services/sessions.service.ts +0 -276
  74. package/template/apps/api/src/services/stats.service.ts +0 -273
  75. package/template/apps/api/src/services/uploads.service.ts +0 -163
  76. package/template/apps/api/src/services/users.service.spec.ts +0 -249
  77. package/template/apps/api/src/services/users.service.ts +0 -198
  78. package/template/apps/api/src/utils/file-validation.ts +0 -108
  79. package/template/apps/api/start.sh +0 -33
  80. package/template/apps/api/test/helpers/fastify-app.ts +0 -24
  81. package/template/apps/api/test/helpers/mock-authorization.ts +0 -16
  82. package/template/apps/api/test/helpers/mock-logger.ts +0 -28
  83. package/template/apps/api/test/helpers/mock-prisma.ts +0 -30
  84. package/template/apps/api/test/helpers/test-db.ts +0 -125
  85. package/template/apps/api/test/integration/auth-flow.integration.spec.ts +0 -449
  86. package/template/apps/api/test/integration/password.integration.spec.ts +0 -427
  87. package/template/apps/api/test/integration/rate-limit.integration.spec.ts +0 -51
  88. package/template/apps/api/test/integration/sessions.integration.spec.ts +0 -445
  89. package/template/apps/api/test/integration/users.integration.spec.ts +0 -211
  90. package/template/apps/api/test/setup.ts +0 -31
  91. package/template/apps/api/tsconfig.json +0 -26
  92. package/template/apps/api/vitest.config.ts +0 -35
  93. package/template/apps/web/.env.local.example +0 -11
  94. package/template/apps/web/components.json +0 -24
  95. package/template/apps/web/next.config.ts +0 -22
  96. package/template/apps/web/package.json +0 -56
  97. package/template/apps/web/postcss.config.js +0 -5
  98. package/template/apps/web/public/apple-icon.png +0 -0
  99. package/template/apps/web/public/icon.png +0 -0
  100. package/template/apps/web/public/robots.txt +0 -3
  101. package/template/apps/web/src/app/(admin)/admin/layout.tsx +0 -222
  102. package/template/apps/web/src/app/(admin)/admin/page.tsx +0 -157
  103. package/template/apps/web/src/app/(admin)/admin/sessions/page.tsx +0 -18
  104. package/template/apps/web/src/app/(admin)/admin/users/page.tsx +0 -20
  105. package/template/apps/web/src/app/(auth)/forgot-password/page.tsx +0 -177
  106. package/template/apps/web/src/app/(auth)/login/page.tsx +0 -159
  107. package/template/apps/web/src/app/(auth)/reset-password/page.tsx +0 -245
  108. package/template/apps/web/src/app/(auth)/signup/page.tsx +0 -153
  109. package/template/apps/web/src/app/dashboard/change-password/page.tsx +0 -255
  110. package/template/apps/web/src/app/dashboard/page.tsx +0 -296
  111. package/template/apps/web/src/app/error.tsx +0 -32
  112. package/template/apps/web/src/app/examples/file-upload/page.tsx +0 -200
  113. package/template/apps/web/src/app/favicon.ico +0 -0
  114. package/template/apps/web/src/app/global-error.tsx +0 -96
  115. package/template/apps/web/src/app/globals.css +0 -22
  116. package/template/apps/web/src/app/icon.png +0 -0
  117. package/template/apps/web/src/app/layout.tsx +0 -34
  118. package/template/apps/web/src/app/not-found.tsx +0 -28
  119. package/template/apps/web/src/app/page.tsx +0 -192
  120. package/template/apps/web/src/components/admin/activity-feed.tsx +0 -101
  121. package/template/apps/web/src/components/admin/charts/auth-breakdown-chart.tsx +0 -114
  122. package/template/apps/web/src/components/admin/charts/chart-tooltip.tsx +0 -124
  123. package/template/apps/web/src/components/admin/charts/realtime-metrics-chart.tsx +0 -511
  124. package/template/apps/web/src/components/admin/charts/role-distribution-chart.tsx +0 -102
  125. package/template/apps/web/src/components/admin/charts/session-activity-chart.tsx +0 -90
  126. package/template/apps/web/src/components/admin/charts/user-growth-chart.tsx +0 -108
  127. package/template/apps/web/src/components/admin/health-indicator.tsx +0 -175
  128. package/template/apps/web/src/components/admin/refresh-control.tsx +0 -90
  129. package/template/apps/web/src/components/admin/session-revoke-all-dialog.tsx +0 -79
  130. package/template/apps/web/src/components/admin/session-revoke-dialog.tsx +0 -74
  131. package/template/apps/web/src/components/admin/sessions-management-table.tsx +0 -372
  132. package/template/apps/web/src/components/admin/stat-card.tsx +0 -137
  133. package/template/apps/web/src/components/admin/user-create-dialog.tsx +0 -152
  134. package/template/apps/web/src/components/admin/user-delete-dialog.tsx +0 -73
  135. package/template/apps/web/src/components/admin/user-edit-dialog.tsx +0 -170
  136. package/template/apps/web/src/components/admin/users-management-table.tsx +0 -285
  137. package/template/apps/web/src/components/auth/email-verification-banner.tsx +0 -85
  138. package/template/apps/web/src/components/auth/github-button.tsx +0 -40
  139. package/template/apps/web/src/components/auth/google-button.tsx +0 -54
  140. package/template/apps/web/src/components/auth/protected-route.tsx +0 -66
  141. package/template/apps/web/src/components/auth/redirect-if-authenticated.tsx +0 -31
  142. package/template/apps/web/src/components/auth/with-auth.tsx +0 -30
  143. package/template/apps/web/src/components/error/error-card.tsx +0 -47
  144. package/template/apps/web/src/components/error/forbidden.tsx +0 -25
  145. package/template/apps/web/src/components/landing/command-block.tsx +0 -64
  146. package/template/apps/web/src/components/landing/feature-card.tsx +0 -60
  147. package/template/apps/web/src/components/landing/included-feature-card.tsx +0 -63
  148. package/template/apps/web/src/components/landing/logo.tsx +0 -41
  149. package/template/apps/web/src/components/landing/tech-badge.tsx +0 -11
  150. package/template/apps/web/src/components/layout/auth-nav.tsx +0 -58
  151. package/template/apps/web/src/components/layout/footer.tsx +0 -3
  152. package/template/apps/web/src/config/landing-data.ts +0 -152
  153. package/template/apps/web/src/config/site.ts +0 -5
  154. package/template/apps/web/src/hooks/api/__tests__/use-users.test.tsx +0 -181
  155. package/template/apps/web/src/hooks/api/use-admin-sessions.ts +0 -75
  156. package/template/apps/web/src/hooks/api/use-admin-stats.ts +0 -33
  157. package/template/apps/web/src/hooks/api/use-sessions.ts +0 -52
  158. package/template/apps/web/src/hooks/api/use-uploads.ts +0 -156
  159. package/template/apps/web/src/hooks/api/use-users.ts +0 -149
  160. package/template/apps/web/src/hooks/use-mobile.ts +0 -21
  161. package/template/apps/web/src/hooks/use-realtime-metrics.ts +0 -120
  162. package/template/apps/web/src/lib/__tests__/utils.test.ts +0 -29
  163. package/template/apps/web/src/lib/api.ts +0 -151
  164. package/template/apps/web/src/lib/auth.ts +0 -13
  165. package/template/apps/web/src/lib/env.ts +0 -52
  166. package/template/apps/web/src/lib/form-utils.ts +0 -11
  167. package/template/apps/web/src/lib/utils.ts +0 -1
  168. package/template/apps/web/src/providers.tsx +0 -34
  169. package/template/apps/web/src/store/atoms.ts +0 -15
  170. package/template/apps/web/src/test/helpers/test-utils.tsx +0 -44
  171. package/template/apps/web/src/test/setup.ts +0 -8
  172. package/template/apps/web/tailwind.config.ts +0 -5
  173. package/template/apps/web/tsconfig.json +0 -26
  174. package/template/apps/web/vitest.config.ts +0 -32
  175. package/template/assets/logo-512.png +0 -0
  176. package/template/assets/logo.svg +0 -4
  177. package/template/docker-compose.prod.yml +0 -66
  178. package/template/docker-compose.yml +0 -36
  179. package/template/eslint.config.ts +0 -119
  180. package/template/package.json +0 -77
  181. package/template/packages/tailwind-config/package.json +0 -9
  182. package/template/packages/tailwind-config/theme.css +0 -179
  183. package/template/packages/types/package.json +0 -29
  184. package/template/packages/types/src/__tests__/schemas.test.ts +0 -255
  185. package/template/packages/types/src/api-response.ts +0 -53
  186. package/template/packages/types/src/health-check.ts +0 -11
  187. package/template/packages/types/src/pagination.ts +0 -41
  188. package/template/packages/types/src/role.ts +0 -5
  189. package/template/packages/types/src/session.ts +0 -48
  190. package/template/packages/types/src/stats.ts +0 -113
  191. package/template/packages/types/src/upload.ts +0 -51
  192. package/template/packages/types/src/user.ts +0 -36
  193. package/template/packages/types/tsconfig.json +0 -5
  194. package/template/packages/types/vitest.config.ts +0 -21
  195. package/template/packages/ui/components.json +0 -21
  196. package/template/packages/ui/package.json +0 -108
  197. package/template/packages/ui/src/__tests__/button.test.tsx +0 -70
  198. package/template/packages/ui/src/alert-dialog.tsx +0 -141
  199. package/template/packages/ui/src/alert.tsx +0 -66
  200. package/template/packages/ui/src/animated-theme-toggler.tsx +0 -167
  201. package/template/packages/ui/src/avatar.tsx +0 -53
  202. package/template/packages/ui/src/badge.tsx +0 -36
  203. package/template/packages/ui/src/button.tsx +0 -84
  204. package/template/packages/ui/src/card.tsx +0 -92
  205. package/template/packages/ui/src/checkbox.tsx +0 -32
  206. package/template/packages/ui/src/data-table/data-table-column-header.tsx +0 -68
  207. package/template/packages/ui/src/data-table/data-table-pagination.tsx +0 -99
  208. package/template/packages/ui/src/data-table/data-table-toolbar.tsx +0 -55
  209. package/template/packages/ui/src/data-table/data-table-view-options.tsx +0 -63
  210. package/template/packages/ui/src/data-table/data-table.tsx +0 -167
  211. package/template/packages/ui/src/dialog.tsx +0 -143
  212. package/template/packages/ui/src/dropdown-menu.tsx +0 -257
  213. package/template/packages/ui/src/empty-state.tsx +0 -52
  214. package/template/packages/ui/src/file-upload-input.tsx +0 -202
  215. package/template/packages/ui/src/form.tsx +0 -168
  216. package/template/packages/ui/src/hooks/use-mobile.ts +0 -19
  217. package/template/packages/ui/src/icons/brand-icons.tsx +0 -16
  218. package/template/packages/ui/src/input.tsx +0 -21
  219. package/template/packages/ui/src/label.tsx +0 -24
  220. package/template/packages/ui/src/lib/utils.ts +0 -6
  221. package/template/packages/ui/src/password-input.tsx +0 -102
  222. package/template/packages/ui/src/popover.tsx +0 -48
  223. package/template/packages/ui/src/radio-group.tsx +0 -45
  224. package/template/packages/ui/src/scroll-area.tsx +0 -58
  225. package/template/packages/ui/src/select.tsx +0 -187
  226. package/template/packages/ui/src/separator.tsx +0 -28
  227. package/template/packages/ui/src/sheet.tsx +0 -139
  228. package/template/packages/ui/src/sidebar.tsx +0 -726
  229. package/template/packages/ui/src/skeleton-variants.tsx +0 -87
  230. package/template/packages/ui/src/skeleton.tsx +0 -13
  231. package/template/packages/ui/src/slider.tsx +0 -63
  232. package/template/packages/ui/src/sonner.tsx +0 -25
  233. package/template/packages/ui/src/spinner.tsx +0 -16
  234. package/template/packages/ui/src/switch.tsx +0 -31
  235. package/template/packages/ui/src/table.tsx +0 -116
  236. package/template/packages/ui/src/tabs.tsx +0 -66
  237. package/template/packages/ui/src/textarea.tsx +0 -18
  238. package/template/packages/ui/src/tooltip.tsx +0 -61
  239. package/template/packages/ui/src/user-avatar.tsx +0 -97
  240. package/template/packages/ui/test-config.js +0 -3
  241. package/template/packages/ui/tsconfig.json +0 -12
  242. package/template/packages/ui/turbo.json +0 -18
  243. package/template/packages/ui/vitest.config.ts +0 -17
  244. package/template/packages/ui/vitest.setup.ts +0 -1
  245. package/template/packages/utils/package.json +0 -23
  246. package/template/packages/utils/src/__tests__/utils.test.ts +0 -223
  247. package/template/packages/utils/src/array.ts +0 -18
  248. package/template/packages/utils/src/async.ts +0 -3
  249. package/template/packages/utils/src/date.ts +0 -77
  250. package/template/packages/utils/src/errors.ts +0 -73
  251. package/template/packages/utils/src/number.ts +0 -11
  252. package/template/packages/utils/src/string.ts +0 -13
  253. package/template/packages/utils/tsconfig.json +0 -5
  254. package/template/packages/utils/vitest.config.ts +0 -21
  255. package/template/pnpm-workspace.yaml +0 -4
  256. package/template/tsconfig.base.json +0 -32
  257. package/template/turbo.json +0 -133
  258. package/template/vitest.shared.ts +0 -26
  259. package/template/vitest.workspace.ts +0 -9
@@ -1,84 +0,0 @@
1
- import { Slot } from '@radix-ui/react-slot';
2
- import { cva, type VariantProps } from 'class-variance-authority';
3
- import { Loader2 } from 'lucide-react';
4
- import * as React from 'react';
5
-
6
- import { cn } from './lib/utils';
7
-
8
- const buttonVariants = cva(
9
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all cursor-pointer disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
10
- {
11
- variants: {
12
- variant: {
13
- default: 'bg-primary text-primary-foreground hover:bg-primary/90',
14
- destructive:
15
- 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
16
- outline:
17
- 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
18
- secondary:
19
- 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
20
- ghost:
21
- 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
22
- link: 'text-primary underline-offset-4 hover:underline',
23
- },
24
- size: {
25
- default: 'h-9 px-4 py-2 has-[>svg]:px-3',
26
- sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
27
- lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
28
- icon: 'size-9',
29
- 'icon-sm': 'size-8',
30
- 'icon-lg': 'size-10',
31
- },
32
- },
33
- defaultVariants: {
34
- variant: 'default',
35
- size: 'default',
36
- },
37
- }
38
- );
39
-
40
- interface ButtonProps
41
- extends React.ComponentProps<'button'>,
42
- VariantProps<typeof buttonVariants> {
43
- asChild?: boolean;
44
- isLoading?: boolean;
45
- }
46
-
47
- function Button({
48
- className,
49
- variant,
50
- size,
51
- asChild = false,
52
- isLoading = false,
53
- children,
54
- disabled,
55
- ...props
56
- }: ButtonProps) {
57
- const Comp = asChild ? Slot : 'button';
58
-
59
- if (asChild) {
60
- return (
61
- <Comp
62
- data-slot="button"
63
- className={cn(buttonVariants({ variant, size, className }))}
64
- {...props}
65
- >
66
- {children}
67
- </Comp>
68
- );
69
- }
70
-
71
- return (
72
- <Comp
73
- data-slot="button"
74
- className={cn(buttonVariants({ variant, size, className }))}
75
- disabled={disabled || isLoading}
76
- {...props}
77
- >
78
- {isLoading && <Loader2 className="animate-spin" />}
79
- {children}
80
- </Comp>
81
- );
82
- }
83
-
84
- export { Button, buttonVariants };
@@ -1,92 +0,0 @@
1
- import * as React from 'react';
2
-
3
- import { cn } from './lib/utils';
4
-
5
- function Card({ className, ...props }: React.ComponentProps<'div'>) {
6
- return (
7
- <div
8
- data-slot="card"
9
- className={cn(
10
- 'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
11
- className
12
- )}
13
- {...props}
14
- />
15
- );
16
- }
17
-
18
- function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
19
- return (
20
- <div
21
- data-slot="card-header"
22
- className={cn(
23
- '@container/card-header has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6 grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6',
24
- className
25
- )}
26
- {...props}
27
- />
28
- );
29
- }
30
-
31
- function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
32
- return (
33
- <div
34
- data-slot="card-title"
35
- className={cn('font-semibold leading-none', className)}
36
- {...props}
37
- />
38
- );
39
- }
40
-
41
- function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
42
- return (
43
- <div
44
- data-slot="card-description"
45
- className={cn('text-muted-foreground text-sm', className)}
46
- {...props}
47
- />
48
- );
49
- }
50
-
51
- function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
52
- return (
53
- <div
54
- data-slot="card-action"
55
- className={cn(
56
- 'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
57
- className
58
- )}
59
- {...props}
60
- />
61
- );
62
- }
63
-
64
- function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
65
- return (
66
- <div
67
- data-slot="card-content"
68
- className={cn('px-6', className)}
69
- {...props}
70
- />
71
- );
72
- }
73
-
74
- function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
75
- return (
76
- <div
77
- data-slot="card-footer"
78
- className={cn('[.border-t]:pt-6 flex items-center px-6', className)}
79
- {...props}
80
- />
81
- );
82
- }
83
-
84
- export {
85
- Card,
86
- CardAction,
87
- CardContent,
88
- CardDescription,
89
- CardFooter,
90
- CardHeader,
91
- CardTitle,
92
- };
@@ -1,32 +0,0 @@
1
- 'use client';
2
-
3
- import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
4
- import { CheckIcon } from 'lucide-react';
5
- import * as React from 'react';
6
-
7
- import { cn } from './lib/utils';
8
-
9
- function Checkbox({
10
- className,
11
- ...props
12
- }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
13
- return (
14
- <CheckboxPrimitive.Root
15
- data-slot="checkbox"
16
- className={cn(
17
- 'border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive shadow-xs peer size-4 shrink-0 cursor-pointer rounded-[4px] border outline-none transition-shadow focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
18
- className
19
- )}
20
- {...props}
21
- >
22
- <CheckboxPrimitive.Indicator
23
- data-slot="checkbox-indicator"
24
- className="flex items-center justify-center text-current transition-none"
25
- >
26
- <CheckIcon className="size-3.5" />
27
- </CheckboxPrimitive.Indicator>
28
- </CheckboxPrimitive.Root>
29
- );
30
- }
31
-
32
- export { Checkbox };
@@ -1,68 +0,0 @@
1
- 'use client';
2
-
3
- import type { Column } from '@tanstack/react-table';
4
- import { ArrowDown, ArrowUp, ChevronsUpDown, EyeOff } from 'lucide-react';
5
-
6
- import { Button } from '../button';
7
- import {
8
- DropdownMenu,
9
- DropdownMenuContent,
10
- DropdownMenuItem,
11
- DropdownMenuSeparator,
12
- DropdownMenuTrigger,
13
- } from '../dropdown-menu';
14
- import { cn } from '../lib/utils';
15
-
16
- interface DataTableColumnHeaderProps<TData, TValue>
17
- extends React.HTMLAttributes<HTMLDivElement> {
18
- column: Column<TData, TValue>;
19
- title: string;
20
- }
21
-
22
- export function DataTableColumnHeader<TData, TValue>({
23
- column,
24
- title,
25
- className,
26
- }: DataTableColumnHeaderProps<TData, TValue>) {
27
- if (!column.getCanSort()) {
28
- return <div className={cn(className)}>{title}</div>;
29
- }
30
-
31
- return (
32
- <div className={cn('flex items-center space-x-2', className)}>
33
- <DropdownMenu>
34
- <DropdownMenuTrigger asChild>
35
- <Button
36
- variant="ghost"
37
- size="sm"
38
- className="data-[state=open]:bg-accent -ml-3 h-8"
39
- >
40
- <span>{title}</span>
41
- {column.getIsSorted() === 'desc' ? (
42
- <ArrowDown className="ml-2 h-4 w-4" />
43
- ) : column.getIsSorted() === 'asc' ? (
44
- <ArrowUp className="ml-2 h-4 w-4" />
45
- ) : (
46
- <ChevronsUpDown className="ml-2 h-4 w-4" />
47
- )}
48
- </Button>
49
- </DropdownMenuTrigger>
50
- <DropdownMenuContent align="start">
51
- <DropdownMenuItem onClick={() => column.toggleSorting(false)}>
52
- <ArrowUp className="text-muted-foreground/70 mr-2 h-3.5 w-3.5" />
53
- Asc
54
- </DropdownMenuItem>
55
- <DropdownMenuItem onClick={() => column.toggleSorting(true)}>
56
- <ArrowDown className="text-muted-foreground/70 mr-2 h-3.5 w-3.5" />
57
- Desc
58
- </DropdownMenuItem>
59
- <DropdownMenuSeparator />
60
- <DropdownMenuItem onClick={() => column.toggleVisibility(false)}>
61
- <EyeOff className="text-muted-foreground/70 mr-2 h-3.5 w-3.5" />
62
- Hide
63
- </DropdownMenuItem>
64
- </DropdownMenuContent>
65
- </DropdownMenu>
66
- </div>
67
- );
68
- }
@@ -1,99 +0,0 @@
1
- 'use client';
2
-
3
- import type { Table } from '@tanstack/react-table';
4
- import {
5
- ChevronLeft,
6
- ChevronRight,
7
- ChevronsLeft,
8
- ChevronsRight,
9
- } from 'lucide-react';
10
-
11
- import { Button } from '../button';
12
- import {
13
- Select,
14
- SelectContent,
15
- SelectItem,
16
- SelectTrigger,
17
- SelectValue,
18
- } from '../select';
19
-
20
- interface DataTablePaginationProps<TData> {
21
- table: Table<TData>;
22
- }
23
-
24
- export function DataTablePagination<TData>({
25
- table,
26
- }: DataTablePaginationProps<TData>) {
27
- return (
28
- <div className="flex items-center justify-between px-2">
29
- <div className="text-muted-foreground flex-1 text-sm">
30
- {table.getFilteredSelectedRowModel().rows.length} of{' '}
31
- {table.getFilteredRowModel().rows.length} row(s) selected.
32
- </div>
33
- <div className="flex items-center space-x-6 lg:space-x-8">
34
- <div className="flex items-center space-x-2">
35
- <p className="text-sm font-medium">Rows per page</p>
36
- <Select
37
- value={`${table.getState().pagination.pageSize}`}
38
- onValueChange={(value) => {
39
- table.setPageSize(Number(value));
40
- }}
41
- >
42
- <SelectTrigger className="h-8 w-[70px]">
43
- <SelectValue placeholder={table.getState().pagination.pageSize} />
44
- </SelectTrigger>
45
- <SelectContent side="top">
46
- {[10, 20, 30, 40, 50].map((pageSize) => (
47
- <SelectItem key={pageSize} value={`${pageSize}`}>
48
- {pageSize}
49
- </SelectItem>
50
- ))}
51
- </SelectContent>
52
- </Select>
53
- </div>
54
- <div className="flex w-[100px] items-center justify-center text-sm font-medium">
55
- Page {table.getState().pagination.pageIndex + 1} of{' '}
56
- {table.getPageCount()}
57
- </div>
58
- <div className="flex items-center space-x-2">
59
- <Button
60
- variant="outline"
61
- className="hidden h-8 w-8 p-0 lg:flex"
62
- onClick={() => table.setPageIndex(0)}
63
- disabled={!table.getCanPreviousPage()}
64
- >
65
- <span className="sr-only">Go to first page</span>
66
- <ChevronsLeft className="h-4 w-4" />
67
- </Button>
68
- <Button
69
- variant="outline"
70
- className="h-8 w-8 p-0"
71
- onClick={() => table.previousPage()}
72
- disabled={!table.getCanPreviousPage()}
73
- >
74
- <span className="sr-only">Go to previous page</span>
75
- <ChevronLeft className="h-4 w-4" />
76
- </Button>
77
- <Button
78
- variant="outline"
79
- className="h-8 w-8 p-0"
80
- onClick={() => table.nextPage()}
81
- disabled={!table.getCanNextPage()}
82
- >
83
- <span className="sr-only">Go to next page</span>
84
- <ChevronRight className="h-4 w-4" />
85
- </Button>
86
- <Button
87
- variant="outline"
88
- className="hidden h-8 w-8 p-0 lg:flex"
89
- onClick={() => table.setPageIndex(table.getPageCount() - 1)}
90
- disabled={!table.getCanNextPage()}
91
- >
92
- <span className="sr-only">Go to last page</span>
93
- <ChevronsRight className="h-4 w-4" />
94
- </Button>
95
- </div>
96
- </div>
97
- </div>
98
- );
99
- }
@@ -1,55 +0,0 @@
1
- 'use client';
2
-
3
- import type { Table } from '@tanstack/react-table';
4
- import { X } from 'lucide-react';
5
-
6
- import { Button } from '../button';
7
- import { Input } from '../input';
8
- import { DataTableViewOptions } from './data-table-view-options';
9
-
10
- interface DataTableToolbarProps<TData> {
11
- table: Table<TData>;
12
- searchPlaceholder?: string;
13
- searchColumnId?: string;
14
- }
15
-
16
- export function DataTableToolbar<TData>({
17
- table,
18
- searchPlaceholder = 'Search...',
19
- searchColumnId,
20
- }: DataTableToolbarProps<TData>) {
21
- const isFiltered = table.getState().columnFilters.length > 0;
22
-
23
- return (
24
- <div className="flex items-center justify-between">
25
- <div className="flex flex-1 items-center space-x-2">
26
- {searchColumnId && (
27
- <Input
28
- placeholder={searchPlaceholder}
29
- value={
30
- (table.getColumn(searchColumnId)?.getFilterValue() as string) ??
31
- ''
32
- }
33
- onChange={(event) =>
34
- table
35
- .getColumn(searchColumnId)
36
- ?.setFilterValue(event.target.value)
37
- }
38
- className="h-8 w-[150px] lg:w-[250px]"
39
- />
40
- )}
41
- {isFiltered && (
42
- <Button
43
- variant="ghost"
44
- onClick={() => table.resetColumnFilters()}
45
- className="h-8 px-2 lg:px-3"
46
- >
47
- Reset
48
- <X className="ml-2 h-4 w-4" />
49
- </Button>
50
- )}
51
- </div>
52
- <DataTableViewOptions table={table} />
53
- </div>
54
- );
55
- }
@@ -1,63 +0,0 @@
1
- 'use client';
2
-
3
- import type { Column, Table } from '@tanstack/react-table';
4
- import { Settings2 } from 'lucide-react';
5
-
6
- import { Button } from '../button';
7
- import {
8
- DropdownMenu,
9
- DropdownMenuCheckboxItem,
10
- DropdownMenuContent,
11
- DropdownMenuLabel,
12
- DropdownMenuSeparator,
13
- DropdownMenuTrigger,
14
- } from '../dropdown-menu';
15
-
16
- interface DataTableViewOptionsProps<TData> {
17
- table: Table<TData>;
18
- }
19
-
20
- function getColumnLabel<TData>(column: Column<TData, unknown>): string {
21
- const meta = column.columnDef.meta as { label?: string } | undefined;
22
- return meta?.label ?? column.id;
23
- }
24
-
25
- export function DataTableViewOptions<TData>({
26
- table,
27
- }: DataTableViewOptionsProps<TData>) {
28
- return (
29
- <DropdownMenu>
30
- <DropdownMenuTrigger asChild>
31
- <Button
32
- variant="outline"
33
- size="sm"
34
- className="ml-auto hidden h-8 lg:flex"
35
- >
36
- <Settings2 className="mr-2 h-4 w-4" />
37
- View
38
- </Button>
39
- </DropdownMenuTrigger>
40
- <DropdownMenuContent align="end" className="w-[150px]">
41
- <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
42
- <DropdownMenuSeparator />
43
- {table
44
- .getAllColumns()
45
- .filter(
46
- (column) =>
47
- typeof column.accessorFn !== 'undefined' && column.getCanHide()
48
- )
49
- .map((column) => {
50
- return (
51
- <DropdownMenuCheckboxItem
52
- key={column.id}
53
- checked={column.getIsVisible()}
54
- onCheckedChange={(value) => column.toggleVisibility(!!value)}
55
- >
56
- {getColumnLabel(column)}
57
- </DropdownMenuCheckboxItem>
58
- );
59
- })}
60
- </DropdownMenuContent>
61
- </DropdownMenu>
62
- );
63
- }
@@ -1,167 +0,0 @@
1
- 'use client';
2
-
3
- import type {
4
- ColumnDef,
5
- ColumnFiltersState,
6
- PaginationState,
7
- SortingState,
8
- VisibilityState,
9
- } from '@tanstack/react-table';
10
- import {
11
- flexRender,
12
- getCoreRowModel,
13
- getFacetedRowModel,
14
- getFacetedUniqueValues,
15
- getFilteredRowModel,
16
- getPaginationRowModel,
17
- getSortedRowModel,
18
- useReactTable,
19
- } from '@tanstack/react-table';
20
- import * as React from 'react';
21
-
22
- import { Skeleton } from '../skeleton';
23
- import {
24
- Table,
25
- TableBody,
26
- TableCell,
27
- TableHead,
28
- TableHeader,
29
- TableRow,
30
- } from '../table';
31
- import { DataTablePagination } from './data-table-pagination';
32
- import { DataTableToolbar } from './data-table-toolbar';
33
-
34
- interface DataTableProps<TData, TValue> {
35
- columns: ColumnDef<TData, TValue>[];
36
- data: TData[];
37
- pagination?: PaginationState;
38
- onPaginationChange?: React.Dispatch<React.SetStateAction<PaginationState>>;
39
- sorting?: SortingState;
40
- onSortingChange?: React.Dispatch<React.SetStateAction<SortingState>>;
41
- columnFilters?: ColumnFiltersState;
42
- onColumnFiltersChange?: React.Dispatch<
43
- React.SetStateAction<ColumnFiltersState>
44
- >;
45
- rowCount?: number;
46
- isLoading?: boolean;
47
- searchPlaceholder?: string;
48
- searchColumnId?: string;
49
- }
50
-
51
- export function DataTable<TData, TValue>({
52
- columns,
53
- data,
54
- pagination,
55
- onPaginationChange,
56
- sorting,
57
- onSortingChange,
58
- columnFilters,
59
- onColumnFiltersChange,
60
- rowCount,
61
- isLoading = false,
62
- searchPlaceholder = 'Search...',
63
- searchColumnId,
64
- }: DataTableProps<TData, TValue>) {
65
- const [rowSelection, setRowSelection] = React.useState({});
66
- const [columnVisibility, setColumnVisibility] =
67
- React.useState<VisibilityState>({});
68
-
69
- const table = useReactTable({
70
- data,
71
- columns,
72
- state: {
73
- sorting,
74
- columnVisibility,
75
- rowSelection,
76
- columnFilters,
77
- pagination,
78
- },
79
- enableRowSelection: true,
80
- onRowSelectionChange: setRowSelection,
81
- onSortingChange,
82
- onColumnFiltersChange,
83
- onColumnVisibilityChange: setColumnVisibility,
84
- onPaginationChange,
85
- getCoreRowModel: getCoreRowModel(),
86
- getFilteredRowModel: getFilteredRowModel(),
87
- getPaginationRowModel: getPaginationRowModel(),
88
- getSortedRowModel: getSortedRowModel(),
89
- getFacetedRowModel: getFacetedRowModel(),
90
- getFacetedUniqueValues: getFacetedUniqueValues(),
91
- manualPagination: !!onPaginationChange,
92
- manualSorting: !!onSortingChange,
93
- manualFiltering: !!onColumnFiltersChange,
94
- rowCount,
95
- });
96
-
97
- return (
98
- <div className="space-y-4">
99
- <DataTableToolbar
100
- table={table}
101
- searchPlaceholder={searchPlaceholder}
102
- searchColumnId={searchColumnId}
103
- />
104
- <div className="rounded-md border">
105
- <Table>
106
- <TableHeader>
107
- {table.getHeaderGroups().map((headerGroup) => (
108
- <TableRow key={headerGroup.id}>
109
- {headerGroup.headers.map((header) => {
110
- return (
111
- <TableHead key={header.id} colSpan={header.colSpan}>
112
- {header.isPlaceholder
113
- ? null
114
- : flexRender(
115
- header.column.columnDef.header,
116
- header.getContext()
117
- )}
118
- </TableHead>
119
- );
120
- })}
121
- </TableRow>
122
- ))}
123
- </TableHeader>
124
- <TableBody>
125
- {isLoading ? (
126
- Array.from({ length: pagination?.pageSize || 10 }).map((_, i) => (
127
- <TableRow key={i}>
128
- {columns.map((_, colIndex) => (
129
- <TableCell key={colIndex}>
130
- <Skeleton className="h-4 w-full" />
131
- </TableCell>
132
- ))}
133
- </TableRow>
134
- ))
135
- ) : table.getRowModel().rows?.length ? (
136
- table.getRowModel().rows.map((row) => (
137
- <TableRow
138
- key={row.id}
139
- data-state={row.getIsSelected() && 'selected'}
140
- >
141
- {row.getVisibleCells().map((cell) => (
142
- <TableCell key={cell.id}>
143
- {flexRender(
144
- cell.column.columnDef.cell,
145
- cell.getContext()
146
- )}
147
- </TableCell>
148
- ))}
149
- </TableRow>
150
- ))
151
- ) : (
152
- <TableRow>
153
- <TableCell
154
- colSpan={columns.length}
155
- className="h-24 text-center"
156
- >
157
- No results.
158
- </TableCell>
159
- </TableRow>
160
- )}
161
- </TableBody>
162
- </Table>
163
- </div>
164
- <DataTablePagination table={table} />
165
- </div>
166
- );
167
- }