startx 1.0.2 → 1.0.3

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 (147) hide show
  1. package/.dockerignore +4 -0
  2. package/apps/cli/src/commands/index.ts +1 -1
  3. package/apps/cli/src/commands/{common → test}/test.ts +4 -2
  4. package/apps/cli/tsconfig.json +0 -1
  5. package/apps/core-server/Dockerfile +5 -4
  6. package/apps/core-server/package.json +1 -1
  7. package/apps/core-server/tsconfig.json +1 -1
  8. package/apps/queue-worker/package.json +1 -1
  9. package/apps/queue-worker/tsconfig.json +1 -1
  10. package/apps/startx-cli/dist/index.mjs +68 -53
  11. package/apps/startx-cli/src/commands/package.ts +453 -0
  12. package/apps/startx-cli/src/configs/scripts.ts +18 -2
  13. package/apps/startx-cli/src/index.ts +2 -4
  14. package/apps/startx-cli/src/types.ts +2 -4
  15. package/apps/startx-cli/src/utils/inquirer.ts +8 -1
  16. package/apps/web-client/.dockerignore +4 -0
  17. package/apps/web-client/app/app.css +1 -0
  18. package/apps/web-client/app/components.json +23 -0
  19. package/apps/web-client/app/config/auth/auth-state.ts +59 -0
  20. package/apps/web-client/app/config/axios-client.ts +87 -0
  21. package/apps/web-client/app/config/env.ts +5 -0
  22. package/apps/web-client/app/entry.client.tsx +7 -0
  23. package/apps/web-client/app/eslint.config.ts +4 -0
  24. package/apps/web-client/app/root.tsx +77 -0
  25. package/apps/web-client/app/routes/home.tsx +12 -0
  26. package/apps/web-client/app/routes.ts +3 -0
  27. package/apps/web-client/eslint.config.ts +4 -0
  28. package/apps/web-client/package.json +55 -0
  29. package/apps/web-client/react-router.config.ts +7 -0
  30. package/apps/web-client/tsconfig.json +22 -0
  31. package/apps/web-client/vite-env.d.ts +8 -0
  32. package/apps/web-client/vite.config.ts +30 -0
  33. package/biome.json +5 -0
  34. package/configs/eslint-config/eslint.config.ts +1 -0
  35. package/configs/eslint-config/src/configs/base.ts +0 -1
  36. package/configs/eslint-config/src/configs/frontend.ts +1 -1
  37. package/configs/eslint-config/tsconfig.json +1 -1
  38. package/configs/typescript-config/tsconfig.frontend.json +1 -1
  39. package/configs/vitest-config/tsconfig.json +1 -1
  40. package/package.json +1 -1
  41. package/packages/@db/drizzle/tsconfig.json +1 -1
  42. package/packages/@db/sqlite/tsconfig.json +1 -1
  43. package/packages/@repo/env/package.json +1 -2
  44. package/packages/@repo/env/src/utils.ts +17 -11
  45. package/packages/@repo/lib/package.json +3 -1
  46. package/packages/@repo/lib/src/session-module/i-session.ts +108 -0
  47. package/packages/@repo/lib/src/session-module/index.ts +8 -111
  48. package/packages/@repo/lib/src/session-module/redis-session.ts +44 -0
  49. package/packages/@repo/lib/tsconfig.json +0 -1
  50. package/packages/@repo/logger/package.json +0 -1
  51. package/packages/@repo/logger/tsconfig.json +1 -1
  52. package/packages/@repo/mail/tsconfig.json +1 -1
  53. package/packages/@repo/redis/tsconfig.json +1 -1
  54. package/packages/aix/package.json +2 -0
  55. package/packages/aix/src/providers/ai-interface.ts +4 -4
  56. package/packages/aix/src/providers/bedrock/bedrock.ts +261 -0
  57. package/packages/aix/src/providers/default-models.ts +65 -0
  58. package/packages/aix/src/providers/openai/openai.ts +2 -2
  59. package/packages/aix/src/providers/providers.ts +11 -0
  60. package/packages/aix/src/providers/types.ts +1 -1
  61. package/packages/{constants → common}/package.json +4 -2
  62. package/packages/{constants/src/index.ts → common/src/constants.ts} +0 -5
  63. package/packages/common/src/types/users.ts +10 -0
  64. package/packages/{constants → common}/tsconfig.json +0 -3
  65. package/packages/ui/components.json +15 -8
  66. package/packages/ui/package.json +23 -36
  67. package/packages/ui/src/api/axios/i-client.ts +40 -0
  68. package/packages/ui/src/api/index.ts +6 -0
  69. package/packages/ui/src/api/query-provider.tsx +34 -0
  70. package/packages/ui/src/api/use-api/api-builder.ts +139 -0
  71. package/packages/ui/src/api/use-api/api-helpers.ts +165 -0
  72. package/packages/ui/src/api/use-api/api-types.ts +138 -0
  73. package/packages/ui/src/api/use-api/query-factory.ts +66 -0
  74. package/packages/ui/src/api/use-api/react-query/types.ts +64 -0
  75. package/packages/ui/src/api/use-api/react-query/use-api-client.ts +56 -0
  76. package/packages/ui/src/api/use-api/react-query/use-api.ts +297 -0
  77. package/packages/ui/src/components/custom/form-wrapper.tsx +113 -160
  78. package/packages/ui/src/components/custom/grid-component.tsx +4 -4
  79. package/packages/ui/src/components/custom/hover-tool.tsx +1 -1
  80. package/packages/ui/src/components/custom/image-picker.tsx +18 -20
  81. package/packages/ui/src/components/custom/no-content.tsx +6 -16
  82. package/packages/ui/src/components/custom/page-section.tsx +14 -17
  83. package/packages/ui/src/components/custom/simple-popover.tsx +5 -9
  84. package/packages/ui/src/components/custom/theme-provider.tsx +117 -42
  85. package/packages/ui/src/components/custom/typography.tsx +20 -22
  86. package/packages/ui/src/components/extensions/timeline.tsx +100 -0
  87. package/packages/ui/src/components/ui/alert-dialog.tsx +46 -108
  88. package/packages/ui/src/components/ui/avatar.tsx +79 -42
  89. package/packages/ui/src/components/ui/badge.tsx +29 -34
  90. package/packages/ui/src/components/ui/breadcrumb.tsx +65 -81
  91. package/packages/ui/src/components/ui/button.tsx +80 -80
  92. package/packages/ui/src/components/ui/card.tsx +48 -69
  93. package/packages/ui/src/components/ui/carousel.tsx +184 -211
  94. package/packages/ui/src/components/ui/checkbox.tsx +21 -24
  95. package/packages/ui/src/components/ui/command.tsx +121 -102
  96. package/packages/ui/src/components/ui/dialog.tsx +45 -32
  97. package/packages/ui/src/components/ui/dropdown-menu.tsx +45 -33
  98. package/packages/ui/src/components/ui/field.tsx +218 -0
  99. package/packages/ui/src/components/ui/form.tsx +63 -76
  100. package/packages/ui/src/components/ui/input-group.tsx +137 -0
  101. package/packages/ui/src/components/ui/input-otp.tsx +60 -50
  102. package/packages/ui/src/components/ui/input.tsx +16 -15
  103. package/packages/ui/src/components/ui/label.tsx +14 -17
  104. package/packages/ui/src/components/ui/multiple-select.tsx +22 -33
  105. package/packages/ui/src/components/ui/popover.tsx +20 -8
  106. package/packages/ui/src/components/ui/select.tsx +33 -34
  107. package/packages/ui/src/components/ui/separator.tsx +8 -8
  108. package/packages/ui/src/components/ui/sheet.tsx +32 -59
  109. package/packages/ui/src/components/ui/sidebar.tsx +654 -0
  110. package/packages/ui/src/components/ui/skeleton.tsx +2 -8
  111. package/packages/ui/src/components/ui/sonner.tsx +39 -0
  112. package/packages/ui/src/components/ui/spinner.tsx +6 -13
  113. package/packages/ui/src/components/ui/switch.tsx +15 -10
  114. package/packages/ui/src/components/ui/table.tsx +48 -89
  115. package/packages/ui/src/components/ui/tabs.tsx +37 -15
  116. package/packages/ui/src/components/ui/textarea.tsx +13 -13
  117. package/packages/ui/src/components/ui/tooltip.tsx +37 -23
  118. package/packages/ui/src/{components/hooks → hooks}/event/use-click.tsx +6 -10
  119. package/packages/ui/src/hooks/time/use-timer.tsx +51 -0
  120. package/packages/ui/src/hooks/use-media-query.tsx +19 -0
  121. package/packages/ui/src/hooks/use-mobile.tsx +17 -0
  122. package/packages/ui/src/{components/hooks → hooks}/use-update-effect.tsx +2 -2
  123. package/packages/ui/src/lib/utils.ts +113 -0
  124. package/packages/ui/src/styles/globals.css +311 -0
  125. package/packages/ui/src/styles/tailwind.css +89 -0
  126. package/packages/ui/tsconfig.json +7 -9
  127. package/pnpm-workspace.yaml +74 -64
  128. package/packages/ui/postcss.config.mjs +0 -9
  129. package/packages/ui/src/components/extensions/carousel.tsx +0 -392
  130. package/packages/ui/src/components/hooks/time/useTimer.tsx +0 -51
  131. package/packages/ui/src/components/hooks/use-media-query.tsx +0 -19
  132. package/packages/ui/src/components/lib/utils.ts +0 -242
  133. package/packages/ui/src/components/ui/timeline.tsx +0 -118
  134. package/packages/ui/src/components/util/n-formattor.ts +0 -22
  135. package/packages/ui/src/components/util/storage.ts +0 -37
  136. package/packages/ui/src/globals.css +0 -87
  137. package/packages/ui/tailwind.config.ts +0 -94
  138. /package/packages/{constants → common}/eslint.config.ts +0 -0
  139. /package/packages/{constants → common}/src/api.ts +0 -0
  140. /package/packages/{constants → common}/src/time.ts +0 -0
  141. /package/packages/{constants → common}/vitest.config.ts +0 -0
  142. /package/packages/ui/src/{components/hooks/time/useDebounce.tsx → hooks/time/use-debounce.tsx} +0 -0
  143. /package/packages/ui/src/{components/hooks/time/useInterval.tsx → hooks/time/use-interval.tsx} +0 -0
  144. /package/packages/ui/src/{components/hooks/time/useTimeout.tsx → hooks/time/use-timeout.tsx} +0 -0
  145. /package/packages/ui/src/{components/hooks → hooks}/use-persistent-storage.tsx +0 -0
  146. /package/packages/ui/src/{components/hooks → hooks}/use-window-dimension.tsx +0 -0
  147. /package/packages/ui/src/{components/sonner.tsx → sonner.ts} +0 -0
