@tuturuuu/ui 0.0.4

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 (104) hide show
  1. package/.checksum +1 -0
  2. package/README.md +46 -0
  3. package/components.json +20 -0
  4. package/eslint.config.mjs +20 -0
  5. package/jsr.json +10 -0
  6. package/package.json +120 -0
  7. package/postcss.config.mjs +8 -0
  8. package/rollup.config.js +40 -0
  9. package/src/components/ui/accordion.tsx +70 -0
  10. package/src/components/ui/alert-dialog.tsx +156 -0
  11. package/src/components/ui/alert.tsx +58 -0
  12. package/src/components/ui/aspect-ratio.tsx +11 -0
  13. package/src/components/ui/avatar.tsx +52 -0
  14. package/src/components/ui/badge.tsx +49 -0
  15. package/src/components/ui/breadcrumb.tsx +108 -0
  16. package/src/components/ui/button.tsx +61 -0
  17. package/src/components/ui/calendar.tsx +212 -0
  18. package/src/components/ui/card.tsx +74 -0
  19. package/src/components/ui/carousel.tsx +240 -0
  20. package/src/components/ui/chart.tsx +365 -0
  21. package/src/components/ui/checkbox.tsx +31 -0
  22. package/src/components/ui/codeblock.tsx +161 -0
  23. package/src/components/ui/collapsible.tsx +33 -0
  24. package/src/components/ui/color-picker.tsx +143 -0
  25. package/src/components/ui/command.tsx +176 -0
  26. package/src/components/ui/context-menu.tsx +251 -0
  27. package/src/components/ui/custom/autosize-textarea.tsx +111 -0
  28. package/src/components/ui/custom/calendar/core.tsx +61 -0
  29. package/src/components/ui/custom/calendar/day-cell.tsx +74 -0
  30. package/src/components/ui/custom/calendar/month-header.tsx +59 -0
  31. package/src/components/ui/custom/calendar/month-view.tsx +110 -0
  32. package/src/components/ui/custom/calendar/utils.ts +76 -0
  33. package/src/components/ui/custom/calendar/year-calendar.tsx +64 -0
  34. package/src/components/ui/custom/calendar/year-view.tsx +58 -0
  35. package/src/components/ui/custom/combobox.tsx +197 -0
  36. package/src/components/ui/custom/common-footer.tsx +215 -0
  37. package/src/components/ui/custom/compared-date-range-picker.tsx +561 -0
  38. package/src/components/ui/custom/date-input.tsx +279 -0
  39. package/src/components/ui/custom/empty-card.tsx +39 -0
  40. package/src/components/ui/custom/feature-summary.tsx +135 -0
  41. package/src/components/ui/custom/file-uploader.tsx +349 -0
  42. package/src/components/ui/custom/input-field.tsx +29 -0
  43. package/src/components/ui/custom/loading-indicator.tsx +28 -0
  44. package/src/components/ui/custom/modifiable-dialog-trigger.tsx +83 -0
  45. package/src/components/ui/custom/month-picker.tsx +157 -0
  46. package/src/components/ui/custom/report-preview.tsx +175 -0
  47. package/src/components/ui/custom/search-bar.tsx +56 -0
  48. package/src/components/ui/custom/select-field.tsx +78 -0
  49. package/src/components/ui/custom/tables/data-table-column-header.tsx +72 -0
  50. package/src/components/ui/custom/tables/data-table-create-button.tsx +31 -0
  51. package/src/components/ui/custom/tables/data-table-faceted-filter.tsx +142 -0
  52. package/src/components/ui/custom/tables/data-table-pagination.tsx +243 -0
  53. package/src/components/ui/custom/tables/data-table-refresh-button.tsx +45 -0
  54. package/src/components/ui/custom/tables/data-table-toolbar.tsx +133 -0
  55. package/src/components/ui/custom/tables/data-table-view-options.tsx +112 -0
  56. package/src/components/ui/custom/tables/data-table.tsx +228 -0
  57. package/src/components/ui/custom/uploaded-files-card.tsx +50 -0
  58. package/src/components/ui/dialog.tsx +137 -0
  59. package/src/components/ui/drawer.tsx +131 -0
  60. package/src/components/ui/dropdown-menu.tsx +256 -0
  61. package/src/components/ui/form.tsx +167 -0
  62. package/src/components/ui/hover-card.tsx +41 -0
  63. package/src/components/ui/icons.tsx +506 -0
  64. package/src/components/ui/input-otp.tsx +78 -0
  65. package/src/components/ui/input.tsx +18 -0
  66. package/src/components/ui/label.tsx +23 -0
  67. package/src/components/ui/markdown.tsx +7 -0
  68. package/src/components/ui/menubar.tsx +275 -0
  69. package/src/components/ui/navigation-menu.tsx +169 -0
  70. package/src/components/ui/pagination.tsx +126 -0
  71. package/src/components/ui/popover.tsx +47 -0
  72. package/src/components/ui/progress.tsx +30 -0
  73. package/src/components/ui/radio-group.tsx +44 -0
  74. package/src/components/ui/resizable.tsx +55 -0
  75. package/src/components/ui/scroll-area.tsx +57 -0
  76. package/src/components/ui/select.tsx +180 -0
  77. package/src/components/ui/separator.tsx +27 -0
  78. package/src/components/ui/sheet.tsx +138 -0
  79. package/src/components/ui/sidebar.tsx +734 -0
  80. package/src/components/ui/skeleton.tsx +13 -0
  81. package/src/components/ui/slider.tsx +62 -0
  82. package/src/components/ui/sonner.tsx +29 -0
  83. package/src/components/ui/switch.tsx +30 -0
  84. package/src/components/ui/table.tsx +112 -0
  85. package/src/components/ui/tabs.tsx +68 -0
  86. package/src/components/ui/tag-input.tsx +141 -0
  87. package/src/components/ui/textarea.tsx +17 -0
  88. package/src/components/ui/time-picker-input.tsx +117 -0
  89. package/src/components/ui/time-picker-utils.tsx +146 -0
  90. package/src/components/ui/toast.tsx +128 -0
  91. package/src/components/ui/toaster.tsx +35 -0
  92. package/src/components/ui/toggle-group.tsx +72 -0
  93. package/src/components/ui/toggle.tsx +46 -0
  94. package/src/components/ui/tooltip.tsx +60 -0
  95. package/src/globals.css +252 -0
  96. package/src/hooks/use-callback-ref.ts +28 -0
  97. package/src/hooks/use-controllable-state.ts +68 -0
  98. package/src/hooks/use-copy-to-clipboard.ts +46 -0
  99. package/src/hooks/use-form.ts +23 -0
  100. package/src/hooks/use-forwarded-ref.ts +17 -0
  101. package/src/hooks/use-mobile.tsx +21 -0
  102. package/src/hooks/use-toast.ts +191 -0
  103. package/src/resolvers.ts +3 -0
  104. package/tsconfig.json +17 -0
