startx 1.0.1 → 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,9 +0,0 @@
1
- /** @type {import('postcss-load-config').Config} */
2
- const config = {
3
- plugins: {
4
- "@tailwindcss/postcss": {},
5
- autoprefixer: {},
6
- },
7
- };
8
-
9
- export default config;
@@ -1,392 +0,0 @@
1
- 'use client';
2
-
3
- import type { EmblaOptionsType } from 'embla-carousel';
4
- import useEmblaCarousel from 'embla-carousel-react';
5
- import { ChevronRightIcon, ChevronLeftIcon } from 'lucide-react';
6
- import type React from 'react';
7
- import { forwardRef, useCallback, useContext, useEffect, useState, createContext } from 'react';
8
-
9
- import { Button } from '@/components/ui/button';
10
-
11
- import { cn } from '../lib/utils';
12
-
13
- type CarouselContextProps = {
14
- carouselOptions?: EmblaOptionsType;
15
- orientation?: 'vertical' | 'horizontal';
16
- plugins?: Parameters<typeof useEmblaCarousel>[1];
17
- };
18
-
19
- type DirectionOption = 'ltr' | 'rtl' | undefined;
20
-
21
- type CarouselContextType = {
22
- emblaMainApi: ReturnType<typeof useEmblaCarousel>[1];
23
- mainRef: ReturnType<typeof useEmblaCarousel>[0];
24
- thumbsRef: ReturnType<typeof useEmblaCarousel>[0];
25
- scrollNext: () => void;
26
- scrollPrev: () => void;
27
- canScrollNext: boolean;
28
- canScrollPrev: boolean;
29
- activeIndex: number;
30
- onThumbClick: (index: number) => void;
31
- handleKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => void;
32
- orientation: 'vertical' | 'horizontal';
33
- direction: DirectionOption;
34
- } & CarouselContextProps;
35
-
36
- const useCarousel = () => {
37
- const context = useContext(CarouselContext);
38
- if (!context) {
39
- throw new Error('useCarousel must be used within a CarouselProvider');
40
- }
41
- return context;
42
- };
43
-
44
- const CarouselContext = createContext<CarouselContextType | null>(null);
45
-
46
- /**
47
- * Carousel Docs: {@link: https://shadcn-extension.vercel.app/docs/carousel}
48
- */
49
-
50
- const Carousel = forwardRef<
51
- HTMLDivElement,
52
- CarouselContextProps & React.HTMLAttributes<HTMLDivElement> & {dir: DirectionOption}
53
- >(
54
- (
55
- { carouselOptions, orientation = 'horizontal', dir, plugins, children, className, ...props },
56
- ref,
57
- ) => {
58
- const [emblaMainRef, emblaMainApi] = useEmblaCarousel(
59
- {
60
- ...carouselOptions,
61
- axis: orientation === 'vertical' ? 'y' : 'x',
62
- direction: carouselOptions?.direction ?? (dir as DirectionOption),
63
- },
64
- plugins,
65
- );
66
-
67
- const [emblaThumbsRef, emblaThumbsApi] = useEmblaCarousel(
68
- {
69
- ...carouselOptions,
70
- axis: orientation === 'vertical' ? 'y' : 'x',
71
- direction: carouselOptions?.direction ?? (dir as DirectionOption),
72
- containScroll: 'keepSnaps',
73
- dragFree: true,
74
- },
75
- plugins,
76
- );
77
-
78
- const [canScrollPrev, setCanScrollPrev] = useState<boolean>(false);
79
- const [canScrollNext, setCanScrollNext] = useState<boolean>(false);
80
- const [activeIndex, setActiveIndex] = useState<number>(0);
81
-
82
- const ScrollNext = useCallback(() => {
83
- if (!emblaMainApi) return;
84
- emblaMainApi.scrollNext();
85
- }, [emblaMainApi]);
86
-
87
- const ScrollPrev = useCallback(() => {
88
- if (!emblaMainApi) return;
89
- emblaMainApi.scrollPrev();
90
- }, [emblaMainApi]);
91
-
92
- const direction = carouselOptions?.direction ?? (dir as DirectionOption);
93
-
94
- const handleKeyDown = useCallback(
95
- (event: React.KeyboardEvent<HTMLDivElement>) => {
96
- if (!emblaMainApi) return;
97
- switch (event.key) {
98
- case 'ArrowLeft':
99
- event.preventDefault();
100
- if (orientation === 'horizontal') {
101
- if (direction === 'rtl') {
102
- ScrollNext();
103
- return;
104
- }
105
- ScrollPrev();
106
- }
107
- break;
108
- case 'ArrowRight':
109
- event.preventDefault();
110
- if (orientation === 'horizontal') {
111
- if (direction === 'rtl') {
112
- ScrollPrev();
113
- return;
114
- }
115
- ScrollNext();
116
- }
117
- break;
118
- case 'ArrowUp':
119
- event.preventDefault();
120
- if (orientation === 'vertical') {
121
- ScrollPrev();
122
- }
123
- break;
124
- case 'ArrowDown':
125
- event.preventDefault();
126
- if (orientation === 'vertical') {
127
- ScrollNext();
128
- }
129
- break;
130
- }
131
- },
132
- [emblaMainApi, orientation, direction],
133
- );
134
-
135
- const onThumbClick = useCallback(
136
- (index: number) => {
137
- if (!emblaMainApi || !emblaThumbsApi) return;
138
- emblaMainApi.scrollTo(index);
139
- },
140
- [emblaMainApi, emblaThumbsApi],
141
- );
142
-
143
- const onSelect = useCallback(() => {
144
- if (!emblaMainApi || !emblaThumbsApi) return;
145
- const selected = emblaMainApi.selectedScrollSnap();
146
- setActiveIndex(selected);
147
- emblaThumbsApi.scrollTo(selected);
148
- setCanScrollPrev(emblaMainApi.canScrollPrev());
149
- setCanScrollNext(emblaMainApi.canScrollNext());
150
- }, [emblaMainApi, emblaThumbsApi]);
151
-
152
- useEffect(() => {
153
- if (!emblaMainApi) return;
154
- onSelect();
155
- emblaMainApi.on('select', onSelect);
156
- emblaMainApi.on('reInit', onSelect);
157
-
158
- return () => {
159
- emblaMainApi.off('select', onSelect);
160
- };
161
- }, [emblaMainApi, onSelect]);
162
-
163
- return (
164
- <CarouselContext.Provider
165
- value={{
166
- emblaMainApi,
167
- mainRef: emblaMainRef,
168
- thumbsRef: emblaThumbsRef,
169
- scrollNext: ScrollNext,
170
- scrollPrev: ScrollPrev,
171
- canScrollNext,
172
- canScrollPrev,
173
- activeIndex,
174
- onThumbClick,
175
- handleKeyDown,
176
- carouselOptions,
177
- direction,
178
- orientation: orientation || (carouselOptions?.axis === 'y' ? 'vertical' : 'horizontal'),
179
- }}
180
- >
181
- <div
182
- {...props}
183
- // tabIndex={0}
184
- ref={ref}
185
- onKeyDownCapture={handleKeyDown}
186
- className={cn('grid gap-2 w-full relative focus:outline-none', className)}
187
- dir={direction}
188
- >
189
- {children}
190
- </div>
191
- </CarouselContext.Provider>
192
- );
193
- },
194
- );
195
-
196
- Carousel.displayName = 'Carousel';
197
-
198
- const CarouselMainContainer = forwardRef<HTMLDivElement, {
199
- } & React.HTMLAttributes<HTMLDivElement>>(
200
- ({ className, children, ...props }, ref) => {
201
- const { mainRef, orientation, direction } = useCarousel();
202
-
203
- return (
204
- <div {...props} ref={mainRef} className="overflow-hidden" dir={direction}>
205
- <div
206
- ref={ref}
207
- className={cn('flex', `${orientation === 'vertical' ? 'flex-col' : ''}`, className)}
208
- >
209
- {children}
210
- </div>
211
- </div>
212
- );
213
- },
214
- );
215
-
216
- CarouselMainContainer.displayName = 'CarouselMainContainer';
217
-
218
- const CarouselThumbsContainer = forwardRef<
219
- HTMLDivElement,
220
- {} & React.HTMLAttributes<HTMLDivElement>
221
- >(({ className, children, ...props }, ref) => {
222
- const { thumbsRef, orientation, direction } = useCarousel();
223
-
224
- return (
225
- <div {...props} ref={thumbsRef} className="overflow-hidden" dir={direction}>
226
- <div
227
- ref={ref}
228
- className={cn('flex', `${orientation === 'vertical' ? 'flex-col' : ''}`, className)}
229
- >
230
- {children}
231
- </div>
232
- </div>
233
- );
234
- });
235
-
236
- CarouselThumbsContainer.displayName = 'CarouselThumbsContainer';
237
-
238
- const SliderMainItem = forwardRef<HTMLDivElement, {} & React.HTMLAttributes<HTMLDivElement>>(
239
- ({ className, children, ...props }, ref) => {
240
- const { orientation } = useCarousel();
241
- return (
242
- <div
243
- {...props}
244
- ref={ref}
245
- className={cn(
246
- `min-w-0 shrink-0 grow-0 basis-full bg-background p-1 ${
247
- orientation === 'vertical' ? 'pb-1' : 'pr-1'
248
- }`,
249
- className,
250
- )}
251
- >
252
- {children}
253
- </div>
254
- );
255
- },
256
- );
257
-
258
- SliderMainItem.displayName = 'SliderMainItem';
259
-
260
- const SliderThumbItem = forwardRef<
261
- HTMLDivElement,
262
- {
263
- index: number;
264
- } & React.HTMLAttributes<HTMLDivElement>
265
- >(({ className, index, children, ...props }, ref) => {
266
- const { activeIndex, onThumbClick, orientation } = useCarousel();
267
- const isSlideActive = activeIndex === index;
268
- return (
269
- <div
270
- {...props}
271
- ref={ref}
272
- onClick={() => onThumbClick(index)}
273
- className={cn(
274
- 'flex min-w-0 shrink-0 grow-0 basis-1/3 bg-background p-1',
275
- `${orientation === 'vertical' ? 'pb-1' : 'pr-1'}`,
276
- className,
277
- )}
278
- >
279
- <div
280
- className={`relative aspect-square h-20 w-full opacity-50 rounded-md transition-opacity ${
281
- isSlideActive ? '!opacity-100' : ''
282
- }`}
283
- >
284
- {children}
285
- </div>
286
- </div>
287
- );
288
- });
289
-
290
- SliderThumbItem.displayName = 'SliderThumbItem';
291
-
292
- const CarouselIndicator = forwardRef<
293
- HTMLButtonElement,
294
- { index: number } & React.ComponentProps<typeof Button>
295
- >(({ className, index, children, ...props }, ref) => {
296
- const { activeIndex, onThumbClick } = useCarousel();
297
- const isSlideActive = activeIndex === index;
298
- return (
299
- <Button
300
- ref={ref}
301
- size="icon"
302
- className={cn(
303
- 'h-1 w-6 rounded-full',
304
- "data-[active='false']:bg-primary/50 data-[active='true']:bg-primary",
305
- className,
306
- )}
307
- data-active={isSlideActive}
308
- onClick={() => onThumbClick(index)}
309
- {...props}
310
- >
311
- <span className="sr-only">slide {index + 1} </span>
312
- </Button>
313
- );
314
- });
315
-
316
- CarouselIndicator.displayName = 'CarouselIndicator';
317
-
318
- const CarouselPrevious = forwardRef<HTMLButtonElement, React.ComponentProps<typeof Button>>(
319
- ({ className, dir, variant = 'outline', size = 'icon', ...props }, ref) => {
320
- const { canScrollNext, canScrollPrev, scrollNext, scrollPrev, orientation, direction } =
321
- useCarousel();
322
-
323
- const scroll = direction === 'rtl' ? scrollNext : scrollPrev;
324
- const canScroll = direction === 'rtl' ? canScrollNext : canScrollPrev;
325
- return (
326
- <Button
327
- type="button"
328
- ref={ref}
329
- variant={variant}
330
- size={size}
331
- className={cn(
332
- 'absolute h-6 w-6 rounded-full z-10',
333
- orientation === 'vertical'
334
- ? '-top-2 left-1/2 -translate-x-1/2 rotate-90'
335
- : '-left-2 top-1/2 -translate-y-1/2',
336
- className,
337
- )}
338
- onClick={scroll}
339
- disabled={!canScroll}
340
- {...props}
341
- >
342
- <ChevronLeftIcon className="h-4 w-4" />
343
- <span className="sr-only">Previous slide</span>
344
- </Button>
345
- );
346
- },
347
- );
348
- CarouselPrevious.displayName = 'CarouselPrevious';
349
-
350
- const CarouselNext = forwardRef<HTMLButtonElement, React.ComponentProps<typeof Button>>(
351
- ({ className, dir, variant = 'outline', size = 'icon', ...props }, ref) => {
352
- const { canScrollNext, canScrollPrev, scrollNext, scrollPrev, orientation, direction } =
353
- useCarousel();
354
- const scroll = direction === 'rtl' ? scrollPrev : scrollNext;
355
- const canScroll = direction === 'rtl' ? canScrollPrev : canScrollNext;
356
- return (
357
- <Button
358
- type="button"
359
- ref={ref}
360
- variant={variant}
361
- size={size}
362
- className={cn(
363
- 'absolute h-6 w-6 rounded-full z-10',
364
- orientation === 'vertical'
365
- ? '-bottom-2 left-1/2 -translate-x-1/2 rotate-90'
366
- : '-right-2 top-1/2 -translate-y-1/2',
367
- className,
368
- )}
369
- onClick={scroll}
370
- disabled={!canScroll}
371
- {...props}
372
- >
373
- <ChevronRightIcon className="h-4 w-4" />
374
- <span className="sr-only">Next slide</span>
375
- </Button>
376
- );
377
- },
378
- );
379
-
380
- CarouselNext.displayName = 'CarouselNext';
381
-
382
- export {
383
- Carousel,
384
- CarouselMainContainer,
385
- CarouselThumbsContainer,
386
- SliderMainItem,
387
- SliderThumbItem,
388
- CarouselIndicator,
389
- CarouselPrevious,
390
- CarouselNext,
391
- useCarousel,
392
- };
@@ -1,51 +0,0 @@
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
- }
@@ -1,19 +0,0 @@
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
- }
@@ -1,242 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { type ClassValue, clsx } from "clsx";
3
- import {
4
- differenceInDays,
5
- differenceInYears,
6
- format,
7
- formatDistance,
8
- isThisWeek,
9
- isToday,
10
- isYesterday,
11
- parseISO,
12
- } from "date-fns";
13
- import { twMerge } from "tailwind-merge";
14
-
15
- import type { Store } from "../util/storage";
16
-
17
- export function cn(...inputs: ClassValue[]) {
18
- return twMerge(clsx(inputs));
19
- }
20
-
21
- // function isFileArray(value: any): value is File[] {
22
- // return Array.isArray(value) && value.every(item => item instanceof File);
23
- // }
24
-
25
- export function getFormData(object: {
26
- [key: string]: undefined | string | number | boolean | Blob | File | object | File[];
27
- }): FormData {
28
- const formData = new FormData();
29
- Object.entries(object).forEach(([key, value]) => {
30
- if (value instanceof Blob || value instanceof File) {
31
- formData.append(key, value);
32
- } else if (value instanceof FileList || (Array.isArray(value) && value[0] instanceof File)) {
33
- Array.from(value).forEach((file: File) => {
34
- formData.append(key, file);
35
- });
36
- } else {
37
- if (!value) return;
38
- formData.append(key, JSON.stringify(value));
39
- }
40
- });
41
- return formData;
42
- }
43
-
44
- export function switchPath(pathname: string, tab: string) {
45
- const fragments = pathname.split("/").filter(str => str);
46
- fragments[2] = tab;
47
- const path = `/${fragments.join("/")}`;
48
- return path;
49
- }
50
-
51
- export function getRelativeDate(date?: string | Date) {
52
- const now = new Date();
53
- if (!date) return "";
54
- if (isToday(date)) {
55
- return format(date, "h:mm a");
56
- } else if (isYesterday(date)) {
57
- return "yesterday";
58
- } else if (isThisWeek(date) && differenceInDays(now, date) <= 7) {
59
- return format(date, "EEEE"); // EEEE gives the full name of the day like Sunday, Monday
60
- } else {
61
- return format(date, "dd/MM/yy");
62
- }
63
- }
64
-
65
- export function getRelativeDateWithTime(date?: string | Date) {
66
- const now = new Date();
67
- if (!date) return "";
68
- return formatDistance(new Date(date), now, { addSuffix: true });
69
- }
70
-
71
- export function getRelativeProDate(dateString: string) {
72
- try {
73
- const date = parseISO(dateString);
74
- const now = new Date();
75
- const yearsDifference = differenceInYears(now, date);
76
- const dateFormat = yearsDifference >= 1 ? "dd MMM yyyy, h:mm a" : "dd MMM, h:mm a";
77
- const formattedDate = format(date, dateFormat);
78
- return formattedDate;
79
- } catch (error) {
80
- console.error("Error formatting date:", error);
81
- return "";
82
- }
83
- }
84
- export function isValidId(str: string) {
85
- const regex = /^[a-f0-9]{24}$/i;
86
- return regex.test(str);
87
- }
88
-
89
- export function getRelativeDateOnly(date?: string | Date) {
90
- const now = new Date();
91
- if (!date) return "";
92
- if (isToday(date)) {
93
- return "today";
94
- } else if (isYesterday(date)) {
95
- return "yesterday";
96
- } else if (isThisWeek(date) && differenceInDays(now, date) <= 7) {
97
- return format(date, "EEEE"); // EEEE gives the full name of the day like Sunday, Monday
98
- } else {
99
- return format(date, "dd/MM/yy");
100
- }
101
- }
102
- export type SocialMediaUrlMetaData = {
103
- platform: "youtube" | "x" | "instagram";
104
- url: string;
105
- contentId: string;
106
- };
107
- export function getUrlMetaData(urlString: string): SocialMediaUrlMetaData | null {
108
- const url = new URL(urlString);
109
- let contentId: string;
110
- let platform: "youtube" | "x" | "instagram";
111
- switch (url.origin) {
112
- case "https://youtu.be":
113
- platform = "youtube";
114
- contentId = url.pathname.replace("/", "");
115
- break;
116
- case "https://www.youtube.com":
117
- platform = "youtube";
118
- contentId = url.searchParams.get("v") as string;
119
- break;
120
- case "https://x.com":
121
- platform = "x";
122
- contentId = url.pathname
123
- .split("/")
124
- .filter(str => str)
125
- .at(-1) as string;
126
- break;
127
- case "https://www.instagram.com":
128
- platform = "instagram";
129
- contentId = url.pathname
130
- .split("/")
131
- .filter(str => str)
132
- .at(-1) as string;
133
- break;
134
- case "https://instagram.com":
135
- platform = "instagram";
136
- contentId = url.pathname
137
- .split("/")
138
- .filter(str => str)
139
- .at(-1) as string;
140
- break;
141
- default:
142
- return null;
143
- }
144
- return {
145
- platform,
146
- url: urlString,
147
- contentId,
148
- };
149
- }
150
-
151
- export function isValidUrl(url: string) {
152
- try {
153
- const origin = new URL(url).origin;
154
- return true;
155
- } catch (error) {
156
- return false;
157
- }
158
- }
159
-
160
- export function memoize<T extends (...args: any[]) => any>(fn: T): T {
161
- const cache: { [key: string]: ReturnType<T> } = {};
162
-
163
- return ((...args: Parameters<T>): ReturnType<T> => {
164
- const key = JSON.stringify(args);
165
- if (cache[key] !== undefined) {
166
- return cache[key];
167
- } else {
168
- const result = fn(...args);
169
- cache[key] = result;
170
- return result;
171
- }
172
- }) as T;
173
- }
174
-
175
- export function memoizeAsync<T extends (...args: any[]) => Promise<any>>(fn: T): T {
176
- const cache: { [key: string]: ReturnType<T> } = {};
177
-
178
- return (async (...args: Parameters<T>): Promise<ReturnType<T>> => {
179
- const key = JSON.stringify(args);
180
- if (cache[key] !== undefined) {
181
- return await cache[key];
182
- } else {
183
- const result = await fn(...args);
184
- cache[key] = result;
185
- return result;
186
- }
187
- }) as T;
188
- }
189
- export function memoizePersistentAsync<T extends (...args: any[]) => Promise<any>>(
190
- fn: T,
191
- store: Store
192
- ): T {
193
- return (async (...args: Parameters<T>): Promise<ReturnType<T>> => {
194
- const key = JSON.stringify(args);
195
- const cachedValue = store.get(key);
196
- if (cachedValue !== null) {
197
- try {
198
- return JSON.parse(cachedValue);
199
- } catch (error) {
200
- console.error("Error parsing cached value:", error);
201
- return await fn(...args);
202
- }
203
- } else {
204
- const result = await fn(...args);
205
- store.set(key, JSON.stringify(result));
206
- return result;
207
- }
208
- }) as T;
209
- }
210
-
211
- export function formatNumberWithKMB(num: number): string {
212
- const formatter = new Intl.NumberFormat("en-US", {
213
- notation: "compact",
214
- minimumSignificantDigits: 1,
215
- maximumSignificantDigits: 3,
216
- });
217
-
218
- return formatter.format(num);
219
- }
220
- export function currencyToNumber(formattedCurrency: string): number {
221
- // Remove everything except digits, minus sign, and decimal point
222
- const numericString = formattedCurrency.replace(/[^0-9.-]+/g, "");
223
-
224
- // Convert the string back to a number
225
- const parsedNumber = Number.parseFloat(numericString);
226
-
227
- // Handle potential NaN if parsing fails
228
- if (isNaN(parsedNumber)) {
229
- throw new Error("Invalid currency format");
230
- }
231
-
232
- return parsedNumber;
233
- }
234
-
235
- export function createLabels(e: string) {
236
- return e
237
- .replaceAll("_", " ")
238
- .replace(/\b\w/g, char => char.toUpperCase())
239
- .trim();
240
- }
241
-
242
- export { cva, type VariantProps } from "class-variance-authority";