@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.
- package/.checksum +1 -0
- package/README.md +46 -0
- package/components.json +20 -0
- package/eslint.config.mjs +20 -0
- package/jsr.json +10 -0
- package/package.json +120 -0
- package/postcss.config.mjs +8 -0
- package/rollup.config.js +40 -0
- package/src/components/ui/accordion.tsx +70 -0
- package/src/components/ui/alert-dialog.tsx +156 -0
- package/src/components/ui/alert.tsx +58 -0
- package/src/components/ui/aspect-ratio.tsx +11 -0
- package/src/components/ui/avatar.tsx +52 -0
- package/src/components/ui/badge.tsx +49 -0
- package/src/components/ui/breadcrumb.tsx +108 -0
- package/src/components/ui/button.tsx +61 -0
- package/src/components/ui/calendar.tsx +212 -0
- package/src/components/ui/card.tsx +74 -0
- package/src/components/ui/carousel.tsx +240 -0
- package/src/components/ui/chart.tsx +365 -0
- package/src/components/ui/checkbox.tsx +31 -0
- package/src/components/ui/codeblock.tsx +161 -0
- package/src/components/ui/collapsible.tsx +33 -0
- package/src/components/ui/color-picker.tsx +143 -0
- package/src/components/ui/command.tsx +176 -0
- package/src/components/ui/context-menu.tsx +251 -0
- package/src/components/ui/custom/autosize-textarea.tsx +111 -0
- package/src/components/ui/custom/calendar/core.tsx +61 -0
- package/src/components/ui/custom/calendar/day-cell.tsx +74 -0
- package/src/components/ui/custom/calendar/month-header.tsx +59 -0
- package/src/components/ui/custom/calendar/month-view.tsx +110 -0
- package/src/components/ui/custom/calendar/utils.ts +76 -0
- package/src/components/ui/custom/calendar/year-calendar.tsx +64 -0
- package/src/components/ui/custom/calendar/year-view.tsx +58 -0
- package/src/components/ui/custom/combobox.tsx +197 -0
- package/src/components/ui/custom/common-footer.tsx +215 -0
- package/src/components/ui/custom/compared-date-range-picker.tsx +561 -0
- package/src/components/ui/custom/date-input.tsx +279 -0
- package/src/components/ui/custom/empty-card.tsx +39 -0
- package/src/components/ui/custom/feature-summary.tsx +135 -0
- package/src/components/ui/custom/file-uploader.tsx +349 -0
- package/src/components/ui/custom/input-field.tsx +29 -0
- package/src/components/ui/custom/loading-indicator.tsx +28 -0
- package/src/components/ui/custom/modifiable-dialog-trigger.tsx +83 -0
- package/src/components/ui/custom/month-picker.tsx +157 -0
- package/src/components/ui/custom/report-preview.tsx +175 -0
- package/src/components/ui/custom/search-bar.tsx +56 -0
- package/src/components/ui/custom/select-field.tsx +78 -0
- package/src/components/ui/custom/tables/data-table-column-header.tsx +72 -0
- package/src/components/ui/custom/tables/data-table-create-button.tsx +31 -0
- package/src/components/ui/custom/tables/data-table-faceted-filter.tsx +142 -0
- package/src/components/ui/custom/tables/data-table-pagination.tsx +243 -0
- package/src/components/ui/custom/tables/data-table-refresh-button.tsx +45 -0
- package/src/components/ui/custom/tables/data-table-toolbar.tsx +133 -0
- package/src/components/ui/custom/tables/data-table-view-options.tsx +112 -0
- package/src/components/ui/custom/tables/data-table.tsx +228 -0
- package/src/components/ui/custom/uploaded-files-card.tsx +50 -0
- package/src/components/ui/dialog.tsx +137 -0
- package/src/components/ui/drawer.tsx +131 -0
- package/src/components/ui/dropdown-menu.tsx +256 -0
- package/src/components/ui/form.tsx +167 -0
- package/src/components/ui/hover-card.tsx +41 -0
- package/src/components/ui/icons.tsx +506 -0
- package/src/components/ui/input-otp.tsx +78 -0
- package/src/components/ui/input.tsx +18 -0
- package/src/components/ui/label.tsx +23 -0
- package/src/components/ui/markdown.tsx +7 -0
- package/src/components/ui/menubar.tsx +275 -0
- package/src/components/ui/navigation-menu.tsx +169 -0
- package/src/components/ui/pagination.tsx +126 -0
- package/src/components/ui/popover.tsx +47 -0
- package/src/components/ui/progress.tsx +30 -0
- package/src/components/ui/radio-group.tsx +44 -0
- package/src/components/ui/resizable.tsx +55 -0
- package/src/components/ui/scroll-area.tsx +57 -0
- package/src/components/ui/select.tsx +180 -0
- package/src/components/ui/separator.tsx +27 -0
- package/src/components/ui/sheet.tsx +138 -0
- package/src/components/ui/sidebar.tsx +734 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/slider.tsx +62 -0
- package/src/components/ui/sonner.tsx +29 -0
- package/src/components/ui/switch.tsx +30 -0
- package/src/components/ui/table.tsx +112 -0
- package/src/components/ui/tabs.tsx +68 -0
- package/src/components/ui/tag-input.tsx +141 -0
- package/src/components/ui/textarea.tsx +17 -0
- package/src/components/ui/time-picker-input.tsx +117 -0
- package/src/components/ui/time-picker-utils.tsx +146 -0
- package/src/components/ui/toast.tsx +128 -0
- package/src/components/ui/toaster.tsx +35 -0
- package/src/components/ui/toggle-group.tsx +72 -0
- package/src/components/ui/toggle.tsx +46 -0
- package/src/components/ui/tooltip.tsx +60 -0
- package/src/globals.css +252 -0
- package/src/hooks/use-callback-ref.ts +28 -0
- package/src/hooks/use-controllable-state.ts +68 -0
- package/src/hooks/use-copy-to-clipboard.ts +46 -0
- package/src/hooks/use-form.ts +23 -0
- package/src/hooks/use-forwarded-ref.ts +17 -0
- package/src/hooks/use-mobile.tsx +21 -0
- package/src/hooks/use-toast.ts +191 -0
- package/src/resolvers.ts +3 -0
- 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
|
+
}
|