@@ -0,0 +1,197 @@
1
+ 'use client';
2
+
3
+ import { Button } from '../button';
4
+ import {
5
+ Command,
6
+ CommandEmpty,
7
+ CommandGroup,
8
+ CommandInput,
9
+ CommandItem,
10
+ } from '../command';
11
+ import { Popover, PopoverContent, PopoverTrigger } from '../popover';
12
+ import { ScrollArea } from '../scroll-area';
13
+ import { Separator } from '../separator';
14
+ import { cn } from '@tuturuuu/utils/format';
15
+ import { CommandList } from 'cmdk';
16
+ import { Check, ChevronsUpDown, Plus } from 'lucide-react';
17
+ import * as React from 'react';
18
+
19
+ export type ComboboxOptions = {
20
+ value: string;
21
+ label: string;
22
+ };
23
+
24
+ type Mode = 'single' | 'multiple';
25
+
26
+ interface ComboboxProps {
27
+ t: any;
28
+ mode?: Mode;
29
+ options: ComboboxOptions[];
30
+ selected: string | string[]; // Updated to handle multiple selections
31
+ className?: string;
32
+ placeholder?: string;
33
+ label?: string;
34
+ disabled?: boolean;
35
+ useFirstValueAsDefault?: boolean;
36
+ // eslint-disable-next-line no-unused-vars
37
+ onChange?: (event: string | string[]) => void; // Updated to handle multiple selections
38
+ // eslint-disable-next-line no-unused-vars
39
+ onCreate?: (value: string) => void;
40
+ }
41
+
42
+ export function Combobox({
43
+ t,
44
+ options,
45
+ selected,
46
+ className,
47
+ placeholder,
48
+ mode = 'single',
49
+ label,
50
+ disabled,
51
+ useFirstValueAsDefault = false,
52
+ onChange,
53
+ onCreate,
54
+ }: ComboboxProps) {
55
+ const [open, setOpen] = React.useState(false);
56
+ const [query, setQuery] = React.useState<string>('');
57
+
58
+ React.useEffect(() => {
59
+ if (!open) {
60
+ setQuery('');
61
+ }
62
+ }, [open]);
63
+
64
+ React.useEffect(() => {
65
+ if (selected) return;
66
+ if (useFirstValueAsDefault && options.length > 0)
67
+ onChange?.(options?.[0]?.value ?? '');
68
+ }, [onChange, selected, options]);
69
+
70
+ return (
71
+ <div className={cn('block', className)}>
72
+ <Popover open={open} onOpenChange={setOpen}>
73
+ <PopoverTrigger asChild>
74
+ <Button
75
+ type="button"
76
+ variant="outline"
77
+ role="combobox"
78
+ aria-expanded={open}
79
+ className={cn(
80
+ 'w-full justify-between',
81
+ !selected && !selected.length && 'text-muted-foreground'
82
+ )}
83
+ disabled={disabled}
84
+ >
85
+ {label ??
86
+ (selected && selected.length > 0 ? (
87
+ <div className="relative mr-auto flex flex-grow flex-wrap items-center overflow-hidden">
88
+ <span>
89
+ {mode === 'multiple' && Array.isArray(selected)
90
+ ? selected
91
+ .map(
92
+ (selectedValue: string) =>
93
+ options.find(
94
+ (item) => item.value === selectedValue
95
+ )?.label
96
+ )
97
+ .join(', ')
98
+ : mode === 'single' &&
99
+ options.find((item) => item.value === selected)?.label}
100
+ </span>
101
+ </div>
102
+ ) : (
103
+ (placeholder ?? 'Select Item')
104
+ ))}
105
+ <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
106
+ </Button>
107
+ </PopoverTrigger>
108
+ <PopoverContent className="w-72 max-w-sm p-0">
109
+ <Command
110
+ filter={(value, search) => {
111
+ if (value.includes(search)) return 1;
112
+ return 0;
113
+ }}
114
+ >
115
+ <CommandInput
116
+ placeholder={placeholder ?? 'Search'}
117
+ value={query}
118
+ onValueChange={(value: string) => setQuery(value)}
119
+ />
120
+ <CommandEmpty className="flex flex-col items-center justify-center p-1">
121
+ <div className="p-8 text-sm text-muted-foreground">
122
+ {t('common.empty')}
123
+ </div>
124
+ {query && (
125
+ <>
126
+ <Separator />
127
+ <Button
128
+ variant="ghost"
129
+ className="mt-1 w-full"
130
+ onClick={() => {
131
+ if (onCreate) {
132
+ onCreate(query);
133
+ setQuery('');
134
+ }
135
+ }}
136
+ disabled={!query || !onCreate}
137
+ >
138
+ <Plus className="mr-2 h-4 w-4 shrink-0" />
139
+ <div className="w-full truncate">
140
+ <span className="font-normal">{t('common.add')}</span>{' '}
141
+ <span className="underline decoration-dashed underline-offset-2">
142
+ {query}
143
+ </span>
144
+ </div>
145
+ </Button>
146
+ </>
147
+ )}
148
+ </CommandEmpty>
149
+ <ScrollArea>
150
+ <div className="max-h-80">
151
+ <CommandList>
152
+ <CommandGroup>
153
+ {options.map((option) => (
154
+ <CommandItem
155
+ key={option.label}
156
+ value={option.label}
157
+ onSelect={() => {
158
+ if (onChange) {
159
+ if (
160
+ mode === 'multiple' &&
161
+ Array.isArray(selected)
162
+ ) {
163
+ onChange(
164
+ selected.includes(option.value)
165
+ ? selected.filter(
166
+ (item) => item !== option.value
167
+ )
168
+ : [...selected, option.value]
169
+ );
170
+ } else {
171
+ onChange(option.value);
172
+ }
173
+ }
174
+ setOpen(false);
175
+ }}
176
+ >
177
+ <Check
178
+ className={cn(
179
+ 'mr-2 h-4 w-4',
180
+ selected.includes(option.value)
181
+ ? 'opacity-100'
182
+ : 'opacity-0'
183
+ )}
184
+ />
185
+ {option.label}
186
+ </CommandItem>
187
+ ))}
188
+ </CommandGroup>
189
+ </CommandList>
190
+ </div>
191
+ </ScrollArea>
192
+ </Command>
193
+ </PopoverContent>
194
+ </Popover>
195
+ </div>
196
+ );
197
+ }
@@ -0,0 +1,215 @@
1
+ import { Separator } from '../separator';
2
+ import Image from 'next/image';
3
+ import Link from 'next/link';
4
+
5
+ export function CommonFooter({ t }: { t: any }) {
6
+ return (
7
+ <div className="w-full text-center">
8
+ {/* {pathname.startsWith('/contact') || (
9
+ <>
10
+ <Separator className="bg-foreground/5 mb-8" />
11
+ <div className="flex flex-col items-center">
12
+ <Slogan />
13
+ </div>
14
+ </>
15
+ )} */}
16
+
17
+ <Separator className="my-8 bg-foreground/5" />
18
+
19
+ <div className="flex flex-col flex-wrap items-center justify-between gap-4 px-4 md:gap-8 md:px-32 lg:flex-row lg:gap-16 xl:px-64">
20
+ <div className="flex flex-col items-center justify-center gap-4">
21
+ <Link
22
+ href="/"
23
+ className="flex items-center gap-4 transition"
24
+ aria-label="Tuturuuu"
25
+ >
26
+ <Image
27
+ src="/media/logos/transparent.png"
28
+ width={64}
29
+ height={64}
30
+ alt="logo"
31
+ className="h-12 w-12"
32
+ />
33
+ <div className="text-4xl font-semibold">Tuturuuu</div>
34
+ </Link>
35
+
36
+ <div className="flex gap-8">
37
+ <Link
38
+ href="https://www.facebook.com/tuturuuu"
39
+ className="fill-foreground/50 transition duration-300 hover:fill-foreground"
40
+ aria-label="Facebook"
41
+ >
42
+ <svg
43
+ xmlns="http://www.w3.org/2000/svg"
44
+ viewBox="0 0 512 512"
45
+ className="w-6"
46
+ >
47
+ <path d="M504 256C504 119 393 8 256 8S8 119 8 256c0 123.78 90.69 226.38 209.25 245V327.69h-63V256h63v-54.64c0-62.15 37-96.48 93.67-96.48 27.14 0 55.52 4.84 55.52 4.84v61h-31.28c-30.8 0-40.41 19.12-40.41 38.73V256h68.78l-11 71.69h-57.78V501C413.31 482.38 504 379.78 504 256z" />
48
+ </svg>
49
+ </Link>
50
+
51
+ <Link
52
+ href="https://x.com/tutur3u"
53
+ className="fill-foreground/50 transition duration-300 hover:fill-foreground"
54
+ aria-label="X (formerly Twitter)"
55
+ >
56
+ <svg
57
+ xmlns="http://www.w3.org/2000/svg"
58
+ viewBox="0 0 42 42"
59
+ className="w-6"
60
+ >
61
+ <polygon points="41,6 9.929,42 6.215,42 37.287,6" />
62
+ <polygon
63
+ className="fill-background"
64
+ fillRule="evenodd"
65
+ points="31.143,41 7.82,7 16.777,7 40.1,41"
66
+ clipRule="evenodd"
67
+ />
68
+ <path d="M15.724,9l20.578,30h-4.106L11.618,9H15.724 M17.304,6H5.922l24.694,36h11.382L17.304,6L17.304,6z" />
69
+ </svg>
70
+ </Link>
71
+
72
+ <Link
73
+ href="https://github.com/tutur3u"
74
+ className="fill-foreground/50 transition duration-300 hover:fill-foreground"
75
+ aria-label="Github"
76
+ >
77
+ <svg
78
+ xmlns="http://www.w3.org/2000/svg"
79
+ viewBox="0 0 512 512"
80
+ className="w-6"
81
+ >
82
+ <path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z" />
83
+ </svg>
84
+ </Link>
85
+
86
+ <Link
87
+ href="https://www.linkedin.com/company/tuturuuu/"
88
+ className="fill-foreground/50 transition duration-300 hover:fill-foreground"
89
+ aria-label="LinkedIn"
90
+ >
91
+ <svg
92
+ xmlns="http://www.w3.org/2000/svg"
93
+ viewBox="0 0 512 512"
94
+ className="w-6"
95
+ >
96
+ <path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z" />
97
+ </svg>
98
+ </Link>
99
+ </div>
100
+ </div>
101
+
102
+ <div className="flex flex-none flex-col flex-wrap items-center gap-4 md:flex-row md:items-start md:gap-16 lg:gap-32">
103
+ <div className="grid gap-1 md:items-start">
104
+ <div className="mb-2 text-lg font-bold md:w-fit md:text-xl">
105
+ {t('common.resources')}
106
+ </div>
107
+ <Link
108
+ href="https://tuturuuu.com/blog"
109
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
110
+ >
111
+ {t('common.blog')}
112
+ </Link>
113
+ <Link
114
+ href="https://tuturuuu.com/changelog"
115
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
116
+ >
117
+ {t('common.changelog')}
118
+ </Link>
119
+ <Link
120
+ href="https://tuturuuu.com/meet-together"
121
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
122
+ >
123
+ {t('common.meet-together')}
124
+ </Link>
125
+ <Link
126
+ href="https://tuturuuu.com/qr-generator"
127
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
128
+ >
129
+ {t('common.qr_generator')}
130
+ </Link>
131
+ <Link
132
+ href="https://tuturuuu.com/branding"
133
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
134
+ >
135
+ {t('common.branding')}
136
+ </Link>
137
+ </div>
138
+
139
+ <div className="grid gap-1 md:items-start">
140
+ <div className="mb-2 text-lg font-bold md:w-fit md:text-xl">
141
+ {t('common.company')}
142
+ </div>
143
+ <Link
144
+ href="https://tuturuuu.com/about"
145
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
146
+ >
147
+ {t('common.about')}
148
+ </Link>
149
+ <Link
150
+ href="https://tuturuuu.com/contact"
151
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
152
+ >
153
+ {t('common.contact')}
154
+ </Link>
155
+ <Link
156
+ href="https://tuturuuu.com/pricing"
157
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
158
+ >
159
+ {t('common.pricing')}
160
+ </Link>
161
+ </div>
162
+
163
+ <div className="grid gap-1 md:items-start">
164
+ <div className="mb-2 text-lg font-bold md:w-fit md:text-xl">
165
+ {t('common.legal')}
166
+ </div>
167
+ <Link
168
+ href="https://tuturuuu.com/security"
169
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
170
+ >
171
+ {t('common.security')}
172
+ </Link>
173
+ <Link
174
+ href="https://tuturuuu.com/terms"
175
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
176
+ >
177
+ {t('common.terms')}
178
+ </Link>
179
+ <Link
180
+ href="https://tuturuuu.com/privacy"
181
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
182
+ >
183
+ {t('common.privacy')}
184
+ </Link>
185
+ </div>
186
+
187
+ <div className="grid gap-1 md:items-start">
188
+ <div className="mb-2 text-lg font-bold md:w-fit md:text-xl">
189
+ {t('common.developers')}
190
+ </div>
191
+ <Link
192
+ href="https://docs.tuturuuu.com"
193
+ target="_blank"
194
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
195
+ >
196
+ {t('common.documentation')}
197
+ </Link>
198
+ <Link
199
+ href="https://github.com/tutur3u/platform"
200
+ target="_blank"
201
+ className="text-sm text-foreground/80 hover:text-foreground hover:underline md:w-fit"
202
+ >
203
+ {t('common.open-source')}
204
+ </Link>
205
+ </div>
206
+ </div>
207
+ </div>
208
+
209
+ <Separator className="mt-8 bg-foreground/5" />
210
+ <div className="p-4 text-center text-sm text-balance opacity-80 md:px-32 xl:px-64">
211
+ {t('common.copyright')}
212
+ </div>
213
+ </div>
214
+ );
215
+ }