@@ -1,16 +1,9 @@
1
- import { type HTMLProps, forwardRef } from 'react';
1
+ import { Loader2Icon } from "lucide-react";
2
2
 
3
- import { cn } from '../lib/utils';
3
+ import { cn } from "@repo/ui/lib/utils";
4
4
 
5
- export const Spinner = forwardRef<HTMLDivElement, HTMLProps<HTMLDivElement>>(
6
- ({ className, ...rest }, ref) => {
7
- const spinnerClass = cn(
8
- 'animate-spin rounded-full border-2 border-current border-t-transparent h-4 w-4',
9
- className,
10
- );
5
+ function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
6
+ return <Loader2Icon role="status" aria-label="Loading" className={cn("size-4 animate-spin", className)} {...props} />;
7
+ }
11
8
 
12
- return <div className={spinnerClass} ref={ref} {...rest} />;
13
- },
14
- );
15
-
16
- Spinner.displayName = 'Spinner';
9
+ export { Spinner };
@@ -1,25 +1,30 @@
1
- 'use client';
1
+ "use client";
2
2
 
3
- import * as SwitchPrimitive from '@radix-ui/react-switch';
4
- import type * as React from 'react';
3
+ import { Switch as SwitchPrimitive } from "radix-ui";
4
+ import * as React from "react";
5
5
 
