@pelatform/starter.shared 0.1.0

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/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # Pelatform Starter
2
+
3
+ A part of SaaS starter kit for Pelatform applications.
4
+
5
+ [![Version](https://img.shields.io/npm/v/@pelatform/starter.svg)](https://www.npmjs.com/package/@pelatform/starter)
@@ -0,0 +1,166 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ComponentProps, ReactNode, PropsWithChildren } from 'react';
3
+ import { Avatar, buttonVariants, Dialog, Card, Button, Input } from 'pelatform-ui/default';
4
+ import { User, Workspace, ApiKey } from '@pelatform/starter.utils';
5
+ import { LucideIcon } from 'lucide-react';
6
+ import { LanguageSwitcherProps } from 'pelatform-ui/components';
7
+ export { Logo as LogoDefault } from 'pelatform-ui/components';
8
+
9
+ type AvatarClassNames = {
10
+ base?: string;
11
+ fallback?: string;
12
+ fallbackIcon?: string;
13
+ image?: string;
14
+ skeleton?: string;
15
+ };
16
+ interface AvatarProps extends ComponentProps<typeof Avatar> {
17
+ className?: string;
18
+ classNames?: AvatarClassNames;
19
+ image?: string;
20
+ isPending?: boolean;
21
+ size?: NonNullable<Parameters<typeof buttonVariants>[0]>["size"] | null | undefined;
22
+ user?: Partial<User> | null;
23
+ workspace?: Partial<Workspace> | null;
24
+ }
25
+
26
+ type DialogClassNames = {
27
+ content?: string;
28
+ header?: string;
29
+ footer?: string;
30
+ };
31
+ interface DialogComponentProps extends ComponentProps<typeof Dialog> {
32
+ className?: string;
33
+ children?: ReactNode;
34
+ classNames?: CardClassNames;
35
+ title?: string;
36
+ description?: string;
37
+ disableFooter?: boolean;
38
+ cancelButton?: boolean;
39
+ cancelButtonDisabled?: boolean;
40
+ button?: ReactNode;
41
+ }
42
+
43
+ type CardClassNames = {
44
+ base?: string;
45
+ cell?: string;
46
+ content?: string;
47
+ header?: string;
48
+ footer?: string;
49
+ grid?: string;
50
+ skeleton?: string;
51
+ title?: string;
52
+ description?: string;
53
+ instructions?: string;
54
+ error?: string;
55
+ label?: string;
56
+ input?: string;
57
+ checkbox?: string;
58
+ icon?: string;
59
+ button?: string;
60
+ primaryButton?: string;
61
+ secondaryButton?: string;
62
+ outlineButton?: string;
63
+ destructiveButton?: string;
64
+ avatar?: AvatarClassNames;
65
+ dialog?: DialogClassNames;
66
+ };
67
+ interface CardComponentProps extends Omit<ComponentProps<typeof Card>, "title" | "variant"> {
68
+ className?: string;
69
+ children?: ReactNode;
70
+ classNames?: CardClassNames;
71
+ title?: ReactNode;
72
+ description?: ReactNode;
73
+ instructions?: ReactNode;
74
+ actionLabel?: ReactNode;
75
+ action?: () => Promise<unknown> | unknown;
76
+ disabled?: boolean;
77
+ isDestructive?: boolean;
78
+ isPending?: boolean;
79
+ isSubmitting?: boolean;
80
+ }
81
+
82
+ declare function CardComponent({ children, className, classNames, title, description, instructions, actionLabel, action, disabled, isDestructive, isPending, isSubmitting, ...props }: CardComponentProps): react_jsx_runtime.JSX.Element;
83
+ declare function CardHeaderComponent({ className, classNames, title, description, isPending, }: CardComponentProps): react_jsx_runtime.JSX.Element;
84
+ declare function CardFooterComponent({ className, classNames, instructions, actionLabel, action, disabled, isDestructive, isPending, isSubmitting, }: CardComponentProps): react_jsx_runtime.JSX.Element;
85
+ declare function CardActionComponent({ classNames, actionLabel, onClick, disabled, isDestructive, isSubmitting, ...props }: CardComponentProps & ComponentProps<typeof Button>): react_jsx_runtime.JSX.Element;
86
+
87
+ declare function DialogComponent({ children, classNames, onOpenChange, title, description, disableFooter, cancelButton, cancelButtonDisabled, button, ...props }: DialogComponentProps): react_jsx_runtime.JSX.Element;
88
+ declare function DialogFooterComponent({ className, classNames, onOpenChange, cancelButton, cancelButtonDisabled, button, }: DialogComponentProps): react_jsx_runtime.JSX.Element;
89
+
90
+ declare function SkeletonViewComponent({ classNames }: {
91
+ classNames?: CardClassNames;
92
+ }): react_jsx_runtime.JSX.Element;
93
+ declare function SkeletonInputComponent({ classNames }: {
94
+ classNames?: CardClassNames;
95
+ }): react_jsx_runtime.JSX.Element;
96
+
97
+ declare function UserAvatar({ className, classNames, image, isPending, size, user, ...props }: AvatarProps): react_jsx_runtime.JSX.Element;
98
+ declare function WorkspaceLogo({ className, classNames, image, isPending, size, workspace, ...props }: AvatarProps): react_jsx_runtime.JSX.Element;
99
+
100
+ declare function DisplayIdCard({ className, classNames, isPending, id, title, description, ...props }: CardComponentProps & {
101
+ id: string | undefined;
102
+ title: string;
103
+ description: string;
104
+ }): react_jsx_runtime.JSX.Element;
105
+
106
+ type EmptyStateProps = PropsWithChildren<{
107
+ className?: string;
108
+ icon?: LucideIcon;
109
+ title: string;
110
+ description?: ReactNode;
111
+ learnMore?: string;
112
+ learnMoreText?: string;
113
+ }>;
114
+ declare function EmptyState({ className, icon: Icon, title, description, learnMore, learnMoreText, children, }: EmptyStateProps): react_jsx_runtime.JSX.Element;
115
+
116
+ declare function LanguageSwitcher({ className, type, variant, size, showNames, showFlags, }: Omit<LanguageSwitcherProps, "currentLocale" | "locales" | "onLocaleChange">): react_jsx_runtime.JSX.Element;
117
+
118
+ interface LogoProps {
119
+ className?: string;
120
+ href?: string;
121
+ }
122
+
123
+ declare function LogoWithName({ className }: LogoProps): react_jsx_runtime.JSX.Element;
124
+ declare function LogoWithHref({ className, href }: LogoProps): react_jsx_runtime.JSX.Element;
125
+
126
+ declare function OTPInputGroup({ otpSeparators }: {
127
+ otpSeparators?: 0 | 1 | 2;
128
+ }): react_jsx_runtime.JSX.Element;
129
+
130
+ declare function PasswordInput({ className, variant, enableToggle, onChange, ...props }: ComponentProps<typeof Input> & {
131
+ enableToggle?: boolean;
132
+ }): react_jsx_runtime.JSX.Element;
133
+
134
+ declare function SignedInHint({ linkHref }: {
135
+ linkHref?: string;
136
+ }): react_jsx_runtime.JSX.Element;
137
+
138
+ declare function UserMenu({ hiddenSwitcher }: {
139
+ hiddenSwitcher?: boolean;
140
+ }): react_jsx_runtime.JSX.Element;
141
+
142
+ type ViewClassNames = {
143
+ base?: string;
144
+ content?: string;
145
+ title?: string;
146
+ subtitle?: string;
147
+ skeleton?: string;
148
+ icon?: string;
149
+ avatar?: AvatarClassNames;
150
+ };
151
+ interface ViewProps {
152
+ className?: string;
153
+ classNames?: ViewClassNames;
154
+ isPending?: boolean;
155
+ size?: NonNullable<Parameters<typeof buttonVariants>[0]>["size"] | null | undefined;
156
+ user?: Partial<User> | null;
157
+ workspace?: Partial<Workspace> | null;
158
+ }
159
+
160
+ declare function UserView({ className, classNames, isPending, size, user }: ViewProps): react_jsx_runtime.JSX.Element;
161
+ declare function ApiKeyView({ className, classNames, apiKey }: ViewProps & {
162
+ apiKey: ApiKey;
163
+ }): react_jsx_runtime.JSX.Element;
164
+ declare function WorkspaceView({ className, classNames, isPending, size, workspace }: ViewProps): react_jsx_runtime.JSX.Element;
165
+
166
+ export { ApiKeyView, type AvatarClassNames, type AvatarProps, CardActionComponent, type CardClassNames, CardComponent, type CardComponentProps, CardFooterComponent, CardHeaderComponent, type DialogClassNames, DialogComponent, type DialogComponentProps, DialogFooterComponent, DisplayIdCard, EmptyState, type EmptyStateProps, LanguageSwitcher, LogoWithHref, LogoWithName, OTPInputGroup, PasswordInput, SignedInHint, SkeletonInputComponent, SkeletonViewComponent, UserAvatar, UserMenu, UserView, type ViewClassNames, type ViewProps, WorkspaceLogo, WorkspaceView };
package/dist/index.js ADDED
@@ -0,0 +1,993 @@
1
+ "use client";
2
+
3
+ // src/components/utils/card.tsx
4
+ import { useFormState } from "react-hook-form";
5
+ import { cn } from "pelatform-ui";
6
+ import { Button, Card, CardContent, CardFooter, Skeleton, Spinner } from "pelatform-ui/default";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ function CardComponent({
9
+ children,
10
+ className,
11
+ classNames,
12
+ title,
13
+ description,
14
+ instructions,
15
+ actionLabel,
16
+ action,
17
+ disabled,
18
+ isDestructive,
19
+ isPending,
20
+ isSubmitting,
21
+ ...props
22
+ }) {
23
+ return /* @__PURE__ */ jsxs(
24
+ Card,
25
+ {
26
+ className: cn(
27
+ "w-full overflow-hidden",
28
+ isDestructive && "border-destructive/70",
29
+ className,
30
+ classNames?.base
31
+ ),
32
+ ...props,
33
+ children: [
34
+ /* @__PURE__ */ jsxs(CardContent, { className: cn("space-y-6 p-5 sm:p-10", classNames?.content), children: [
35
+ /* @__PURE__ */ jsx(
36
+ CardHeaderComponent,
37
+ {
38
+ classNames,
39
+ description,
40
+ title,
41
+ isPending
42
+ }
43
+ ),
44
+ children
45
+ ] }),
46
+ /* @__PURE__ */ jsx(
47
+ CardFooterComponent,
48
+ {
49
+ classNames,
50
+ instructions,
51
+ actionLabel,
52
+ action,
53
+ disabled,
54
+ isDestructive,
55
+ isPending,
56
+ isSubmitting
57
+ }
58
+ )
59
+ ]
60
+ }
61
+ );
62
+ }
63
+ function CardHeaderComponent({
64
+ className,
65
+ classNames,
66
+ title,
67
+ description,
68
+ isPending
69
+ }) {
70
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-2", className, classNames?.header), children: isPending ? /* @__PURE__ */ jsxs(Fragment, { children: [
71
+ /* @__PURE__ */ jsx(Skeleton, { className: cn("h-7 w-1/3", classNames?.skeleton) }),
72
+ description && /* @__PURE__ */ jsx(Skeleton, { className: cn("h-5 w-2/3", classNames?.skeleton) })
73
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
74
+ /* @__PURE__ */ jsx("h2", { className: cn("font-medium text-xl", classNames?.title), children: title }),
75
+ description && /* @__PURE__ */ jsx("p", { className: cn("text-muted-foreground text-sm", classNames?.description), children: description })
76
+ ] }) });
77
+ }
78
+ function CardFooterComponent({
79
+ className,
80
+ classNames,
81
+ instructions,
82
+ actionLabel,
83
+ action,
84
+ disabled,
85
+ isDestructive,
86
+ isPending,
87
+ isSubmitting
88
+ }) {
89
+ return /* @__PURE__ */ jsx(
90
+ CardFooter,
91
+ {
92
+ className: cn(
93
+ "flex items-center justify-between space-x-4 bg-muted p-3 sm:px-10",
94
+ isDestructive && "border-destructive/70",
95
+ className,
96
+ classNames?.footer
97
+ ),
98
+ children: isPending ? /* @__PURE__ */ jsxs(Fragment, { children: [
99
+ instructions && /* @__PURE__ */ jsx(
100
+ Skeleton,
101
+ {
102
+ className: cn(
103
+ "h-4 w-48 max-w-full bg-muted-foreground/10 md:h-5 md:w-60",
104
+ classNames?.skeleton
105
+ )
106
+ }
107
+ ),
108
+ actionLabel && /* @__PURE__ */ jsx(
109
+ Skeleton,
110
+ {
111
+ className: cn("h-8 w-20 bg-muted-foreground/10 md:ms-auto", classNames?.skeleton)
112
+ }
113
+ )
114
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
115
+ instructions && /* @__PURE__ */ jsx(
116
+ "div",
117
+ {
118
+ className: cn("text-muted-foreground text-xs md:text-sm", classNames?.instructions),
119
+ children: instructions
120
+ }
121
+ ),
122
+ actionLabel && /* @__PURE__ */ jsx(
123
+ CardActionComponent,
124
+ {
125
+ classNames,
126
+ actionLabel,
127
+ onClick: action,
128
+ disabled,
129
+ isDestructive,
130
+ isSubmitting
131
+ }
132
+ )
133
+ ] })
134
+ }
135
+ );
136
+ }
137
+ function CardActionComponent({
138
+ classNames,
139
+ actionLabel,
140
+ onClick,
141
+ disabled,
142
+ isDestructive,
143
+ isSubmitting,
144
+ ...props
145
+ }) {
146
+ if (!onClick) {
147
+ const formState = useFormState();
148
+ isSubmitting = formState.isSubmitting;
149
+ }
150
+ return /* @__PURE__ */ jsxs(
151
+ Button,
152
+ {
153
+ type: onClick ? "button" : "submit",
154
+ variant: isDestructive ? "destructive" : "primary",
155
+ size: "sm",
156
+ className: cn(
157
+ "ms-auto",
158
+ isSubmitting || disabled ? "pointer-events-auto! cursor-not-allowed" : "",
159
+ classNames?.button,
160
+ isDestructive ? classNames?.destructiveButton : classNames?.primaryButton
161
+ ),
162
+ onClick,
163
+ disabled: isSubmitting || disabled,
164
+ ...props,
165
+ children: [
166
+ isSubmitting && /* @__PURE__ */ jsx(Spinner, {}),
167
+ actionLabel
168
+ ]
169
+ }
170
+ );
171
+ }
172
+
173
+ // src/components/utils/dialog.tsx
174
+ import { useTranslations } from "next-intl";
175
+ import { cn as cn2 } from "pelatform-ui";
176
+ import {
177
+ Button as Button2,
178
+ Dialog,
179
+ DialogContent,
180
+ DialogDescription,
181
+ DialogFooter,
182
+ DialogHeader,
183
+ DialogTitle
184
+ } from "pelatform-ui/default";
185
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
186
+ function DialogComponent({
187
+ children,
188
+ classNames,
189
+ onOpenChange,
190
+ title,
191
+ description,
192
+ disableFooter,
193
+ cancelButton,
194
+ cancelButtonDisabled,
195
+ button,
196
+ ...props
197
+ }) {
198
+ return /* @__PURE__ */ jsx2(Dialog, { onOpenChange, ...props, children: /* @__PURE__ */ jsxs2(
199
+ DialogContent,
200
+ {
201
+ onOpenAutoFocus: (e) => e.preventDefault(),
202
+ className: classNames?.dialog?.content,
203
+ children: [
204
+ /* @__PURE__ */ jsxs2(DialogHeader, { className: cn2("space-y-2", classNames?.header), children: [
205
+ /* @__PURE__ */ jsx2(DialogTitle, { className: classNames?.title, children: title }),
206
+ description && /* @__PURE__ */ jsx2(DialogDescription, { className: classNames?.description, children: description })
207
+ ] }),
208
+ children,
209
+ !disableFooter && /* @__PURE__ */ jsx2(
210
+ DialogFooterComponent,
211
+ {
212
+ classNames,
213
+ onOpenChange,
214
+ cancelButton,
215
+ cancelButtonDisabled,
216
+ button
217
+ }
218
+ )
219
+ ]
220
+ }
221
+ ) });
222
+ }
223
+ function DialogFooterComponent({
224
+ className,
225
+ classNames,
226
+ onOpenChange,
227
+ cancelButton,
228
+ cancelButtonDisabled,
229
+ button
230
+ }) {
231
+ const t = useTranslations();
232
+ return /* @__PURE__ */ jsxs2(DialogFooter, { className: cn2(className, classNames?.dialog?.footer), children: [
233
+ cancelButton && /* @__PURE__ */ jsx2(
234
+ Button2,
235
+ {
236
+ type: "button",
237
+ variant: "secondary",
238
+ className: cn2(classNames?.button, classNames?.secondaryButton),
239
+ onClick: () => onOpenChange?.(false),
240
+ disabled: cancelButtonDisabled,
241
+ children: t("common.actions.cancel")
242
+ }
243
+ ),
244
+ button
245
+ ] });
246
+ }
247
+
248
+ // src/components/utils/skeleton.tsx
249
+ import { cn as cn3 } from "pelatform-ui";
250
+ import { Card as Card2, Skeleton as Skeleton2 } from "pelatform-ui/default";
251
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
252
+ function SkeletonViewComponent({ classNames }) {
253
+ return /* @__PURE__ */ jsxs3(Card2, { className: cn3("flex-row items-center gap-3 px-4 py-3", classNames?.cell), children: [
254
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
255
+ /* @__PURE__ */ jsx3(Skeleton2, { className: cn3("size-5 rounded-full", classNames?.skeleton) }),
256
+ /* @__PURE__ */ jsx3("div", { children: /* @__PURE__ */ jsx3(Skeleton2, { className: cn3("h-4 w-32", classNames?.skeleton) }) })
257
+ ] }),
258
+ /* @__PURE__ */ jsx3(Skeleton2, { className: cn3("ms-auto size-8 w-16", classNames?.skeleton) })
259
+ ] });
260
+ }
261
+ function SkeletonInputComponent({ classNames }) {
262
+ return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-1.5", children: [
263
+ /* @__PURE__ */ jsx3(Skeleton2, { className: cn3("h-4 w-32", classNames?.skeleton) }),
264
+ /* @__PURE__ */ jsx3(Skeleton2, { className: cn3("h-9 w-full", classNames?.skeleton) })
265
+ ] });
266
+ }
267
+
268
+ // src/components/avatar.tsx
269
+ import { BuildingIcon, UserRoundIcon } from "lucide-react";
270
+ import { useTranslations as useTranslations2 } from "next-intl";
271
+ import { getSizeAvatar, getUserName } from "@pelatform/starter.utils";
272
+ import { cn as cn4 } from "pelatform-ui";
273
+ import { getInitials } from "pelatform-ui/components";
274
+ import { Avatar, AvatarFallback, AvatarImage, Skeleton as Skeleton3 } from "pelatform-ui/default";
275
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
276
+ function UserAvatar({
277
+ className,
278
+ classNames,
279
+ image,
280
+ isPending,
281
+ size,
282
+ user,
283
+ ...props
284
+ }) {
285
+ const t = useTranslations2();
286
+ const name = getUserName(user);
287
+ const src = user?.image;
288
+ if (isPending) {
289
+ return /* @__PURE__ */ jsx4(
290
+ Skeleton3,
291
+ {
292
+ className: cn4(
293
+ "shrink-0 rounded-full",
294
+ getSizeAvatar(size),
295
+ className,
296
+ classNames?.base,
297
+ classNames?.skeleton
298
+ )
299
+ }
300
+ );
301
+ }
302
+ return /* @__PURE__ */ jsxs4(
303
+ Avatar,
304
+ {
305
+ className: cn4("rounded-full bg-accent", getSizeAvatar(size), className, classNames?.base),
306
+ ...props,
307
+ children: [
308
+ /* @__PURE__ */ jsx4(
309
+ AvatarImage,
310
+ {
311
+ src: image || src || void 0,
312
+ alt: name || t("ui.navigation.user"),
313
+ className: classNames?.image
314
+ }
315
+ ),
316
+ /* @__PURE__ */ jsx4(
317
+ AvatarFallback,
318
+ {
319
+ className: cn4("text-foreground uppercase", classNames?.fallback),
320
+ delayMs: src ? 600 : void 0,
321
+ children: getInitials(name, 2) || /* @__PURE__ */ jsx4(UserRoundIcon, { className: cn4("size-[50%]", classNames?.fallbackIcon) })
322
+ }
323
+ )
324
+ ]
325
+ }
326
+ );
327
+ }
328
+ function WorkspaceLogo({
329
+ className,
330
+ classNames,
331
+ image,
332
+ isPending,
333
+ size,
334
+ workspace,
335
+ ...props
336
+ }) {
337
+ const t = useTranslations2();
338
+ const name = workspace?.name;
339
+ const src = workspace?.logo;
340
+ if (isPending) {
341
+ return /* @__PURE__ */ jsx4(
342
+ Skeleton3,
343
+ {
344
+ className: cn4(
345
+ "shrink-0 rounded-full",
346
+ getSizeAvatar(size),
347
+ className,
348
+ classNames?.base,
349
+ classNames?.skeleton
350
+ )
351
+ }
352
+ );
353
+ }
354
+ return /* @__PURE__ */ jsxs4(
355
+ Avatar,
356
+ {
357
+ className: cn4("rounded-full bg-accent", getSizeAvatar(size), className, classNames?.base),
358
+ ...props,
359
+ children: [
360
+ /* @__PURE__ */ jsx4(
361
+ AvatarImage,
362
+ {
363
+ src: image || src || void 0,
364
+ alt: name || t("ui.navigation.workspace"),
365
+ className: classNames?.image
366
+ }
367
+ ),
368
+ /* @__PURE__ */ jsx4(
369
+ AvatarFallback,
370
+ {
371
+ className: cn4("text-foreground", classNames?.fallback),
372
+ delayMs: src ? 600 : void 0,
373
+ children: /* @__PURE__ */ jsx4(BuildingIcon, { className: cn4("size-[50%]", classNames?.fallbackIcon) })
374
+ }
375
+ )
376
+ ]
377
+ }
378
+ );
379
+ }
380
+
381
+ // src/components/display-id.tsx
382
+ import { useRef } from "react";
383
+ import { CheckIcon, CopyIcon } from "lucide-react";
384
+ import { useTranslations as useTranslations3 } from "next-intl";
385
+ import { cn as cn5 } from "pelatform-ui";
386
+ import {
387
+ Button as Button3,
388
+ Input,
389
+ Skeleton as Skeleton4,
390
+ Tooltip,
391
+ TooltipContent,
392
+ TooltipProvider,
393
+ TooltipTrigger
394
+ } from "pelatform-ui/default";
395
+ import { useCopyToClipboard } from "pelatform-ui/hooks";
396
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
397
+ function DisplayIdCard({
398
+ className,
399
+ classNames,
400
+ isPending,
401
+ id,
402
+ title,
403
+ description,
404
+ ...props
405
+ }) {
406
+ const t = useTranslations3();
407
+ const { copy, copied } = useCopyToClipboard();
408
+ const inputRef = useRef(null);
409
+ const handleCopy = () => {
410
+ if (inputRef.current) {
411
+ copy(inputRef.current.value);
412
+ }
413
+ };
414
+ return /* @__PURE__ */ jsx5(
415
+ CardComponent,
416
+ {
417
+ className,
418
+ classNames,
419
+ title,
420
+ description,
421
+ isPending,
422
+ ...props,
423
+ children: isPending ? /* @__PURE__ */ jsx5(Skeleton4, { className: cn5("h-11.5 w-full max-w-md", classNames?.skeleton) }) : /* @__PURE__ */ jsxs5(
424
+ "div",
425
+ {
426
+ className: cn5(
427
+ "flex w-full max-w-md items-center justify-between rounded-md border p-2",
428
+ classNames?.grid
429
+ ),
430
+ children: [
431
+ /* @__PURE__ */ jsx5(Input, { value: id, ref: inputRef, disabled: true, className: "border-none! bg-transparent!" }),
432
+ /* @__PURE__ */ jsx5(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs5(Tooltip, { children: [
433
+ /* @__PURE__ */ jsx5(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx5(Button3, { variant: "dim", onClick: handleCopy, disabled: copied, children: copied ? /* @__PURE__ */ jsx5(CheckIcon, { className: cn5("stroke-green-600", classNames?.icon) }) : /* @__PURE__ */ jsx5(CopyIcon, { className: classNames?.icon }) }) }),
434
+ /* @__PURE__ */ jsx5(TooltipContent, { className: "px-2 py-1 text-xs", children: t("common.actions.copy") })
435
+ ] }) })
436
+ ]
437
+ }
438
+ )
439
+ }
440
+ );
441
+ }
442
+
443
+ // src/components/empty-state.tsx
444
+ import Link from "next/link";
445
+ import { useTranslations as useTranslations4 } from "next-intl";
446
+ import { cn as cn6 } from "pelatform-ui";
447
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
448
+ function EmptyState({
449
+ className,
450
+ icon: Icon,
451
+ title,
452
+ description,
453
+ learnMore,
454
+ learnMoreText,
455
+ children
456
+ }) {
457
+ const t = useTranslations4();
458
+ return /* @__PURE__ */ jsxs6("div", { className: cn6("flex flex-col items-center justify-center gap-y-4", className), children: [
459
+ Icon && /* @__PURE__ */ jsx6("div", { className: "flex size-14 items-center justify-center rounded-2xl border bg-muted", children: /* @__PURE__ */ jsx6(Icon, { className: "size-6 text-foreground" }) }),
460
+ /* @__PURE__ */ jsx6("p", { className: "text-center font-medium text-base text-foreground", children: title }),
461
+ description && /* @__PURE__ */ jsxs6("p", { className: "max-w-sm text-balance text-center text-muted-foreground text-sm", children: [
462
+ description,
463
+ " ",
464
+ learnMore && /* @__PURE__ */ jsxs6(
465
+ Link,
466
+ {
467
+ href: learnMore,
468
+ className: "text-foreground underline underline-offset-2 transition-colors hover:text-primary",
469
+ children: [
470
+ learnMoreText ?? t("ui.common.learnMore"),
471
+ " \u2197"
472
+ ]
473
+ }
474
+ )
475
+ ] }),
476
+ children
477
+ ] });
478
+ }
479
+
480
+ // src/components/language-switcher.tsx
481
+ import Image from "next/image";
482
+ import { useRouter } from "next/navigation";
483
+ import { useLocale, useTranslations as useTranslations5 } from "next-intl";
484
+ import { useConfig } from "@pelatform/starter.hook";
485
+ import {
486
+ LanguageSwitcher as LanguageSwitcherBase
487
+ } from "pelatform-ui/components";
488
+ import { jsx as jsx7 } from "react/jsx-runtime";
489
+ function LanguageSwitcher({
490
+ className,
491
+ type,
492
+ variant,
493
+ size,
494
+ showNames,
495
+ showFlags
496
+ }) {
497
+ const { i18n } = useConfig();
498
+ const router = useRouter();
499
+ const t = useTranslations5();
500
+ const currentLocale = useLocale();
501
+ const availableLocales = (() => {
502
+ if (!i18n.enabled) {
503
+ return [i18n.defaultLocale];
504
+ }
505
+ const availableLocales2 = Object.keys(i18n.locales);
506
+ return availableLocales2;
507
+ })();
508
+ const languages = availableLocales.map((locale) => {
509
+ const localeConfig = i18n.locales[locale] || null;
510
+ return {
511
+ code: locale,
512
+ name: localeConfig?.name || locale.toUpperCase(),
513
+ flag: `/flags/${localeConfig?.flag}.svg` || ""
514
+ };
515
+ });
516
+ function handleLanguageChange(newLocale) {
517
+ if (newLocale === currentLocale) {
518
+ return;
519
+ }
520
+ document.cookie = `${i18n.localeCookieName}=${newLocale}; max-age=${60 * 60 * 24 * 365}; path=/`;
521
+ router.refresh();
522
+ }
523
+ return /* @__PURE__ */ jsx7(
524
+ LanguageSwitcherBase,
525
+ {
526
+ className,
527
+ type,
528
+ variant,
529
+ size,
530
+ showNames,
531
+ showFlags,
532
+ label: t("ui.common.language"),
533
+ i18nEnabled: i18n.enabled,
534
+ currentLocale,
535
+ locales: languages,
536
+ onLocaleChange: handleLanguageChange,
537
+ customFlagUrl: true,
538
+ Image
539
+ }
540
+ );
541
+ }
542
+
543
+ // src/components/logo.tsx
544
+ import Link2 from "next/link";
545
+ import { useConfig as useConfig2 } from "@pelatform/starter.hook";
546
+ import { cn as cn7 } from "pelatform-ui";
547
+ import { Logo } from "pelatform-ui/components";
548
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
549
+ function LogoWithName({ className }) {
550
+ const { app } = useConfig2();
551
+ return /* @__PURE__ */ jsxs7("div", { className: cn7("flex items-center gap-2", className), children: [
552
+ /* @__PURE__ */ jsx8(Logo, { className: "size-7" }),
553
+ /* @__PURE__ */ jsx8("span", { className: "font-semibold text-lg text-mono", children: app.name })
554
+ ] });
555
+ }
556
+ function LogoWithHref({ className, href = "/" }) {
557
+ const { app } = useConfig2();
558
+ return /* @__PURE__ */ jsxs7(Link2, { href, className: cn7("flex items-center gap-2", className), children: [
559
+ /* @__PURE__ */ jsx8(Logo, { className: "size-7" }),
560
+ /* @__PURE__ */ jsx8("span", { className: "font-semibold text-lg text-mono", children: app.name })
561
+ ] });
562
+ }
563
+
564
+ // src/components/otp-input-group.tsx
565
+ import { InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "pelatform-ui/default";
566
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
567
+ function OTPInputGroup({ otpSeparators = 0 }) {
568
+ if (otpSeparators === 0) {
569
+ return /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
570
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 0 }),
571
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 1 }),
572
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 2 }),
573
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 3 }),
574
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 4 }),
575
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 5 })
576
+ ] });
577
+ }
578
+ if (otpSeparators === 1) {
579
+ return /* @__PURE__ */ jsxs8(Fragment2, { children: [
580
+ /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
581
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 0 }),
582
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 1 }),
583
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 2 })
584
+ ] }),
585
+ /* @__PURE__ */ jsx9(InputOTPSeparator, {}),
586
+ /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
587
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 3 }),
588
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 4 }),
589
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 5 })
590
+ ] })
591
+ ] });
592
+ }
593
+ return /* @__PURE__ */ jsxs8(Fragment2, { children: [
594
+ /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
595
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 0 }),
596
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 1 })
597
+ ] }),
598
+ /* @__PURE__ */ jsx9(InputOTPSeparator, {}),
599
+ /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
600
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 2 }),
601
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 3 })
602
+ ] }),
603
+ /* @__PURE__ */ jsx9(InputOTPSeparator, {}),
604
+ /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
605
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 4 }),
606
+ /* @__PURE__ */ jsx9(InputOTPSlot, { index: 5 })
607
+ ] })
608
+ ] });
609
+ }
610
+
611
+ // src/components/password-input.tsx
612
+ import { useState } from "react";
613
+ import { EyeIcon, EyeOffIcon } from "lucide-react";
614
+ import { cn as cn8 } from "pelatform-ui";
615
+ import { Button as Button4, Input as Input2 } from "pelatform-ui/default";
616
+ import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
617
+ function PasswordInput({
618
+ className,
619
+ variant,
620
+ enableToggle,
621
+ onChange,
622
+ ...props
623
+ }) {
624
+ const [disabled, setDisabled] = useState(true);
625
+ const [isVisible, setIsVisible] = useState(false);
626
+ return /* @__PURE__ */ jsxs9("div", { className: "relative", children: [
627
+ /* @__PURE__ */ jsx10(
628
+ Input2,
629
+ {
630
+ type: isVisible && enableToggle ? "text" : "password",
631
+ variant,
632
+ className: cn8(enableToggle && "pe-10", className),
633
+ ...props,
634
+ onChange: (event) => {
635
+ setDisabled(!event.target.value);
636
+ onChange?.(event);
637
+ }
638
+ }
639
+ ),
640
+ enableToggle && /* @__PURE__ */ jsxs9(Fragment3, { children: [
641
+ /* @__PURE__ */ jsx10(
642
+ Button4,
643
+ {
644
+ type: "button",
645
+ variant: "ghost",
646
+ size: "icon",
647
+ className: "absolute end-0 top-0 bg-transparent!",
648
+ onClick: () => setIsVisible(!isVisible),
649
+ disabled,
650
+ children: isVisible ? /* @__PURE__ */ jsx10(EyeIcon, {}) : /* @__PURE__ */ jsx10(EyeOffIcon, {})
651
+ }
652
+ ),
653
+ /* @__PURE__ */ jsx10("style", { children: `
654
+ .hide-password-toggle::-ms-reveal,
655
+ .hide-password-toggle::-ms-clear {
656
+ visibility: hidden;
657
+ pointer-events: none;
658
+ display: none;
659
+ }
660
+ ` })
661
+ ] })
662
+ ] });
663
+ }
664
+
665
+ // src/components/signed-in-hint.tsx
666
+ import Link3 from "next/link";
667
+ import { useTranslations as useTranslations6 } from "next-intl";
668
+ import { useSession } from "@pelatform/starter.hook";
669
+ import { Button as Button5 } from "pelatform-ui/default";
670
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
671
+ function SignedInHint({ linkHref = "/signin" }) {
672
+ const t = useTranslations6("ui.common.signed");
673
+ const { isPending, user } = useSession();
674
+ return /* @__PURE__ */ jsxs10("div", { className: "fixed start-0 bottom-0 z-40 m-5 flex flex-col gap-2", children: [
675
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 text-muted-foreground text-xs", children: [
676
+ t("text"),
677
+ " ",
678
+ isPending || !user ? /* @__PURE__ */ jsx11("span", { className: "h-3 w-32 animate-pulse rounded-md border bg-muted-foreground" }) : /* @__PURE__ */ jsx11("b", { className: "text-foreground", children: user.email })
679
+ ] }),
680
+ /* @__PURE__ */ jsx11(Button5, { variant: "mono", className: "h-8 w-fit rounded-lg px-3 text-xs shadow-sm", children: /* @__PURE__ */ jsx11(Link3, { href: linkHref, children: t("button") }) })
681
+ ] });
682
+ }
683
+
684
+ // src/components/user-menu.tsx
685
+ import { Fragment as Fragment5, useCallback, useEffect, useState as useState2 } from "react";
686
+ import Link4 from "next/link";
687
+ import { useRouter as useRouter2 } from "next/navigation";
688
+ import { LogOut, PlusCircleIcon, Settings, Shield, UserStar } from "lucide-react";
689
+ import { useTranslations as useTranslations8 } from "next-intl";
690
+ import {
691
+ useConfig as useConfig3,
692
+ useListDeviceSessions,
693
+ useSession as useSession2,
694
+ useSetActiveSession
695
+ } from "@pelatform/starter.hook";
696
+ import { getUserName as getUserName3 } from "@pelatform/starter.utils";
697
+ import { ModeSwitcher, UserAvatar as UserAvatar2 } from "pelatform-ui/components";
698
+ import {
699
+ Badge,
700
+ DropdownMenu,
701
+ DropdownMenuContent,
702
+ DropdownMenuItem,
703
+ DropdownMenuSeparator,
704
+ DropdownMenuTrigger,
705
+ Skeleton as Skeleton6
706
+ } from "pelatform-ui/default";
707
+
708
+ // src/components/view.tsx
709
+ import { KeyRoundIcon } from "lucide-react";
710
+ import { useLocale as useLocale2, useTranslations as useTranslations7 } from "next-intl";
711
+ import { getUserName as getUserName2 } from "@pelatform/starter.utils";
712
+ import { cn as cn9 } from "pelatform-ui";
713
+ import { Skeleton as Skeleton5 } from "pelatform-ui/default";
714
+ import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
715
+ function UserView({ className, classNames, isPending, size, user }) {
716
+ const t = useTranslations7();
717
+ return /* @__PURE__ */ jsxs11("div", { className: cn9("flex items-center gap-2", className, classNames?.base), children: [
718
+ /* @__PURE__ */ jsx12(
719
+ UserAvatar,
720
+ {
721
+ className: cn9(size !== "sm" && "my-0.5"),
722
+ classNames: classNames?.avatar,
723
+ isPending,
724
+ size,
725
+ user
726
+ }
727
+ ),
728
+ /* @__PURE__ */ jsx12("div", { className: cn9("grid flex-1 text-start leading-tight", classNames?.content), children: isPending ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
729
+ /* @__PURE__ */ jsx12(
730
+ Skeleton5,
731
+ {
732
+ className: cn9(
733
+ "max-w-full",
734
+ size === "lg" ? "h-4.5 w-32" : "h-3.5 w-24",
735
+ classNames?.title,
736
+ classNames?.skeleton
737
+ )
738
+ }
739
+ ),
740
+ size !== "sm" && /* @__PURE__ */ jsx12(
741
+ Skeleton5,
742
+ {
743
+ className: cn9(
744
+ "mt-1.5 max-w-full",
745
+ size === "lg" ? "h-3.5 w-40" : "h-3 w-32",
746
+ classNames?.subtitle,
747
+ classNames?.skeleton
748
+ )
749
+ }
750
+ )
751
+ ] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
752
+ /* @__PURE__ */ jsx12(
753
+ "span",
754
+ {
755
+ className: cn9(
756
+ "truncate font-semibold",
757
+ size === "lg" ? "text-base" : "text-sm",
758
+ classNames?.title
759
+ ),
760
+ children: getUserName2(user) || t("ui.navigation.user")
761
+ }
762
+ ),
763
+ !user?.isAnonymous && size !== "sm" && (user?.name || user?.username) && /* @__PURE__ */ jsx12(
764
+ "span",
765
+ {
766
+ className: cn9(
767
+ "truncate opacity-70",
768
+ size === "lg" ? "text-sm" : "text-xs",
769
+ classNames?.subtitle
770
+ ),
771
+ children: user?.email
772
+ }
773
+ )
774
+ ] }) })
775
+ ] });
776
+ }
777
+ function ApiKeyView({ className, classNames, apiKey }) {
778
+ const t = useTranslations7();
779
+ const locale = useLocale2();
780
+ const formatExpiration = () => {
781
+ if (!apiKey.expiresAt) return t("common.time.neverExpires");
782
+ const expiresDate = new Date(apiKey.expiresAt);
783
+ return `${t("common.time.expires")} ${expiresDate.toLocaleDateString(locale ?? "en", {
784
+ month: "short",
785
+ day: "numeric",
786
+ year: "numeric"
787
+ })}`;
788
+ };
789
+ return /* @__PURE__ */ jsxs11("div", { className: cn9("flex items-center gap-3 truncate", className, classNames?.base), children: [
790
+ /* @__PURE__ */ jsx12(KeyRoundIcon, { className: cn9("size-4 shrink-0", classNames?.icon) }),
791
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-col truncate text-start", children: [
792
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
793
+ /* @__PURE__ */ jsx12("span", { className: "truncate font-semibold text-sm", children: apiKey.name }),
794
+ /* @__PURE__ */ jsxs11("span", { className: "flex-1 truncate text-muted-foreground text-sm", children: [
795
+ apiKey.start,
796
+ "******"
797
+ ] })
798
+ ] }),
799
+ /* @__PURE__ */ jsx12("div", { className: "truncate text-muted-foreground text-xs", children: formatExpiration() })
800
+ ] })
801
+ ] });
802
+ }
803
+ function WorkspaceView({ className, classNames, isPending, size, workspace }) {
804
+ const t = useTranslations7();
805
+ return /* @__PURE__ */ jsxs11("div", { className: cn9("flex items-center gap-2 truncate", className, classNames?.base), children: [
806
+ /* @__PURE__ */ jsx12(
807
+ WorkspaceLogo,
808
+ {
809
+ className: cn9(size !== "sm" && "my-0.5"),
810
+ classNames: classNames?.avatar,
811
+ isPending,
812
+ workspace,
813
+ size
814
+ }
815
+ ),
816
+ /* @__PURE__ */ jsx12("div", { className: cn9("flex flex-col truncate text-start leading-tight", classNames?.content), children: isPending ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
817
+ /* @__PURE__ */ jsx12(
818
+ Skeleton5,
819
+ {
820
+ className: cn9(
821
+ "max-w-full",
822
+ size === "lg" ? "h-4.5 w-32" : "h-3.5 w-24",
823
+ classNames?.title,
824
+ classNames?.skeleton
825
+ )
826
+ }
827
+ ),
828
+ size !== "sm" && /* @__PURE__ */ jsx12(
829
+ Skeleton5,
830
+ {
831
+ className: cn9(
832
+ "mt-1.5 max-w-full",
833
+ size === "lg" ? "h-3.5 w-24" : "h-3 w-16",
834
+ classNames?.subtitle,
835
+ classNames?.skeleton
836
+ )
837
+ }
838
+ )
839
+ ] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
840
+ /* @__PURE__ */ jsx12(
841
+ "span",
842
+ {
843
+ className: cn9(
844
+ "truncate font-semibold",
845
+ size === "lg" ? "text-base" : "text-sm",
846
+ classNames?.title
847
+ ),
848
+ children: workspace?.name || t("ui.navigation.workspace")
849
+ }
850
+ ),
851
+ size !== "sm" && workspace?.slug && /* @__PURE__ */ jsx12(
852
+ "span",
853
+ {
854
+ className: cn9(
855
+ "truncate opacity-70",
856
+ size === "lg" ? "text-sm" : "text-xs",
857
+ classNames?.subtitle
858
+ ),
859
+ children: workspace.slug
860
+ }
861
+ )
862
+ ] }) })
863
+ ] });
864
+ }
865
+
866
+ // src/components/user-menu.tsx
867
+ import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
868
+ function UserMenu({ hiddenSwitcher = false }) {
869
+ const { features, path } = useConfig3();
870
+ const router = useRouter2();
871
+ const t = useTranslations8();
872
+ const { isPending: sessionPending, user } = useSession2();
873
+ const { setActiveSessionAsync } = useSetActiveSession();
874
+ const { data: deviceSessions, isPending: deviceSessionsPending } = useListDeviceSessions({
875
+ enabled: features.multiSession
876
+ });
877
+ const [activeSessionPending, setActiveSessionPending] = useState2(false);
878
+ const isPending = sessionPending || activeSessionPending;
879
+ const switchAccount = useCallback(
880
+ async (sessionToken) => {
881
+ setActiveSessionPending(true);
882
+ try {
883
+ await setActiveSessionAsync({ sessionToken });
884
+ router.refresh();
885
+ setActiveSessionPending(false);
886
+ } catch (error) {
887
+ console.error("Error switching account:", error);
888
+ setActiveSessionPending(false);
889
+ }
890
+ },
891
+ [router, setActiveSessionAsync]
892
+ );
893
+ useEffect(() => {
894
+ if (!features.multiSession) return;
895
+ setActiveSessionPending(false);
896
+ }, [features.multiSession, user?.id]);
897
+ const userEmail = user?.email || "user@example.com";
898
+ const userName = getUserName3(user);
899
+ const userAvatar = user?.image || void 0;
900
+ const userRole = user?.role || "user";
901
+ return /* @__PURE__ */ jsxs12(DropdownMenu, { children: [
902
+ /* @__PURE__ */ jsx13(DropdownMenuTrigger, { className: "focus:outline-none focus:ring-0", children: isPending ? /* @__PURE__ */ jsx13(Skeleton6, { className: "size-8 shrink-0 rounded-full" }) : /* @__PURE__ */ jsx13(UserAvatar2, { className: "size-8", indicator: true, src: userAvatar, alt: userName }) }),
903
+ /* @__PURE__ */ jsxs12(DropdownMenuContent, { className: "w-56", side: "bottom", align: "end", sideOffset: 11, children: [
904
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-3 px-3 py-2", children: [
905
+ /* @__PURE__ */ jsx13(UserAvatar2, { src: userAvatar, alt: userName }),
906
+ /* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 flex-1 flex-col items-start", children: [
907
+ /* @__PURE__ */ jsx13("span", { className: "truncate font-semibold text-foreground text-sm", children: userName }),
908
+ /* @__PURE__ */ jsx13("span", { className: "block w-full truncate text-muted-foreground text-xs", children: userEmail }),
909
+ /* @__PURE__ */ jsx13(Badge, { variant: "success", appearance: "outline", size: "sm", className: "mt-1", children: userRole.toUpperCase() })
910
+ ] })
911
+ ] }),
912
+ /* @__PURE__ */ jsx13(DropdownMenuSeparator, {}),
913
+ /* @__PURE__ */ jsx13(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs12(Link4, { href: path.account.SETTINGS, children: [
914
+ /* @__PURE__ */ jsx13(Settings, {}),
915
+ /* @__PURE__ */ jsx13("span", { children: t("ui.navigation.preferences") })
916
+ ] }) }),
917
+ /* @__PURE__ */ jsx13(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs12(Link4, { href: path.account.SECURITY, children: [
918
+ /* @__PURE__ */ jsx13(Shield, {}),
919
+ /* @__PURE__ */ jsx13("span", { children: t("ui.navigation.security") })
920
+ ] }) }),
921
+ "admin" === userRole && /* @__PURE__ */ jsx13(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs12(Link4, { href: path.admin.OVERVIEW, children: [
922
+ /* @__PURE__ */ jsx13(UserStar, {}),
923
+ /* @__PURE__ */ jsx13("span", { children: "Admin Dashboard" })
924
+ ] }) }),
925
+ !hiddenSwitcher && /* @__PURE__ */ jsxs12(Fragment6, { children: [
926
+ /* @__PURE__ */ jsx13(DropdownMenuSeparator, {}),
927
+ /* @__PURE__ */ jsx13(
928
+ ModeSwitcher,
929
+ {
930
+ type: "sub-dropdown",
931
+ label: {
932
+ system: t("ui.common.system"),
933
+ dark: t("ui.common.dark"),
934
+ light: t("ui.common.light")
935
+ }
936
+ }
937
+ ),
938
+ /* @__PURE__ */ jsx13(LanguageSwitcher, { type: "sub-dropdown" })
939
+ ] }),
940
+ /* @__PURE__ */ jsx13(DropdownMenuSeparator, {}),
941
+ /* @__PURE__ */ jsx13(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs12(Link4, { href: path.auth.SIGN_OUT, children: [
942
+ /* @__PURE__ */ jsx13(LogOut, {}),
943
+ /* @__PURE__ */ jsx13("span", { children: t("ui.navigation.signOut") })
944
+ ] }) }),
945
+ user && features.multiSession && /* @__PURE__ */ jsxs12(Fragment6, { children: [
946
+ /* @__PURE__ */ jsx13(DropdownMenuSeparator, {}),
947
+ !deviceSessions && deviceSessionsPending && /* @__PURE__ */ jsxs12(Fragment6, { children: [
948
+ /* @__PURE__ */ jsx13(DropdownMenuItem, { disabled: true, children: /* @__PURE__ */ jsx13(UserView, { isPending: true }) }),
949
+ /* @__PURE__ */ jsx13(DropdownMenuSeparator, {})
950
+ ] }),
951
+ deviceSessions?.filter((sessionData) => sessionData.user.id !== user?.id).map(({ session, user: multiUser }) => /* @__PURE__ */ jsxs12(Fragment5, { children: [
952
+ /* @__PURE__ */ jsxs12(DropdownMenuItem, { onClick: () => switchAccount(session.token), children: [
953
+ /* @__PURE__ */ jsx13(UserAvatar2, { src: multiUser?.image || void 0, alt: getUserName3(multiUser) }),
954
+ /* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 flex-1 flex-col items-start", children: [
955
+ /* @__PURE__ */ jsx13("span", { className: "truncate font-semibold text-foreground text-xs", children: getUserName3(multiUser) }),
956
+ /* @__PURE__ */ jsx13("span", { className: "block w-full truncate text-muted-foreground text-xs", children: multiUser?.email })
957
+ ] })
958
+ ] }),
959
+ /* @__PURE__ */ jsx13(DropdownMenuSeparator, {})
960
+ ] }, session.id)),
961
+ /* @__PURE__ */ jsx13(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs12(Link4, { href: path.auth.SIGN_IN, children: [
962
+ /* @__PURE__ */ jsx13(PlusCircleIcon, {}),
963
+ t("common.actions.addAccount")
964
+ ] }) })
965
+ ] })
966
+ ] })
967
+ ] });
968
+ }
969
+ export {
970
+ ApiKeyView,
971
+ CardActionComponent,
972
+ CardComponent,
973
+ CardFooterComponent,
974
+ CardHeaderComponent,
975
+ DialogComponent,
976
+ DialogFooterComponent,
977
+ DisplayIdCard,
978
+ EmptyState,
979
+ LanguageSwitcher,
980
+ Logo as LogoDefault,
981
+ LogoWithHref,
982
+ LogoWithName,
983
+ OTPInputGroup,
984
+ PasswordInput,
985
+ SignedInHint,
986
+ SkeletonInputComponent,
987
+ SkeletonViewComponent,
988
+ UserAvatar,
989
+ UserMenu,
990
+ UserView,
991
+ WorkspaceLogo,
992
+ WorkspaceView
993
+ };
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ @source ".";
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@pelatform/starter.shared",
3
+ "version": "0.1.0",
4
+ "description": "A part of SaaS starter kit for Pelatform applications.",
5
+ "author": "Pelatform",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "sideEffects": false,
11
+ "exports": {
12
+ "./css": "./dist/style.css",
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "scripts": {
19
+ "clean": "rimraf dist",
20
+ "clean:all": "rimraf .turbo dist node_modules",
21
+ "dev": "tsup --watch --onSuccess \"cp src/style.css dist/style.css\"",
22
+ "build": "tsup && cp src/style.css dist/style.css",
23
+ "types:check": "tsc --noEmit"
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "keywords": [
29
+ "pelatform",
30
+ "starter kit",
31
+ "components",
32
+ "utilities"
33
+ ],
34
+ "dependencies": {},
35
+ "devDependencies": {
36
+ "@pelatform/starter.config": "0.1.0",
37
+ "@pelatform/starter.hook": "0.1.1",
38
+ "@pelatform/starter.i18n": "0.1.2",
39
+ "@pelatform/starter.utils": "0.1.1",
40
+ "@pelatform/tsconfig": "^0.1.3",
41
+ "@types/react": "^19.2.7",
42
+ "lucide-react": "^0.556.0",
43
+ "next": "^16.0.7",
44
+ "next-intl": "^4.5.8",
45
+ "pelatform-ui": "^1.1.3",
46
+ "react": "^19.2.1",
47
+ "react-hook-form": "^7.68.0",
48
+ "tsup": "^8.5.1"
49
+ },
50
+ "peerDependencies": {
51
+ "@pelatform/starter.config": ">=0.1.0",
52
+ "@pelatform/starter.hook": ">=0.1.0",
53
+ "@pelatform/starter.i18n": ">=0.1.0",
54
+ "@pelatform/starter.utils": ">=0.1.0",
55
+ "lucide-react": ">=0.55.0",
56
+ "next": ">=16.0.0",
57
+ "next-intl": ">=4.5.0",
58
+ "pelatform-ui": ">=1.1.0",
59
+ "react": ">=18.0.0 || >=19.0.0-rc.0",
60
+ "react-hook-form": ">=7.5.0"
61
+ },
62
+ "publishConfig": {
63
+ "registry": "https://registry.npmjs.org/",
64
+ "access": "public"
65
+ },
66
+ "lint-staged": {
67
+ "*.{js,jsx,ts,tsx,cjs,mjs,cts,mts}": "biome check --write --no-errors-on-unmatched",
68
+ "*.{md,yml,yaml}": "prettier --write",
69
+ "*.{json,jsonc,html}": "biome format --write --no-errors-on-unmatched"
70
+ }
71
+ }