@moontra/moonui-pro 2.2.2 → 2.2.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/dist/index.mjs +41089 -39395
- package/package.json +1 -2
- package/src/components/index.ts +4 -2
- package/src/components/internal/index.ts +78 -0
- package/src/components/ui/accordion.tsx +73 -0
- package/src/components/ui/alert.tsx +142 -0
- package/src/components/ui/aspect-ratio.tsx +81 -0
- package/src/components/ui/breadcrumb.tsx +221 -0
- package/src/components/ui/checkbox.tsx +2 -2
- package/src/components/ui/collapsible.tsx +135 -0
- package/src/components/ui/command.tsx +225 -0
- package/src/components/ui/dropdown-menu.tsx +18 -2
- package/src/components/ui/index.ts +157 -35
- package/src/components/ui/label.tsx +2 -2
- package/src/components/ui/pagination.tsx +122 -0
- package/src/components/ui/radio-group.tsx +261 -0
- package/src/components/ui/table.tsx +334 -0
- package/src/components/ui/toggle.tsx +56 -0
- package/src/utils/cn.ts +2 -65
- package/dist/index.d.ts +0 -850
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
|
|
6
|
+
export type SortDirection = "asc" | "desc" | null;
|
|
7
|
+
|
|
8
|
+
const MoonUItableVariantsPro = cva(
|
|
9
|
+
"w-full caption-bottom text-sm",
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
default: "dark:text-gray-200",
|
|
14
|
+
bordered: "border border-border dark:border-gray-700",
|
|
15
|
+
striped: "dark:text-gray-200",
|
|
16
|
+
card: "border border-border dark:border-gray-700 rounded-md shadow-sm dark:shadow-gray-900/20",
|
|
17
|
+
minimal: "border-none dark:text-gray-200",
|
|
18
|
+
},
|
|
19
|
+
size: {
|
|
20
|
+
sm: "text-xs",
|
|
21
|
+
default: "text-sm",
|
|
22
|
+
lg: "text-base",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: {
|
|
26
|
+
variant: "default",
|
|
27
|
+
size: "default",
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export interface ColumnDefinition<T> {
|
|
33
|
+
id: string;
|
|
34
|
+
header: React.ReactNode;
|
|
35
|
+
accessorKey?: keyof T;
|
|
36
|
+
cell?: (row: T) => React.ReactNode;
|
|
37
|
+
sortable?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface TableProps<T>
|
|
41
|
+
extends React.HTMLAttributes<HTMLTableElement>,
|
|
42
|
+
VariantProps<typeof MoonUItableVariantsPro> {
|
|
43
|
+
/** Veri yükleniyor durumunu gösterir */
|
|
44
|
+
loading?: boolean;
|
|
45
|
+
/** Sıralama için kullanılan sütun */
|
|
46
|
+
sortColumn?: string;
|
|
47
|
+
/** Sıralama yönü */
|
|
48
|
+
sortDirection?: SortDirection;
|
|
49
|
+
/** Sıralama değiştiğinde çağrılacak fonksiyon */
|
|
50
|
+
onSortChange?: (column: string, direction: SortDirection) => void;
|
|
51
|
+
/** Boş durum için özel içerik */
|
|
52
|
+
emptyContent?: React.ReactNode;
|
|
53
|
+
/** Seçili satır id'leri */
|
|
54
|
+
selectedRowIds?: string[];
|
|
55
|
+
/** Satır seçim değiştiğinde çağrılacak fonksiyon */
|
|
56
|
+
onRowSelectionChange?: (selectedRowIds: string[]) => void;
|
|
57
|
+
/** Satır seçim devre dışı */
|
|
58
|
+
disableRowSelection?: boolean;
|
|
59
|
+
/** Her satır için benzersiz id çıkarma fonksiyonu */
|
|
60
|
+
getRowId?: (row: T) => string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Tip parametresiz Table bileşeni için varsayılan tip, herhangi bir veri tipini kabul edebilmesi için
|
|
64
|
+
const MoonUITablePro = React.forwardRef<
|
|
65
|
+
HTMLTableElement,
|
|
66
|
+
TableProps<unknown>
|
|
67
|
+
>(({
|
|
68
|
+
className,
|
|
69
|
+
variant,
|
|
70
|
+
size,
|
|
71
|
+
loading,
|
|
72
|
+
emptyContent,
|
|
73
|
+
// Kullanılmayan özellikleri yoruma alarak lint uyarılarını önlüyoruz
|
|
74
|
+
// sortColumn,
|
|
75
|
+
// sortDirection,
|
|
76
|
+
// onSortChange,
|
|
77
|
+
// selectedRowIds,
|
|
78
|
+
// onRowSelectionChange,
|
|
79
|
+
// disableRowSelection,
|
|
80
|
+
// getRowId,
|
|
81
|
+
...props
|
|
82
|
+
}, ref) => {
|
|
83
|
+
// Apply striped styles to the tbody via a class name
|
|
84
|
+
const MoonUIstripedPro = variant === "striped";
|
|
85
|
+
|
|
86
|
+
// Çocukları güvenli bir şekilde işle ve tip kontrollerini doğru yap
|
|
87
|
+
const MoonUIchildrenWithPropsPro = React.Children.map(props.children, (child) => {
|
|
88
|
+
if (React.isValidElement(child)) {
|
|
89
|
+
if (child.type === "tbody") {
|
|
90
|
+
// Tip güvenliği için props'ları düzgün şekilde ele alıyoruz
|
|
91
|
+
const MoonUItbodyPropsPro = child.props as Record<string, unknown>;
|
|
92
|
+
return React.cloneElement(child as React.ReactElement<React.HTMLAttributes<HTMLTableSectionElement>>, {
|
|
93
|
+
className: cn(tbodyProps.className as string | undefined, striped && "even:[&>tr]:bg-muted/50")
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return child;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div className="relative w-full overflow-auto">
|
|
102
|
+
{/* Yükleniyor durumu için overlay */}
|
|
103
|
+
{loading && (
|
|
104
|
+
<div className="absolute inset-0 bg-background/60 flex items-center justify-center z-10">
|
|
105
|
+
<div className="h-8 w-8 animate-spin rounded-full border-2 border-primary border-t-transparent"></div>
|
|
106
|
+
</div>
|
|
107
|
+
)}
|
|
108
|
+
|
|
109
|
+
<table
|
|
110
|
+
ref={ref}
|
|
111
|
+
className={cn(
|
|
112
|
+
MoonUItableVariantsPro({ variant, size }),
|
|
113
|
+
loading && "opacity-70",
|
|
114
|
+
className
|
|
115
|
+
)}
|
|
116
|
+
{...props}
|
|
117
|
+
>
|
|
118
|
+
{childrenWithProps}
|
|
119
|
+
</table>
|
|
120
|
+
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
MoonUITablePro.displayName = "TablePro";
|
|
125
|
+
|
|
126
|
+
const MoonUITableHeaderPro = React.forwardRef<
|
|
127
|
+
HTMLTableSectionElement,
|
|
128
|
+
React.HTMLAttributes<HTMLTableSectionElement>
|
|
129
|
+
>(({ className, ...props }, ref) => (
|
|
130
|
+
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
|
131
|
+
));
|
|
132
|
+
MoonUITableHeaderPro.displayName = "TableHeaderPro";
|
|
133
|
+
|
|
134
|
+
interface TableBodyProps extends React.HTMLAttributes<HTMLTableSectionElement> {
|
|
135
|
+
/** Veri yoksa gösterilecek boş durum içeriği */
|
|
136
|
+
emptyContent?: React.ReactNode;
|
|
137
|
+
/** Varsayılan boş durum mesajı */
|
|
138
|
+
emptyMessage?: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const MoonUITableBodyPro = React.forwardRef<
|
|
142
|
+
HTMLTableSectionElement,
|
|
143
|
+
TableBodyProps
|
|
144
|
+
>(({ className, emptyContent, emptyMessage = "No data available", children, ...props }, ref) => {
|
|
145
|
+
// Çocuk elementlerin varlığını kontrol et
|
|
146
|
+
const MoonUIhasChildrenPro = React.Children.count(children) > 0;
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<tbody
|
|
150
|
+
ref={ref}
|
|
151
|
+
className={cn("[&_tr:last-child]:border-0", className)}
|
|
152
|
+
{...props}
|
|
153
|
+
>
|
|
154
|
+
{hasChildren ? (
|
|
155
|
+
children
|
|
156
|
+
) : (
|
|
157
|
+
<tr>
|
|
158
|
+
<td colSpan={100} className="h-24 text-center">
|
|
159
|
+
{emptyContent || (
|
|
160
|
+
<div className="py-6 text-muted-foreground">
|
|
161
|
+
<div className="text-sm">
|
|
162
|
+
{emptyMessage}
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
)}
|
|
166
|
+
</td>
|
|
167
|
+
</tr>
|
|
168
|
+
)}
|
|
169
|
+
</tbody>
|
|
170
|
+
)
|
|
171
|
+
});
|
|
172
|
+
MoonUITableBodyPro.displayName = "TableBodyPro";
|
|
173
|
+
|
|
174
|
+
const MoonUITableFooterPro = React.forwardRef<
|
|
175
|
+
HTMLTableSectionElement,
|
|
176
|
+
React.HTMLAttributes<HTMLTableSectionElement>
|
|
177
|
+
>(({ className, ...props }, ref) => (
|
|
178
|
+
<tfoot
|
|
179
|
+
ref={ref}
|
|
180
|
+
className={cn("bg-primary text-primary-foreground font-medium", className)}
|
|
181
|
+
{...props}
|
|
182
|
+
/>
|
|
183
|
+
));
|
|
184
|
+
MoonUITableFooterPro.displayName = "TableFooterPro";
|
|
185
|
+
|
|
186
|
+
const MoonUITableRowPro = React.forwardRef<
|
|
187
|
+
HTMLTableRowElement,
|
|
188
|
+
React.HTMLAttributes<HTMLTableRowElement>
|
|
189
|
+
>(({ className, ...props }, ref) => (
|
|
190
|
+
<tr
|
|
191
|
+
ref={ref}
|
|
192
|
+
className={cn(
|
|
193
|
+
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
|
194
|
+
className
|
|
195
|
+
)}
|
|
196
|
+
{...props}
|
|
197
|
+
/>
|
|
198
|
+
));
|
|
199
|
+
MoonUITableRowPro.displayName = "TableRowPro";
|
|
200
|
+
|
|
201
|
+
interface TableHeadProps extends React.ThHTMLAttributes<HTMLTableCellElement> {
|
|
202
|
+
/** Bu sütun için sıralama durumu */
|
|
203
|
+
sortable?: boolean;
|
|
204
|
+
/** Bu sütunun sıralanma durumu */
|
|
205
|
+
sorted?: SortDirection;
|
|
206
|
+
/** Sıralama değiştiğinde çağrılacak fonksiyon */
|
|
207
|
+
onSort?: () => void;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const MoonUITableHeadPro = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
|
|
211
|
+
({ className, sortable, sorted, onSort, children, ...props }, ref) => {
|
|
212
|
+
// Sıralama için simgeler
|
|
213
|
+
const MoonUIrenderSortIconPro = () => {
|
|
214
|
+
if (!sortable) return null;
|
|
215
|
+
|
|
216
|
+
if (sorted === "asc") {
|
|
217
|
+
return (
|
|
218
|
+
<svg
|
|
219
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
220
|
+
className="ml-1 h-4 w-4 inline-block"
|
|
221
|
+
viewBox="0 0 20 20"
|
|
222
|
+
fill="currentColor"
|
|
223
|
+
>
|
|
224
|
+
<path
|
|
225
|
+
fillRule="evenodd"
|
|
226
|
+
d="M14.707 10.293a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L9 12.586V5a1 1 0 012 0v7.586l2.293-2.293a1 1 0 011.414 0z"
|
|
227
|
+
clipRule="evenodd"
|
|
228
|
+
/>
|
|
229
|
+
</svg>
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (sorted === "desc") {
|
|
234
|
+
return (
|
|
235
|
+
<svg
|
|
236
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
237
|
+
className="ml-1 h-4 w-4 inline-block"
|
|
238
|
+
viewBox="0 0 20 20"
|
|
239
|
+
fill="currentColor"
|
|
240
|
+
>
|
|
241
|
+
<path
|
|
242
|
+
fillRule="evenodd"
|
|
243
|
+
d="M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L11 7.414V15a1 1 0 11-2 0V7.414L6.707 9.707a1 1 0 01-1.414 0z"
|
|
244
|
+
clipRule="evenodd"
|
|
245
|
+
/>
|
|
246
|
+
</svg>
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<svg
|
|
252
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
253
|
+
className="ml-1 h-4 w-4 inline-block opacity-30"
|
|
254
|
+
viewBox="0 0 20 20"
|
|
255
|
+
fill="currentColor"
|
|
256
|
+
>
|
|
257
|
+
<path
|
|
258
|
+
fillRule="evenodd"
|
|
259
|
+
d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z"
|
|
260
|
+
clipRule="evenodd"
|
|
261
|
+
/>
|
|
262
|
+
</svg>
|
|
263
|
+
);
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
return (
|
|
267
|
+
<th
|
|
268
|
+
ref={ref}
|
|
269
|
+
className={cn(
|
|
270
|
+
"h-10 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
|
271
|
+
sortable && "cursor-pointer hover:text-foreground select-none",
|
|
272
|
+
className
|
|
273
|
+
)}
|
|
274
|
+
onClick={sortable ? onSort : undefined}
|
|
275
|
+
{...props}
|
|
276
|
+
>
|
|
277
|
+
<div className="flex items-center">
|
|
278
|
+
{children}
|
|
279
|
+
{sortable && renderSortIcon()}
|
|
280
|
+
</div>
|
|
281
|
+
</th>
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
MoonUITableHeadPro.displayName = "TableHeadPro";
|
|
286
|
+
|
|
287
|
+
const MoonUITableCellPro = React.forwardRef<
|
|
288
|
+
HTMLTableCellElement,
|
|
289
|
+
React.TdHTMLAttributes<HTMLTableCellElement>
|
|
290
|
+
>(({ className, ...props }, ref) => (
|
|
291
|
+
<td
|
|
292
|
+
ref={ref}
|
|
293
|
+
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
|
294
|
+
{...props}
|
|
295
|
+
/>
|
|
296
|
+
));
|
|
297
|
+
MoonUITableCellPro.displayName = "TableCellPro";
|
|
298
|
+
|
|
299
|
+
const MoonUITableCaptionPro = React.forwardRef<
|
|
300
|
+
HTMLTableCaptionElement,
|
|
301
|
+
React.HTMLAttributes<HTMLTableCaptionElement>
|
|
302
|
+
>(({ className, ...props }, ref) => (
|
|
303
|
+
<caption
|
|
304
|
+
ref={ref}
|
|
305
|
+
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
|
306
|
+
{...props}
|
|
307
|
+
/>
|
|
308
|
+
));
|
|
309
|
+
MoonUITableCaptionPro.displayName = "TableCaptionPro";
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
// Internal aliases for Pro component usage
|
|
313
|
+
export const tableVariantsInternal = MoonUItableVariantsPro
|
|
314
|
+
export const TableInternal = MoonUITablePro
|
|
315
|
+
export const stripedInternal = MoonUIstripedPro
|
|
316
|
+
export const childrenWithPropsInternal = MoonUIchildrenWithPropsPro
|
|
317
|
+
export const tbodyPropsInternal = MoonUItbodyPropsPro
|
|
318
|
+
export const TableHeaderInternal = MoonUITableHeaderPro
|
|
319
|
+
export const TableBodyInternal = MoonUITableBodyPro
|
|
320
|
+
export const hasChildrenInternal = MoonUIhasChildrenPro
|
|
321
|
+
export const TableFooterInternal = MoonUITableFooterPro
|
|
322
|
+
export const TableRowInternal = MoonUITableRowPro
|
|
323
|
+
export const TableHeadInternal = MoonUITableHeadPro
|
|
324
|
+
export const renderSortIconInternal = MoonUIrenderSortIconPro
|
|
325
|
+
export const TableCellInternal = MoonUITableCellPro
|
|
326
|
+
export const TableCaptionInternal = MoonUITableCaptionPro
|
|
327
|
+
|
|
328
|
+
// Pro exports
|
|
329
|
+
export { MoonUItableVariantsPro, MoonUITablePro, MoonUIstripedPro, MoonUIchildrenWithPropsPro, MoonUItbodyPropsPro, MoonUITableHeaderPro, MoonUITableBodyPro, MoonUIhasChildrenPro, MoonUITableFooterPro, MoonUITableRowPro, MoonUITableHeadPro, MoonUIrenderSortIconPro, MoonUITableCellPro, MoonUITableCaptionPro }
|
|
330
|
+
|
|
331
|
+
// Clean exports (without MoonUI prefix for easier usage)
|
|
332
|
+
export { MoonUItableVariantsPro as tableVariants, MoonUITablePro as Table, MoonUIstripedPro as striped, MoonUIchildrenWithPropsPro as childrenWithProps, MoonUItbodyPropsPro as tbodyProps, MoonUITableHeaderPro as TableHeader, MoonUITableBodyPro as TableBody, MoonUIhasChildrenPro as hasChildren, MoonUITableFooterPro as TableFooter, MoonUITableRowPro as TableRow, MoonUITableHeadPro as TableHead, MoonUIrenderSortIconPro as renderSortIcon, MoonUITableCellPro as TableCell, MoonUITableCaptionPro as TableCaption };
|
|
333
|
+
|
|
334
|
+
export type { TableBodyProps };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as TogglePrimitive from "@radix-ui/react-toggle"
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
6
|
+
|
|
7
|
+
import { cn } from "../../lib/utils"
|
|
8
|
+
|
|
9
|
+
const MoonUItoggleVariantsPro = cva(
|
|
10
|
+
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
|
|
11
|
+
{
|
|
12
|
+
variants: {
|
|
13
|
+
variant: {
|
|
14
|
+
default: "bg-transparent",
|
|
15
|
+
outline:
|
|
16
|
+
"border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
|
|
17
|
+
},
|
|
18
|
+
size: {
|
|
19
|
+
default: "h-10 px-3",
|
|
20
|
+
sm: "h-9 px-2.5",
|
|
21
|
+
lg: "h-11 px-5",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
variant: "default",
|
|
26
|
+
size: "default",
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
export interface ToggleProps extends React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root>, VariantProps<typeof MoonUItoggleVariantsPro> {}
|
|
32
|
+
|
|
33
|
+
const MoonUITogglePro = React.forwardRef<
|
|
34
|
+
React.ElementRef<typeof TogglePrimitive.Root>,
|
|
35
|
+
ToggleProps
|
|
36
|
+
>(({ className, variant, size, ...props }, ref) => (
|
|
37
|
+
<TogglePrimitive.Root
|
|
38
|
+
ref={ref}
|
|
39
|
+
className={cn(MoonUItoggleVariantsPro({ variant, size, className }))}
|
|
40
|
+
{...props}
|
|
41
|
+
/>
|
|
42
|
+
))
|
|
43
|
+
|
|
44
|
+
MoonUITogglePro.displayName = TogglePrimitive.Root.displayName
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
// Internal aliases for Pro component usage
|
|
48
|
+
export const toggleVariantsInternal = MoonUItoggleVariantsPro
|
|
49
|
+
export const ToggleInternal = MoonUITogglePro
|
|
50
|
+
|
|
51
|
+
// Pro exports
|
|
52
|
+
export { MoonUItoggleVariantsPro, MoonUITogglePro }
|
|
53
|
+
|
|
54
|
+
// Clean exports (without MoonUI prefix for easier usage)
|
|
55
|
+
export { MoonUItoggleVariantsPro as toggleVariants, MoonUITogglePro as Toggle }
|
|
56
|
+
export type { ToggleProps }
|
package/src/utils/cn.ts
CHANGED
|
@@ -1,69 +1,6 @@
|
|
|
1
|
-
import { type ClassValue, clsx } from
|
|
2
|
-
import { twMerge } from
|
|
1
|
+
import { type ClassValue, clsx } from 'clsx';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
3
|
|
|
4
|
-
// Utility function using clsx and tailwind-merge
|
|
5
4
|
export function cn(...inputs: ClassValue[]) {
|
|
6
5
|
return twMerge(clsx(inputs));
|
|
7
6
|
}
|
|
8
|
-
|
|
9
|
-
// Date formatting utility
|
|
10
|
-
export function formatDate(date: Date): string {
|
|
11
|
-
if (isNaN(date.getTime())) {
|
|
12
|
-
return 'Invalid Date'
|
|
13
|
-
}
|
|
14
|
-
return date.toLocaleDateString('en-US', {
|
|
15
|
-
year: 'numeric',
|
|
16
|
-
month: 'short',
|
|
17
|
-
day: 'numeric'
|
|
18
|
-
})
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Currency formatting utility
|
|
22
|
-
export function formatCurrency(amount: number): string {
|
|
23
|
-
return new Intl.NumberFormat('en-US', {
|
|
24
|
-
style: 'currency',
|
|
25
|
-
currency: 'USD'
|
|
26
|
-
}).format(amount)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Text truncation utility
|
|
30
|
-
export function truncateText(text: string, maxLength: number): string {
|
|
31
|
-
if (text.length <= maxLength) {
|
|
32
|
-
return text
|
|
33
|
-
}
|
|
34
|
-
return text.slice(0, maxLength) + '...'
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// ID generation utility
|
|
38
|
-
export function generateId(length: number = 8): string {
|
|
39
|
-
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
40
|
-
let result = ''
|
|
41
|
-
for (let i = 0; i < length; i++) {
|
|
42
|
-
result += chars.charAt(Math.floor(Math.random() * chars.length))
|
|
43
|
-
}
|
|
44
|
-
return result
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Get client IP address from request
|
|
48
|
-
export function getClientIP(request: Request): string {
|
|
49
|
-
// Check various headers for IP address
|
|
50
|
-
const forwarded = request.headers.get('x-forwarded-for')
|
|
51
|
-
const realIP = request.headers.get('x-real-ip')
|
|
52
|
-
const remoteAddr = request.headers.get('x-remote-addr')
|
|
53
|
-
|
|
54
|
-
if (forwarded) {
|
|
55
|
-
// x-forwarded-for can contain multiple IPs, take the first one
|
|
56
|
-
return forwarded.split(',')[0].trim()
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (realIP) {
|
|
60
|
-
return realIP
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (remoteAddr) {
|
|
64
|
-
return remoteAddr
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Fallback to a default IP if none found
|
|
68
|
-
return '127.0.0.1'
|
|
69
|
-
}
|