6
- import { cn } from '../lib/utils';
6
+ import { cn } from "@repo/ui/lib/utils";
7
7
 
8
- function Switch({ className, ...props }: React.ComponentProps<typeof SwitchPrimitive.Root>) {
8
+ function Switch({
9
+ className,
10
+ size = "default",
11
+ ...props
12
+ }: React.ComponentProps<typeof SwitchPrimitive.Root> & {
13
+ size?: "sm" | "default";
14
+ }) {
9
15
  return (
10
16
  <SwitchPrimitive.Root
11
17
  data-slot="switch"
18
+ data-size={size}
12
19
  className={cn(
13
- 'peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
14
- className,
20
+ "peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 data-disabled:cursor-not-allowed data-disabled:opacity-50",
21
+ className
15
22
  )}
16
23
  {...props}
17
24
  >
18
25
  <SwitchPrimitive.Thumb
19
26
  data-slot="switch-thumb"
20
- className={cn(
21
- 'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0',
22
- )}
27
+ className="pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] dark:data-checked:bg-primary-foreground group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 dark:data-unchecked:bg-foreground"
23
28
  />
24
29
  </SwitchPrimitive.Root>
25
30
  );
@@ -1,116 +1,75 @@
1
1
  "use client";
2
2
 
3
- import type * as React from "react";
3
+ import * as React from "react";
4
4
 
5
- import { cn } from "../lib/utils";
5
+ import { cn } from "@repo/ui/lib/utils";
6
6
 
7
7
  function Table({ className, ...props }: React.ComponentProps<"table">) {
8
- return (
9
- <div
10
- data-slot="table-container"
11
- className="relative w-full overflow-x-auto"
12
- >
13
- <table
14
- data-slot="table"
15
- className={cn("w-full caption-bottom text-sm", className)}
16
- {...props}
17
- />
18
- </div>
19
- );
8
+ return (
9
+ <div data-slot="table-container" className="relative w-full overflow-x-auto">
10
+ <table data-slot="table" className={cn("w-full caption-bottom text-sm", className)} {...props} />
11
+ </div>
12
+ );
20
13
  }
21
14
 
22
15
  function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
23
- return (
24
- <thead
25
- data-slot="table-header"
26
- className={cn("[&_tr]:border-b", className)}
27
- {...props}
28
- />
29
- );
16
+ return <thead data-slot="table-header" className={cn("[&_tr]:border-b", className)} {...props} />;
30
17
  }
31
18
 
32
19
  function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
33
- return (
34
- <tbody
35
- data-slot="table-body"
36
- className={cn("[&_tr:last-child]:border-0", className)}
37
- {...props}
38
- />
39
- );
20
+ return <tbody data-slot="table-body" className={cn("[&_tr:last-child]:border-0", className)} {...props} />;
40
21
  }
