@windrun-huaiin/third-ui 20.0.0 → 21.0.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/LICENSE +1 -1
- package/dist/clerk/clerk-page-generator.d.ts +0 -8
- package/dist/clerk/fingerprint/fingerprint-provider.js +58 -49
- package/dist/clerk/fingerprint/fingerprint-provider.mjs +58 -49
- package/dist/fuma/fuma-page-genarator.d.ts +2 -2
- package/dist/fuma/fuma-page-genarator.js +21 -8
- package/dist/fuma/fuma-page-genarator.mjs +21 -8
- package/dist/fuma/llm-copy-handler.js +3 -2
- package/dist/fuma/llm-copy-handler.mjs +3 -2
- package/dist/fuma/mdx/index.d.ts +1 -0
- package/dist/fuma/mdx/index.js +3 -0
- package/dist/fuma/mdx/index.mjs +1 -0
- package/dist/fuma/mdx/math.d.ts +17 -0
- package/dist/fuma/mdx/math.js +60 -0
- package/dist/fuma/mdx/math.mjs +57 -0
- package/dist/fuma/mdx/zia-card.js +1 -1
- package/dist/fuma/mdx/zia-card.mjs +1 -1
- package/dist/main/{ads-alert-dialog.d.ts → alert-dialog/ads-alert-dialog.d.ts} +1 -1
- package/dist/main/alert-dialog/ads-alert-dialog.js +24 -0
- package/dist/main/alert-dialog/ads-alert-dialog.mjs +22 -0
- package/dist/main/alert-dialog/confirm-dialog.d.ts +15 -0
- package/dist/main/alert-dialog/confirm-dialog.js +40 -0
- package/dist/main/alert-dialog/confirm-dialog.mjs +38 -0
- package/dist/main/alert-dialog/dialog-styles.d.ts +14 -0
- package/dist/main/alert-dialog/dialog-styles.js +35 -0
- package/dist/main/alert-dialog/dialog-styles.mjs +20 -0
- package/dist/main/alert-dialog/high-priority-confirm-dialog.d.ts +12 -0
- package/dist/main/alert-dialog/high-priority-confirm-dialog.js +23 -0
- package/dist/main/alert-dialog/high-priority-confirm-dialog.mjs +21 -0
- package/dist/main/alert-dialog/index.d.ts +4 -0
- package/dist/main/alert-dialog/info-dialog.d.ts +13 -0
- package/dist/main/alert-dialog/info-dialog.js +50 -0
- package/dist/main/alert-dialog/info-dialog.mjs +48 -0
- package/dist/main/index.d.ts +1 -1
- package/dist/main/index.js +7 -1
- package/dist/main/index.mjs +4 -1
- package/package.json +4 -4
- package/src/clerk/clerk-page-generator.tsx +0 -9
- package/src/clerk/fingerprint/fingerprint-provider.tsx +155 -62
- package/src/fuma/fuma-page-genarator.tsx +26 -9
- package/src/fuma/llm-copy-handler.ts +3 -3
- package/src/fuma/mdx/index.ts +1 -0
- package/src/fuma/mdx/math.tsx +130 -0
- package/src/fuma/mdx/zia-card.tsx +1 -0
- package/src/main/{ads-alert-dialog.tsx → alert-dialog/ads-alert-dialog.tsx} +46 -29
- package/src/main/alert-dialog/confirm-dialog.tsx +131 -0
- package/src/main/alert-dialog/dialog-styles.ts +73 -0
- package/src/main/alert-dialog/high-priority-confirm-dialog.tsx +94 -0
- package/src/main/alert-dialog/index.ts +7 -0
- package/src/main/alert-dialog/info-dialog.tsx +139 -0
- package/src/main/index.ts +1 -1
- package/src/main/language-detector.tsx +0 -8
- package/dist/main/ads-alert-dialog.js +0 -21
- package/dist/main/ads-alert-dialog.mjs +0 -19
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import katex from 'katex';
|
|
2
|
+
import { cn } from '@windrun-huaiin/lib/utils';
|
|
3
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
type MathSourceProps = {
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
math?: string;
|
|
8
|
+
formula?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type Align = 'left' | 'center' | 'right';
|
|
12
|
+
|
|
13
|
+
export type MathBlockProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> &
|
|
14
|
+
MathSourceProps & {
|
|
15
|
+
title?: ReactNode;
|
|
16
|
+
titleAlign?: Align;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type InlineMathProps = Omit<HTMLAttributes<HTMLSpanElement>, 'children'> &
|
|
20
|
+
MathSourceProps & {
|
|
21
|
+
align?: Align;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const alignClassMap: Record<Align, string> = {
|
|
25
|
+
left: 'text-left justify-start',
|
|
26
|
+
center: 'text-center justify-center',
|
|
27
|
+
right: 'text-right justify-end',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const textAlignClassMap: Record<Align, string> = {
|
|
31
|
+
left: 'text-left',
|
|
32
|
+
center: 'text-center',
|
|
33
|
+
right: 'text-right',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function getMathSource({ children, math, formula }: MathSourceProps): string {
|
|
37
|
+
if (typeof math === 'string' && math.trim() !== '') return math.trim();
|
|
38
|
+
if (typeof formula === 'string' && formula.trim() !== '') return formula.trim();
|
|
39
|
+
if (typeof children === 'string' && children.trim() !== '') return children.trim();
|
|
40
|
+
|
|
41
|
+
if (Array.isArray(children)) {
|
|
42
|
+
const text = children
|
|
43
|
+
.map((item) => (typeof item === 'string' ? item : ''))
|
|
44
|
+
.join('')
|
|
45
|
+
.trim();
|
|
46
|
+
|
|
47
|
+
if (text !== '') return text;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function renderMath(source: string, displayMode: boolean) {
|
|
54
|
+
if (source === '') return '';
|
|
55
|
+
|
|
56
|
+
return katex.renderToString(source, {
|
|
57
|
+
displayMode,
|
|
58
|
+
throwOnError: false,
|
|
59
|
+
output: 'html',
|
|
60
|
+
strict: 'ignore',
|
|
61
|
+
trust: false,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function MathBlock({
|
|
66
|
+
title,
|
|
67
|
+
titleAlign = 'center',
|
|
68
|
+
children,
|
|
69
|
+
math,
|
|
70
|
+
formula,
|
|
71
|
+
className,
|
|
72
|
+
...props
|
|
73
|
+
}: MathBlockProps) {
|
|
74
|
+
const source = getMathSource({ children, math, formula });
|
|
75
|
+
const html = renderMath(source, true);
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div
|
|
79
|
+
{...props}
|
|
80
|
+
className={cn(
|
|
81
|
+
'not-prose my-6 overflow-x-auto rounded-xl border bg-fd-card p-4 text-fd-card-foreground',
|
|
82
|
+
className,
|
|
83
|
+
)}
|
|
84
|
+
>
|
|
85
|
+
{title ? (
|
|
86
|
+
<div
|
|
87
|
+
className={cn(
|
|
88
|
+
'mb-3 text-sm font-medium text-fd-muted-foreground',
|
|
89
|
+
alignClassMap[titleAlign].split(' ')[0],
|
|
90
|
+
)}
|
|
91
|
+
>
|
|
92
|
+
{title}
|
|
93
|
+
</div>
|
|
94
|
+
) : null}
|
|
95
|
+
{html ? (
|
|
96
|
+
<div
|
|
97
|
+
className="min-w-fit [&_.katex-display]:my-0 [&_.katex-display]:overflow-x-auto [&_.katex-display]:overflow-y-hidden"
|
|
98
|
+
dangerouslySetInnerHTML={{ __html: html }}
|
|
99
|
+
/>
|
|
100
|
+
) : (
|
|
101
|
+
<div className="text-sm text-fd-muted-foreground">Empty math block.</div>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function InlineMath({
|
|
108
|
+
children,
|
|
109
|
+
math,
|
|
110
|
+
formula,
|
|
111
|
+
align = 'center',
|
|
112
|
+
className,
|
|
113
|
+
...props
|
|
114
|
+
}: InlineMathProps) {
|
|
115
|
+
const source = getMathSource({ children, math, formula });
|
|
116
|
+
const html = renderMath(source, false);
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<span
|
|
120
|
+
{...props}
|
|
121
|
+
className={cn(
|
|
122
|
+
'mx-1 inline-flex max-w-full align-middle rounded-md bg-neutral-200 px-2 py-0.5 text-sm leading-none dark:bg-white/20 [&_.katex]:text-inherit',
|
|
123
|
+
textAlignClassMap[align],
|
|
124
|
+
className,
|
|
125
|
+
)}
|
|
126
|
+
>
|
|
127
|
+
<span dangerouslySetInnerHTML={{ __html: html }} />
|
|
128
|
+
</span>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
@@ -22,6 +22,7 @@ export function ZiaCard({ icon, title, description, ...props }: ZiaCardProps) {
|
|
|
22
22
|
return (
|
|
23
23
|
<Link
|
|
24
24
|
href={props.href!}
|
|
25
|
+
prefetch={false}
|
|
25
26
|
data-card
|
|
26
27
|
className={cn(
|
|
27
28
|
'block rounded-lg border bg-fd-card p-4 text-fd-card-foreground shadow-md transition-colors @max-lg:col-span-full',
|
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React, { useState } from
|
|
4
|
-
import Image from
|
|
5
|
-
import {
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import Image from 'next/image';
|
|
5
|
+
import { BellIcon, ImageOffIcon, XIcon } from '@windrun-huaiin/base-ui/icons';
|
|
6
6
|
import {
|
|
7
7
|
AlertDialog,
|
|
8
|
+
AlertDialogAction,
|
|
8
9
|
AlertDialogContent,
|
|
9
|
-
AlertDialogTitle,
|
|
10
10
|
AlertDialogDescription,
|
|
11
|
-
|
|
12
|
-
} from
|
|
11
|
+
AlertDialogTitle,
|
|
12
|
+
} from '@windrun-huaiin/base-ui/ui';
|
|
13
|
+
import { cn } from '@windrun-huaiin/lib/utils';
|
|
14
|
+
import {
|
|
15
|
+
closeButtonClass,
|
|
16
|
+
dialogContentClass,
|
|
17
|
+
dialogDescriptionClass,
|
|
18
|
+
dialogFooterClass,
|
|
19
|
+
dialogHeaderClass,
|
|
20
|
+
dialogThemedOverlayClass,
|
|
21
|
+
dialogTitleClass,
|
|
22
|
+
primaryButtonClass,
|
|
23
|
+
secondaryButtonClass,
|
|
24
|
+
subtlePrimaryButtonClass,
|
|
25
|
+
} from './dialog-styles';
|
|
13
26
|
|
|
14
27
|
interface AdsAlertDialogProps {
|
|
15
28
|
open: boolean;
|
|
@@ -37,49 +50,52 @@ export function AdsAlertDialog({
|
|
|
37
50
|
onConfirm,
|
|
38
51
|
}: AdsAlertDialogProps) {
|
|
39
52
|
const [imgError, setImgError] = useState(false);
|
|
53
|
+
const handleClose = () => onOpenChange(false);
|
|
40
54
|
|
|
41
55
|
return (
|
|
42
56
|
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
|
43
57
|
<AlertDialogContent
|
|
44
|
-
className=
|
|
58
|
+
className={cn(dialogContentClass, 'max-w-md p-4')}
|
|
59
|
+
overlayClassName={dialogThemedOverlayClass}
|
|
60
|
+
onOverlayClick={handleClose}
|
|
45
61
|
>
|
|
46
|
-
{
|
|
47
|
-
<div className="flex flex-row items-center justify-between mb-2">
|
|
62
|
+
<div className={dialogHeaderClass}>
|
|
48
63
|
<AlertDialogTitle asChild>
|
|
49
|
-
<div className=
|
|
50
|
-
<
|
|
64
|
+
<div className={dialogTitleClass}>
|
|
65
|
+
<span className="inline-flex size-9 shrink-0 items-center justify-center rounded-full bg-neutral-100 text-neutral-600 ring-1 ring-neutral-200 dark:bg-neutral-900 dark:text-neutral-300 dark:ring-neutral-800">
|
|
66
|
+
<BellIcon className="size-5" />
|
|
67
|
+
</span>
|
|
51
68
|
<span className="truncate">{title}</span>
|
|
52
69
|
</div>
|
|
53
70
|
</AlertDialogTitle>
|
|
54
71
|
<button
|
|
55
|
-
|
|
56
|
-
|
|
72
|
+
type="button"
|
|
73
|
+
className={closeButtonClass}
|
|
74
|
+
onClick={handleClose}
|
|
57
75
|
aria-label="Close"
|
|
58
|
-
tabIndex={0}
|
|
59
76
|
>
|
|
60
|
-
<XIcon className="
|
|
77
|
+
<XIcon className="size-4" />
|
|
61
78
|
</button>
|
|
62
79
|
</div>
|
|
63
|
-
|
|
64
|
-
{
|
|
65
|
-
<AlertDialogDescription className="text-base font-medium text-neutral-800 dark:text-neutral-100 mb-2">
|
|
80
|
+
|
|
81
|
+
<AlertDialogDescription className={cn(dialogDescriptionClass, 'mb-3 text-base text-neutral-800 dark:text-neutral-100')}>
|
|
66
82
|
{description}
|
|
67
83
|
</AlertDialogDescription>
|
|
68
|
-
|
|
84
|
+
|
|
69
85
|
{imgSrc && (
|
|
70
|
-
<div className="w-full max-w-[400px]
|
|
86
|
+
<div className="relative mb-2 flex h-[220px] w-full max-w-[400px] items-center justify-center overflow-hidden rounded-xl border border-neutral-200 bg-neutral-50 dark:border-neutral-800 dark:bg-neutral-900">
|
|
71
87
|
{imgError ? (
|
|
72
|
-
<div className="absolute inset-0 flex flex-col items-center justify-center
|
|
73
|
-
<ImageOffIcon className="
|
|
88
|
+
<div className="absolute inset-0 flex flex-col items-center justify-center border border-dashed border-neutral-300 text-sm text-neutral-400 dark:border-neutral-700">
|
|
89
|
+
<ImageOffIcon className="mb-2 size-12" />
|
|
74
90
|
<span>Image loading failed</span>
|
|
75
91
|
</div>
|
|
76
92
|
) : imgHref ? (
|
|
77
|
-
<a href={imgHref} target="_blank" rel="noopener noreferrer" className="block
|
|
93
|
+
<a href={imgHref} target="_blank" rel="noopener noreferrer" className="block h-full w-full">
|
|
78
94
|
<Image
|
|
79
95
|
src={imgSrc}
|
|
80
96
|
alt="image"
|
|
81
97
|
fill
|
|
82
|
-
className="object-contain
|
|
98
|
+
className="rounded-lg object-contain"
|
|
83
99
|
priority={false}
|
|
84
100
|
placeholder="empty"
|
|
85
101
|
unoptimized
|
|
@@ -92,7 +108,7 @@ export function AdsAlertDialog({
|
|
|
92
108
|
src={imgSrc}
|
|
93
109
|
alt="image"
|
|
94
110
|
fill
|
|
95
|
-
className="object-contain
|
|
111
|
+
className="rounded-lg object-contain"
|
|
96
112
|
priority={false}
|
|
97
113
|
placeholder="empty"
|
|
98
114
|
unoptimized
|
|
@@ -102,16 +118,17 @@ export function AdsAlertDialog({
|
|
|
102
118
|
)}
|
|
103
119
|
</div>
|
|
104
120
|
)}
|
|
105
|
-
|
|
121
|
+
|
|
106
122
|
{(cancelText || confirmText) && (
|
|
107
|
-
<div className=
|
|
123
|
+
<div className={dialogFooterClass}>
|
|
108
124
|
{cancelText && (
|
|
109
125
|
<button
|
|
126
|
+
type="button"
|
|
110
127
|
onClick={() => {
|
|
111
128
|
onOpenChange(false);
|
|
112
129
|
onCancel?.();
|
|
113
130
|
}}
|
|
114
|
-
className=
|
|
131
|
+
className={secondaryButtonClass}
|
|
115
132
|
>
|
|
116
133
|
{cancelText}
|
|
117
134
|
</button>
|
|
@@ -122,7 +139,7 @@ export function AdsAlertDialog({
|
|
|
122
139
|
onOpenChange(false);
|
|
123
140
|
onConfirm?.();
|
|
124
141
|
}}
|
|
125
|
-
className=
|
|
142
|
+
className={confirmText && !cancelText ? subtlePrimaryButtonClass : primaryButtonClass}
|
|
126
143
|
>
|
|
127
144
|
{confirmText}
|
|
128
145
|
</AlertDialogAction>
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { CircleAlertIcon, CircleQuestionMarkIcon, XIcon } from '@windrun-huaiin/base-ui/icons';
|
|
5
|
+
import { themeBgColor, themeIconColor } from '@windrun-huaiin/base-ui/lib';
|
|
6
|
+
import {
|
|
7
|
+
AlertDialog,
|
|
8
|
+
AlertDialogAction,
|
|
9
|
+
AlertDialogCancel,
|
|
10
|
+
AlertDialogContent,
|
|
11
|
+
AlertDialogDescription,
|
|
12
|
+
AlertDialogTitle,
|
|
13
|
+
} from '@windrun-huaiin/base-ui/ui';
|
|
14
|
+
import { cn } from '@windrun-huaiin/lib/utils';
|
|
15
|
+
import {
|
|
16
|
+
closeButtonClass,
|
|
17
|
+
dangerButtonClass,
|
|
18
|
+
dialogContentClass,
|
|
19
|
+
dialogDescriptionClass,
|
|
20
|
+
dialogFooterClass,
|
|
21
|
+
dialogHeaderClass,
|
|
22
|
+
dialogThemedOverlayClass,
|
|
23
|
+
dialogTitleClass,
|
|
24
|
+
primaryButtonClass,
|
|
25
|
+
secondaryButtonClass,
|
|
26
|
+
} from './dialog-styles';
|
|
27
|
+
|
|
28
|
+
export type ConfirmDialogType = 'normal' | 'danger';
|
|
29
|
+
|
|
30
|
+
interface ConfirmDialogProps {
|
|
31
|
+
open: boolean;
|
|
32
|
+
onOpenChange: (open: boolean) => void;
|
|
33
|
+
type?: ConfirmDialogType;
|
|
34
|
+
title: React.ReactNode;
|
|
35
|
+
description: React.ReactNode;
|
|
36
|
+
cancelText?: string;
|
|
37
|
+
confirmText?: string;
|
|
38
|
+
onCancel?: () => void;
|
|
39
|
+
onConfirm?: () => void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const confirmTypeClassMap: Record<ConfirmDialogType, {
|
|
43
|
+
content: string;
|
|
44
|
+
iconWrap: string;
|
|
45
|
+
icon: string;
|
|
46
|
+
action: string;
|
|
47
|
+
Icon: typeof CircleQuestionMarkIcon;
|
|
48
|
+
}> = {
|
|
49
|
+
normal: {
|
|
50
|
+
content: '',
|
|
51
|
+
iconWrap: cn(themeBgColor, 'ring-0'),
|
|
52
|
+
icon: themeIconColor,
|
|
53
|
+
action: primaryButtonClass,
|
|
54
|
+
Icon: CircleQuestionMarkIcon,
|
|
55
|
+
},
|
|
56
|
+
danger: {
|
|
57
|
+
content: 'border-red-300 dark:border-red-700',
|
|
58
|
+
iconWrap: 'bg-red-100 text-red-600 ring-red-200 dark:bg-red-950 dark:text-red-300 dark:ring-red-900',
|
|
59
|
+
icon: 'text-red-600 dark:text-red-300',
|
|
60
|
+
action: dangerButtonClass,
|
|
61
|
+
Icon: CircleAlertIcon,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export function ConfirmDialog({
|
|
66
|
+
open,
|
|
67
|
+
onOpenChange,
|
|
68
|
+
type = 'normal',
|
|
69
|
+
title,
|
|
70
|
+
description,
|
|
71
|
+
cancelText = 'Cancel',
|
|
72
|
+
confirmText = 'Confirm',
|
|
73
|
+
onCancel,
|
|
74
|
+
onConfirm,
|
|
75
|
+
}: ConfirmDialogProps) {
|
|
76
|
+
const typeClass = confirmTypeClassMap[type];
|
|
77
|
+
const Icon = typeClass.Icon;
|
|
78
|
+
|
|
79
|
+
const handleCancel = () => {
|
|
80
|
+
onOpenChange(false);
|
|
81
|
+
onCancel?.();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
|
86
|
+
<AlertDialogContent
|
|
87
|
+
className={cn(dialogContentClass, typeClass.content)}
|
|
88
|
+
overlayClassName={dialogThemedOverlayClass}
|
|
89
|
+
onOverlayClick={handleCancel}
|
|
90
|
+
>
|
|
91
|
+
<div className={dialogHeaderClass}>
|
|
92
|
+
<AlertDialogTitle asChild>
|
|
93
|
+
<div className={dialogTitleClass}>
|
|
94
|
+
<span className={cn('inline-flex size-9 shrink-0 items-center justify-center rounded-full ring-1', typeClass.iconWrap)}>
|
|
95
|
+
<Icon className={cn('size-5', typeClass.icon)} />
|
|
96
|
+
</span>
|
|
97
|
+
<span className="min-w-0 truncate">{title}</span>
|
|
98
|
+
</div>
|
|
99
|
+
</AlertDialogTitle>
|
|
100
|
+
<button
|
|
101
|
+
type="button"
|
|
102
|
+
className={closeButtonClass}
|
|
103
|
+
onClick={handleCancel}
|
|
104
|
+
aria-label="Close"
|
|
105
|
+
>
|
|
106
|
+
<XIcon className="size-4" />
|
|
107
|
+
</button>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<AlertDialogDescription className={dialogDescriptionClass}>
|
|
111
|
+
{description}
|
|
112
|
+
</AlertDialogDescription>
|
|
113
|
+
|
|
114
|
+
<div className={dialogFooterClass}>
|
|
115
|
+
<AlertDialogCancel className={secondaryButtonClass} onClick={handleCancel}>
|
|
116
|
+
{cancelText}
|
|
117
|
+
</AlertDialogCancel>
|
|
118
|
+
<AlertDialogAction
|
|
119
|
+
className={typeClass.action}
|
|
120
|
+
onClick={() => {
|
|
121
|
+
onOpenChange(false);
|
|
122
|
+
onConfirm?.();
|
|
123
|
+
}}
|
|
124
|
+
>
|
|
125
|
+
{confirmText}
|
|
126
|
+
</AlertDialogAction>
|
|
127
|
+
</div>
|
|
128
|
+
</AlertDialogContent>
|
|
129
|
+
</AlertDialog>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
themeBgColor,
|
|
5
|
+
themeBorderColor,
|
|
6
|
+
themeButtonGradientClass,
|
|
7
|
+
themeButtonGradientHoverClass,
|
|
8
|
+
themeIconColor,
|
|
9
|
+
themeMainBgColor,
|
|
10
|
+
themeRingColor,
|
|
11
|
+
} from '@windrun-huaiin/base-ui/lib';
|
|
12
|
+
import { cn } from '@windrun-huaiin/lib/utils';
|
|
13
|
+
|
|
14
|
+
export const dialogSurfaceClass = cn(
|
|
15
|
+
'w-[calc(100vw-2rem)] max-w-md rounded-2xl border bg-white p-5 text-neutral-950 shadow-2xl outline-none dark:bg-neutral-950 dark:text-neutral-50',
|
|
16
|
+
'border-neutral-200 dark:border-neutral-800'
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export const dialogThemedOverlayClass = cn(
|
|
20
|
+
themeMainBgColor,
|
|
21
|
+
'opacity-90 backdrop-blur-[2px] dark:opacity-85'
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export const dialogContentClass = cn(
|
|
25
|
+
'fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2',
|
|
26
|
+
dialogSurfaceClass
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export const dialogHeaderClass = 'flex items-start justify-between gap-4';
|
|
30
|
+
|
|
31
|
+
export const dialogTitleClass =
|
|
32
|
+
'flex min-w-0 items-center gap-2 text-lg font-bold leading-tight text-neutral-950 dark:text-neutral-50';
|
|
33
|
+
|
|
34
|
+
export const dialogDescriptionClass =
|
|
35
|
+
'mt-3 text-sm font-medium leading-relaxed text-neutral-600 dark:text-neutral-300';
|
|
36
|
+
|
|
37
|
+
export const dialogFooterClass = 'mt-6 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end';
|
|
38
|
+
|
|
39
|
+
export const closeButtonClass =
|
|
40
|
+
'inline-flex size-8 shrink-0 items-center justify-center rounded-full text-neutral-400 transition hover:bg-neutral-100 hover:text-neutral-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-neutral-200';
|
|
41
|
+
|
|
42
|
+
export const secondaryButtonClass =
|
|
43
|
+
'inline-flex min-h-10 items-center justify-center rounded-full border border-neutral-300 bg-white px-5 py-2 text-sm font-semibold text-neutral-700 transition hover:bg-neutral-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400 disabled:pointer-events-none disabled:opacity-60 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-200 dark:hover:bg-neutral-800';
|
|
44
|
+
|
|
45
|
+
export const primaryButtonClass = cn(
|
|
46
|
+
'inline-flex min-h-10 items-center justify-center rounded-full px-5 py-2 text-sm font-bold text-white shadow-sm transition hover:shadow-md focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-60',
|
|
47
|
+
themeButtonGradientClass,
|
|
48
|
+
themeButtonGradientHoverClass,
|
|
49
|
+
themeRingColor
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
export const subtlePrimaryButtonClass = cn(
|
|
53
|
+
'inline-flex min-h-10 items-center justify-center rounded-full border px-5 py-2 text-sm font-bold transition hover:brightness-95 focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-60',
|
|
54
|
+
themeBgColor,
|
|
55
|
+
themeBorderColor,
|
|
56
|
+
themeIconColor,
|
|
57
|
+
themeRingColor
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
export const dangerButtonClass =
|
|
61
|
+
'inline-flex min-h-10 items-center justify-center rounded-full bg-red-600 px-5 py-2 text-sm font-bold text-white shadow-sm transition hover:bg-red-700 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500 disabled:pointer-events-none disabled:opacity-60 dark:bg-red-600 dark:hover:bg-red-500';
|
|
62
|
+
|
|
63
|
+
export const highPriorityTitleClass = cn(
|
|
64
|
+
'flex min-w-0 items-center gap-2 text-lg font-bold leading-tight',
|
|
65
|
+
themeIconColor
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
export const highPrioritySurfaceClass = cn(
|
|
69
|
+
dialogSurfaceClass,
|
|
70
|
+
'backdrop-blur-md ring-4 animate-in zoom-in-95 duration-300',
|
|
71
|
+
themeBorderColor,
|
|
72
|
+
themeRingColor
|
|
73
|
+
);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { useEffect, useState } from "react";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
5
|
+
import { FAQSIcon, XIcon } from "@windrun-huaiin/base-ui/icons";
|
|
6
|
+
import { cn } from "@windrun-huaiin/lib/utils";
|
|
7
|
+
import {
|
|
8
|
+
closeButtonClass,
|
|
9
|
+
dialogDescriptionClass,
|
|
10
|
+
dialogFooterClass,
|
|
11
|
+
dialogHeaderClass,
|
|
12
|
+
highPrioritySurfaceClass,
|
|
13
|
+
highPriorityTitleClass,
|
|
14
|
+
primaryButtonClass,
|
|
15
|
+
secondaryButtonClass,
|
|
16
|
+
} from "./dialog-styles";
|
|
17
|
+
import { themeBgColor, themeBorderColor, themeIconColor } from "@windrun-huaiin/base-ui/lib";
|
|
18
|
+
|
|
19
|
+
interface HighPriorityConfirmDialogProps {
|
|
20
|
+
open: boolean;
|
|
21
|
+
onCancel: () => void;
|
|
22
|
+
onConfirm: () => void;
|
|
23
|
+
title: string;
|
|
24
|
+
description: React.ReactNode;
|
|
25
|
+
confirmText?: string;
|
|
26
|
+
cancelText?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function HighPriorityConfirmDialog({
|
|
30
|
+
open,
|
|
31
|
+
onCancel,
|
|
32
|
+
onConfirm,
|
|
33
|
+
title,
|
|
34
|
+
description,
|
|
35
|
+
confirmText = "Confirm",
|
|
36
|
+
cancelText = "Cancel",
|
|
37
|
+
}: HighPriorityConfirmDialogProps) {
|
|
38
|
+
const [mounted, setMounted] = useState(false);
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
// Ensure portal target exists and prevent hydration mismatch
|
|
42
|
+
setTimeout(() => setMounted(true), 0);
|
|
43
|
+
}, []);
|
|
44
|
+
|
|
45
|
+
if (!open || !mounted) return null;
|
|
46
|
+
|
|
47
|
+
return createPortal(
|
|
48
|
+
<div className="fixed inset-0 z-10000 flex items-center justify-center bg-black/60 backdrop-blur-sm animate-in fade-in duration-300">
|
|
49
|
+
<div
|
|
50
|
+
className={cn(highPrioritySurfaceClass, "scale-100")}
|
|
51
|
+
role="dialog"
|
|
52
|
+
aria-modal="true"
|
|
53
|
+
onClick={(e) => e.stopPropagation()}
|
|
54
|
+
>
|
|
55
|
+
<div className={dialogHeaderClass}>
|
|
56
|
+
<h3 className={highPriorityTitleClass}>
|
|
57
|
+
<span className={cn('inline-flex size-9 shrink-0 items-center justify-center rounded-full ring-1', themeBgColor, themeBorderColor)}>
|
|
58
|
+
<FAQSIcon className={cn('size-5', themeIconColor)} />
|
|
59
|
+
</span>
|
|
60
|
+
<span className="min-w-0 truncate">{title}</span>
|
|
61
|
+
</h3>
|
|
62
|
+
<button
|
|
63
|
+
type="button"
|
|
64
|
+
className={closeButtonClass}
|
|
65
|
+
onClick={onCancel}
|
|
66
|
+
aria-label="Close"
|
|
67
|
+
>
|
|
68
|
+
<XIcon className="size-4" />
|
|
69
|
+
</button>
|
|
70
|
+
</div>
|
|
71
|
+
<div className={dialogDescriptionClass}>
|
|
72
|
+
{description}
|
|
73
|
+
</div>
|
|
74
|
+
<div className={dialogFooterClass}>
|
|
75
|
+
<button
|
|
76
|
+
type="button"
|
|
77
|
+
onClick={onCancel}
|
|
78
|
+
className={secondaryButtonClass}
|
|
79
|
+
>
|
|
80
|
+
{cancelText}
|
|
81
|
+
</button>
|
|
82
|
+
<button
|
|
83
|
+
type="button"
|
|
84
|
+
onClick={onConfirm}
|
|
85
|
+
className={cn(primaryButtonClass, "hover:scale-105 active:scale-95")}
|
|
86
|
+
>
|
|
87
|
+
{confirmText}
|
|
88
|
+
</button>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</div>,
|
|
92
|
+
document.body
|
|
93
|
+
);
|
|
94
|
+
}
|