41
22
 
42
23
  function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
43
- return (
44
- <tfoot
45
- data-slot="table-footer"
46
- className={cn(
47
- "bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
48
- className
49
- )}
50
- {...props}
51
- />
52
- );
24
+ return (
25
+ <tfoot
26
+ data-slot="table-footer"
27
+ className={cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className)}
28
+ {...props}
29
+ />
30
+ );
53
31
  }
54
32
 
55
33
  function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
56
- return (
57
- <tr
58
- data-slot="table-row"
59
- className={cn(
60
- "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
61
- className
62
- )}
63
- {...props}
64
- />
65
- );
34
+ return (
35
+ <tr
36
+ data-slot="table-row"
37
+ className={cn(
38
+ "border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted",
39
+ className
40
+ )}
41
+ {...props}
42
+ />
43
+ );
66
44
  }
67
45
 
68
46
  function TableHead({ className, ...props }: React.ComponentProps<"th">) {
69
- return (
70
- <th
71
- data-slot="table-head"
72
- className={cn(
73
- "text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
74
- className
75
- )}
76
- {...props}
77
- />
78
- );
47
+ return (
48
+ <th
49
+ data-slot="table-head"
50
+ className={cn(
51
+ "h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
52
+ className
53
+ )}
54
+ {...props}
55
+ />
56
+ );
79
57
  }
80
58
 
81
59
  function TableCell({ className, ...props }: React.ComponentProps<"td">) {
82
- return (
83
- <td
84
- data-slot="table-cell"
85
- className={cn(
86
- "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
87
- className
88
- )}
89
- {...props}
90
- />
91
- );
60
+ return (
61
+ <td
62
+ data-slot="table-cell"
63
+ className={cn("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0", className)}
64
+ {...props}
65
+ />
66
+ );
92
67
  }
93
68
 
94
- function TableCaption({
95
- className,
96
- ...props
97
- }: React.ComponentProps<"caption">) {
98
- return (
99
- <caption
100
- data-slot="table-caption"
101
- className={cn("text-muted-foreground mt-4 text-sm", className)}
102
- {...props}
103
- />
104
- );
69
+ function TableCaption({ className, ...props }: React.ComponentProps<"caption">) {
70
+ return (
71
+ <caption data-slot="table-caption" className={cn("mt-4 text-sm text-muted-foreground", className)} {...props} />
72
+ );
105
73
  }
106
74
 
107
- export {
108
- Table,
109
- TableHeader,
110
- TableBody,
111
- TableFooter,
112
- TableHead,
113
- TableRow,
114
- TableCell,
115
- TableCaption,
116
- };
75
+ export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };
@@ -1,28 +1,47 @@
1
- 'use client';
1
+ "use client";
2
2
 
3
- import * as TabsPrimitive from '@radix-ui/react-tabs';
4
- import type * as React from 'react';
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { Tabs as TabsPrimitive } from "radix-ui";
5
+ import * as React from "react";
5
6
 
6
- import { cn } from '../lib/utils';
7
+ import { cn } from "@repo/ui/lib/utils";
7
8
 
8
- function Tabs({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Root>) {
9
+ function Tabs({ className, orientation = "horizontal", ...props }: React.ComponentProps<typeof TabsPrimitive.Root>) {
9
10
  return (
10
11
  <TabsPrimitive.Root
11
12
  data-slot="tabs"
12
- className={cn('flex flex-col gap-2', className)}
13
+ data-orientation={orientation}
14
+ className={cn("group/tabs flex gap-2 data-horizontal:flex-col", className)}
13
15
  {...props}
14
16
  />
15
17
  );
16
18
  }
17
19
 
18
- function TabsList({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.List>) {
20
+ const tabsListVariants = cva(
21
+ "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
22
+ {
23
+ variants: {
24
+ variant: {
25
+ default: "bg-muted",
26
+ line: "gap-1 bg-transparent",
27
+ },
28
+ },
29
+ defaultVariants: {
30
+ variant: "default",
31
+ },
32
+ }
33
+ );
34
+
35
+ function TabsList({
36
+ className,
37
+ variant = "default",
38
+ ...props
39
+ }: React.ComponentProps<typeof TabsPrimitive.List> & VariantProps<typeof tabsListVariants>) {
19
40
  return (
20
41
  <TabsPrimitive.List
21
42
  data-slot="tabs-list"
22
- className={cn(
23
- 'bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]',
24
- className,
25
- )}
43
+ data-variant={variant}
44
+ className={cn(tabsListVariants({ variant }), className)}
26
45
  {...props}
27
46
  />
28
47
  );
@@ -33,8 +52,11 @@ function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPr
33
52
  <TabsPrimitive.Trigger
34
53
  data-slot="tabs-trigger"
35
54
  className={cn(
36
- "data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
37
- className,
55
+ "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
56
+ "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
57
+ "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
58
+ "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
59
+ className
38
60
  )}
39
61
  {...props}
40
62
  />
@@ -45,10 +67,10 @@ function TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPr
45
67
  return (
46
68
  <TabsPrimitive.Content
47
69
  data-slot="tabs-content"
48
- className={cn('flex-1 outline-none', className)}
70
+ className={cn("flex-1 text-sm outline-none", className)}
49
71
  {...props}
50
72
  />
51
73
  );
52
74
  }
53
75
 
54
- export { Tabs, TabsList, TabsTrigger, TabsContent };
76
+ export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
@@ -1,18 +1,18 @@
1
- import type * as React from "react";
1
+ import * as React from "react";
2
+
3
+ import { cn } from "@repo/ui/lib/utils";
2
4
 
3
- import { cn } from "../lib/utils";
4
- export type TextAreaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
5
5
  function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
6
- return (
7
- <textarea
8
- data-slot="textarea"
9
- className={cn(
10
- "border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
11
- className
12
- )}
13
- {...props}
14
- />
15
- );
6
+ return (
7
+ <textarea
8
+ data-slot="textarea"
9
+ className={cn(
10
+ "flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
11
+ className
12
+ )}
13
+ {...props}
14
+ />
15
+ );
16
16
  }
17
17
 
18
18
  export { Textarea };
@@ -1,30 +1,44 @@
1
- 'use client';
1
+ "use client";
2
2
 
3
- import * as TooltipPrimitive from '@radix-ui/react-tooltip';
4
- import * as React from 'react';
3
+ import { Tooltip as TooltipPrimitive } from "radix-ui";
4
+ import * as React from "react";
5
5
 
6
- import { cn } from '../lib/utils';
6
+ import { cn } from "@repo/ui/lib/utils";
7
7
 
8
- const TooltipProvider = TooltipPrimitive.Provider;
8
+ function TooltipProvider({ delayDuration = 0, ...props }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
9
+ return <TooltipPrimitive.Provider data-slot="tooltip-provider" delayDuration={delayDuration} {...props} />;
10
+ }
9
11
 
10
- const Tooltip = TooltipPrimitive.Root;
12
+ function Tooltip({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
13
+ return <TooltipPrimitive.Root data-slot="tooltip" {...props} />;
14
+ }
11
15
 
12
- const TooltipTrigger = TooltipPrimitive.Trigger;
16
+ function TooltipTrigger({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
17
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
18
+ }
13
19
 
14
- const TooltipContent = React.forwardRef<
15
- React.ElementRef<typeof TooltipPrimitive.Content>,
16
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
17
- >(({ className, sideOffset = 4, ...props }, ref) => (
18
- <TooltipPrimitive.Content
19
- ref={ref}
20
- sideOffset={sideOffset}
21
- className={cn(
22
- 'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
23
- className,
24
- )}
25
- {...props}
26
- />
27
- ));
28
- TooltipContent.displayName = TooltipPrimitive.Content.displayName;
20
+ function TooltipContent({
21
+ className,
22
+ sideOffset = 0,
23
+ children,
24
+ ...props
25
+ }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
26
+ return (
27
+ <TooltipPrimitive.Portal>
28
+ <TooltipPrimitive.Content
29
+ data-slot="tooltip-content"
30
+ sideOffset={sideOffset}
31
+ className={cn(
32
+ "z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
33
+ className
34
+ )}
35
+ {...props}
36
+ >
37
+ {children}
38
+ <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />
39
+ </TooltipPrimitive.Content>
40
+ </TooltipPrimitive.Portal>
41
+ );
42
+ }
29
43
 
30
- export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
44
+ export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
@@ -1,10 +1,6 @@
1
- /* eslint-disable id-denylist */
2
- import { type RefObject, useEffect } from 'react';
1
+ import { type RefObject, useEffect } from "react";
3
2
 
4
- function useOutsideClick<T extends HTMLElement>(
5
- ref: RefObject<T | null>,
6
- callback: () => void,
7
- ): void {
3
+ function useOutsideClick<T extends HTMLElement>(ref: RefObject<T | null>, callback: () => void): void {
8
4
  useEffect(() => {
9
5
  const handleClickOrTouch = (event: Event) => {
10
6
  if (ref.current && !ref.current.contains(event.target as Node)) {
@@ -12,10 +8,10 @@ function useOutsideClick<T extends HTMLElement>(
12
8
  }
13
9
  };
14
10
 
15
- document.addEventListener('mousedown', handleClickOrTouch);
11
+ document.addEventListener("mousedown", handleClickOrTouch);
16
12
 
17
13
  return () => {
18
- document.removeEventListener('mousedown', handleClickOrTouch);
14
+ document.removeEventListener("mousedown", handleClickOrTouch);
19
15
  };
20
16
  }, [ref, callback]);
21
17
  }
@@ -28,10 +24,10 @@ function useInsideClick<T extends HTMLElement>(ref: RefObject<T>, callback: () =
28
24
  }
29
25
  };
30
26
 
31
- document.addEventListener('mousedown', handleClickOrTouch);
27
+ document.addEventListener("mousedown", handleClickOrTouch);
32
28
 
33
29
  return () => {
34
- document.removeEventListener('mousedown', handleClickOrTouch);
30
+ document.removeEventListener("mousedown", handleClickOrTouch);
35
31
  };
36
32
  }, [ref, callback]);
37
33
  }
@@ -0,0 +1,51 @@
1
+ import { useState, useRef, useEffect } from "react";
2
+
3
+ type TimerHook = {
4
+ counter: number;
5
+ start: () => void;
6
+ reset: () => void;
7
+ clear: () => void;
8
+ };
9
+
10
+ export function useTimer(initialSeconds: number): TimerHook {
11
+ const [counter, setCounter] = useState(initialSeconds);
12
+ const timerRef = useRef<NodeJS.Timeout | null>(null);
13
+
14
+ useEffect(() => {
15
+ // Cleanup on component unmount or when counter changes
16
+ return () => {
17
+ if (timerRef.current) {
18
+ clearTimeout(timerRef.current);
19
+ }
20
+ };
21
+ }, []);
22
+
23
+ const start = () => {
24
+ if (timerRef.current) {
25
+ clearTimeout(timerRef.current);
26
+ }
27
+
28
+ timerRef.current = setTimeout(() => {
29
+ setCounter(prev => (prev > 0 ? prev - 1 : 0));
30
+ }, 1000);
31
+ };
32
+
33
+ const reset = () => {
34
+ setCounter(initialSeconds);
35
+ clear();
36
+ };
37
+
38
+ const clear = () => {
39
+ if (timerRef.current) {
40
+ clearTimeout(timerRef.current);
41
+ }
42
+ };
43
+
44
+ useEffect(() => {
45
+ if (counter > 0) {
46
+ start();
47
+ }
48
+ }, [counter]);
49
+
50
+ return { counter, start, reset, clear };
51
+ }
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+
3
+ export function useMediaQuery(query: string) {
4
+ const [value, setValue] = React.useState(false);
5
+
6
+ React.useEffect(() => {
7
+ function onChange(event: MediaQueryListEvent) {
8
+ setValue(event.matches);
9
+ }
10
+
11
+ const result = matchMedia(query);
12
+ result.addEventListener("change", onChange);
13
+ setValue(result.matches);
14
+
15
+ return () => result.removeEventListener("change", onChange);
16
+ }, [query]);
17
+
18
+ return value;
19
+ }
@@ -0,0 +1,17 @@
1
+ import * as React from "react";
2
+
3
+ export function useIsMobile(mobileBreakpoint = 768) {
4
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
5
+
6
+ React.useEffect(() => {
7
+ const mql = window.matchMedia(`(max-width: ${mobileBreakpoint - 1}px)`);
8
+ const onChange = () => {
9
+ setIsMobile(window.innerWidth < mobileBreakpoint);
10
+ };
11
+ mql.addEventListener("change", onChange);
12
+ setIsMobile(window.innerWidth < mobileBreakpoint);
13
+ return () => mql.removeEventListener("change", onChange);
14
+ }, [mobileBreakpoint]);
15
+
16
+ return !!isMobile;
17
+ }
@@ -1,5 +1,5 @@
1
- import type React from 'react';
2
- import { useEffect, useRef } from 'react';
1
+ import type React from "react";
2
+ import { useEffect, useRef } from "react";
3
3
 
4
4
  const useDidMountEffect = (func: React.EffectCallback, deps: React.DependencyList) => {
5
5
  const didMount = useRef(false);