@tangle-network/blueprint-ui 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 +160 -0
- package/package.json +82 -0
- package/src/blueprints/registry.ts +107 -0
- package/src/components/forms/BlueprintJobForm.tsx +88 -0
- package/src/components/forms/FormField.tsx +206 -0
- package/src/components/forms/FormSummary.tsx +47 -0
- package/src/components/forms/JobExecutionDialog.tsx +203 -0
- package/src/components/layout/AppDocument.tsx +48 -0
- package/src/components/layout/AppFooter.tsx +38 -0
- package/src/components/layout/AppToaster.tsx +33 -0
- package/src/components/layout/ChainSwitcher.tsx +71 -0
- package/src/components/layout/ThemeToggle.tsx +18 -0
- package/src/components/layout/Web3Shell.tsx +28 -0
- package/src/components/motion/AnimatedPage.tsx +36 -0
- package/src/components/shared/Identicon.tsx +22 -0
- package/src/components/shared/TangleLogo.tsx +49 -0
- package/src/components/ui/badge.tsx +37 -0
- package/src/components/ui/button.tsx +61 -0
- package/src/components/ui/card.tsx +34 -0
- package/src/components/ui/dialog.tsx +59 -0
- package/src/components/ui/input.tsx +24 -0
- package/src/components/ui/select.tsx +80 -0
- package/src/components/ui/separator.tsx +25 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/table.tsx +49 -0
- package/src/components/ui/tabs.tsx +39 -0
- package/src/components/ui/textarea.tsx +23 -0
- package/src/components/ui/toggle.tsx +35 -0
- package/src/components.ts +51 -0
- package/src/contracts/abi.ts +259 -0
- package/src/contracts/chains.ts +100 -0
- package/src/contracts/generic-encoder.ts +69 -0
- package/src/contracts/publicClient.ts +55 -0
- package/src/env.d.ts +14 -0
- package/src/hooks/useAuthenticatedFetch.ts +57 -0
- package/src/hooks/useJobForm.ts +78 -0
- package/src/hooks/useJobPrice.ts +283 -0
- package/src/hooks/useOperators.ts +141 -0
- package/src/hooks/useProvisionProgress.ts +125 -0
- package/src/hooks/useQuotes.ts +261 -0
- package/src/hooks/useServiceValidation.ts +113 -0
- package/src/hooks/useSessionAuth.ts +103 -0
- package/src/hooks/useSubmitJob.ts +115 -0
- package/src/hooks/useThemeValue.ts +6 -0
- package/src/index.ts +79 -0
- package/src/preset.ts +61 -0
- package/src/stores/infra.ts +43 -0
- package/src/stores/persistedAtom.ts +67 -0
- package/src/stores/session.ts +64 -0
- package/src/stores/theme.ts +28 -0
- package/src/stores/txHistory.ts +47 -0
- package/src/utils/resolveOperatorRpc.ts +20 -0
- package/src/utils/web3.ts +21 -0
- package/src/utils.ts +6 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cn } from '../../utils';
|
|
3
|
+
|
|
4
|
+
function Card({ className, ...props }: React.ComponentProps<'div'>) {
|
|
5
|
+
return (
|
|
6
|
+
<div
|
|
7
|
+
data-slot="card"
|
|
8
|
+
className={cn('glass-card rounded-xl text-bp-elements-textPrimary', className)}
|
|
9
|
+
{...props}
|
|
10
|
+
/>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
15
|
+
return <div data-slot="card-header" className={cn('flex flex-col gap-1.5 p-6', className)} {...props} />;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
19
|
+
return <div data-slot="card-title" className={cn('leading-none font-semibold font-display', className)} {...props} />;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
|
|
23
|
+
return <div data-slot="card-description" className={cn('text-bp-elements-textSecondary text-sm', className)} {...props} />;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
27
|
+
return <div data-slot="card-content" className={cn('px-6 pb-6', className)} {...props} />;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
31
|
+
return <div data-slot="card-footer" className={cn('flex items-center px-6 pb-6', className)} {...props} />;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
3
|
+
import { cn } from '../../utils';
|
|
4
|
+
|
|
5
|
+
function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
6
|
+
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
10
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
14
|
+
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function DialogOverlay({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
18
|
+
return <DialogPrimitive.Overlay data-slot="dialog-overlay" className={cn('fixed inset-0 z-50 bg-black/50', className)} {...props} />;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function DialogContent({ className, children, ...props }: React.ComponentProps<typeof DialogPrimitive.Content>) {
|
|
22
|
+
return (
|
|
23
|
+
<DialogPortal>
|
|
24
|
+
<DialogOverlay />
|
|
25
|
+
<DialogPrimitive.Content
|
|
26
|
+
data-slot="dialog-content"
|
|
27
|
+
className={cn(
|
|
28
|
+
'bg-background fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-xl border border-border p-6 shadow-2xl duration-200 outline-none sm:max-w-lg',
|
|
29
|
+
className,
|
|
30
|
+
)}
|
|
31
|
+
{...props}
|
|
32
|
+
>
|
|
33
|
+
{children}
|
|
34
|
+
<DialogPrimitive.Close className="absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none">
|
|
35
|
+
<div className="i-ph:x size-4" />
|
|
36
|
+
<span className="sr-only">Close</span>
|
|
37
|
+
</DialogPrimitive.Close>
|
|
38
|
+
</DialogPrimitive.Content>
|
|
39
|
+
</DialogPortal>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
44
|
+
return <div data-slot="dialog-header" className={cn('flex flex-col gap-2 text-center sm:text-left', className)} {...props} />;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
48
|
+
return <div data-slot="dialog-footer" className={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)} {...props} />;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
52
|
+
return <DialogPrimitive.Title data-slot="dialog-title" className={cn('text-lg leading-none font-semibold', className)} {...props} />;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function DialogDescription({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
56
|
+
return <DialogPrimitive.Description data-slot="dialog-description" className={cn('text-muted-foreground text-sm', className)} {...props} />;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cn } from '../../utils';
|
|
3
|
+
|
|
4
|
+
function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
|
5
|
+
return (
|
|
6
|
+
<input
|
|
7
|
+
type={type}
|
|
8
|
+
data-slot="input"
|
|
9
|
+
className={cn(
|
|
10
|
+
'h-11 w-full min-w-0 rounded-lg px-3.5 py-2.5 text-base font-body',
|
|
11
|
+
'bg-bp-elements-background-depth-3 dark:bg-bp-elements-background-depth-4 border border-bp-elements-borderColor text-bp-elements-textPrimary',
|
|
12
|
+
'placeholder:text-bp-elements-textTertiary',
|
|
13
|
+
'transition-all duration-200 outline-none',
|
|
14
|
+
'hover:border-bp-elements-borderColorActive/40',
|
|
15
|
+
'focus-visible:border-violet-500/40 focus-visible:ring-2 focus-visible:ring-violet-500/10',
|
|
16
|
+
'disabled:pointer-events-none disabled:opacity-40',
|
|
17
|
+
className,
|
|
18
|
+
)}
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { Input };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
3
|
+
import { cn } from '../../utils';
|
|
4
|
+
|
|
5
|
+
export interface SelectOption {
|
|
6
|
+
label: string;
|
|
7
|
+
value: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface SelectProps {
|
|
11
|
+
value?: string;
|
|
12
|
+
onValueChange?: (value: string) => void;
|
|
13
|
+
options: SelectOption[];
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function Select({ value, onValueChange, options, placeholder, className, disabled }: SelectProps) {
|
|
20
|
+
return (
|
|
21
|
+
<SelectPrimitive.Root value={value} onValueChange={onValueChange} disabled={disabled}>
|
|
22
|
+
<SelectPrimitive.Trigger
|
|
23
|
+
className={cn(
|
|
24
|
+
'group flex h-11 w-full items-center justify-between rounded-lg px-3.5 py-2.5 text-base font-body',
|
|
25
|
+
'bg-bp-elements-background-depth-3 dark:bg-bp-elements-background-depth-4 border border-bp-elements-borderColor text-bp-elements-textPrimary',
|
|
26
|
+
'transition-all duration-200 outline-none',
|
|
27
|
+
'hover:border-bp-elements-borderColorActive/40',
|
|
28
|
+
'focus-visible:border-violet-500/40 focus-visible:ring-2 focus-visible:ring-violet-500/10',
|
|
29
|
+
'disabled:pointer-events-none disabled:opacity-40',
|
|
30
|
+
'data-[placeholder]:text-bp-elements-textTertiary',
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
>
|
|
34
|
+
<SelectPrimitive.Value placeholder={placeholder ?? 'Select...'} />
|
|
35
|
+
<SelectPrimitive.Icon className="ml-2 shrink-0 text-bp-elements-textTertiary transition-transform duration-200 group-data-[state=open]:rotate-180">
|
|
36
|
+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
|
37
|
+
<path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
38
|
+
</svg>
|
|
39
|
+
</SelectPrimitive.Icon>
|
|
40
|
+
</SelectPrimitive.Trigger>
|
|
41
|
+
|
|
42
|
+
<SelectPrimitive.Portal>
|
|
43
|
+
<SelectPrimitive.Content
|
|
44
|
+
position="popper"
|
|
45
|
+
sideOffset={4}
|
|
46
|
+
className={cn(
|
|
47
|
+
'relative z-50 max-h-[min(var(--radix-select-content-available-height),280px)] min-w-[var(--radix-select-trigger-width)] overflow-hidden',
|
|
48
|
+
'rounded-xl border border-white/[0.06] bg-neutral-900/95 backdrop-blur-xl shadow-2xl shadow-black/40',
|
|
49
|
+
'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-[0.98] data-[state=open]:slide-in-from-top-1',
|
|
50
|
+
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-[0.98] data-[state=closed]:slide-out-to-top-1',
|
|
51
|
+
)}
|
|
52
|
+
>
|
|
53
|
+
<SelectPrimitive.Viewport className="p-1.5">
|
|
54
|
+
{options.map((opt) => (
|
|
55
|
+
<SelectPrimitive.Item
|
|
56
|
+
key={opt.value}
|
|
57
|
+
value={opt.value}
|
|
58
|
+
className={cn(
|
|
59
|
+
'relative flex w-full cursor-pointer items-center rounded-lg px-3 py-2.5 text-sm font-body outline-none select-none',
|
|
60
|
+
'text-neutral-300 transition-colors duration-100',
|
|
61
|
+
'data-[highlighted]:bg-white/[0.06] data-[highlighted]:text-white',
|
|
62
|
+
'data-[state=checked]:text-violet-300',
|
|
63
|
+
)}
|
|
64
|
+
>
|
|
65
|
+
<SelectPrimitive.ItemText>{opt.label}</SelectPrimitive.ItemText>
|
|
66
|
+
<SelectPrimitive.ItemIndicator className="ml-auto pl-3">
|
|
67
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
|
|
68
|
+
<path d="M3 7.5L5.5 10L11 4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
69
|
+
</svg>
|
|
70
|
+
</SelectPrimitive.ItemIndicator>
|
|
71
|
+
</SelectPrimitive.Item>
|
|
72
|
+
))}
|
|
73
|
+
</SelectPrimitive.Viewport>
|
|
74
|
+
</SelectPrimitive.Content>
|
|
75
|
+
</SelectPrimitive.Portal>
|
|
76
|
+
</SelectPrimitive.Root>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { Select };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
|
3
|
+
import { cn } from '../../utils';
|
|
4
|
+
|
|
5
|
+
function Separator({
|
|
6
|
+
className,
|
|
7
|
+
orientation = 'horizontal',
|
|
8
|
+
decorative = true,
|
|
9
|
+
...props
|
|
10
|
+
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
|
|
11
|
+
return (
|
|
12
|
+
<SeparatorPrimitive.Root
|
|
13
|
+
data-slot="separator"
|
|
14
|
+
decorative={decorative}
|
|
15
|
+
orientation={orientation}
|
|
16
|
+
className={cn(
|
|
17
|
+
'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
|
|
18
|
+
className,
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { Separator };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { cn } from '../../utils';
|
|
2
|
+
|
|
3
|
+
function Skeleton({ className, ...props }: React.ComponentProps<'div'>) {
|
|
4
|
+
return (
|
|
5
|
+
<div
|
|
6
|
+
data-slot="skeleton"
|
|
7
|
+
className={cn('bg-accent animate-pulse rounded-md', className)}
|
|
8
|
+
{...props}
|
|
9
|
+
/>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export { Skeleton };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cn } from '../../utils';
|
|
3
|
+
|
|
4
|
+
function Table({ className, ...props }: React.ComponentProps<'table'>) {
|
|
5
|
+
return (
|
|
6
|
+
<div data-slot="table-container" className="glass-card rounded-xl overflow-hidden">
|
|
7
|
+
<div className="relative w-full overflow-auto">
|
|
8
|
+
<table data-slot="table" className={cn('w-full caption-bottom text-sm', className)} {...props} />
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function TableHeader({ className, ...props }: React.ComponentProps<'thead'>) {
|
|
15
|
+
return <thead data-slot="table-header" className={cn('border-b border-bp-elements-borderColor', className)} {...props} />;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function TableBody({ className, ...props }: React.ComponentProps<'tbody'>) {
|
|
19
|
+
return <tbody data-slot="table-body" className={cn('[&_tr:last-child]:border-0', className)} {...props} />;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function TableRow({ className, ...props }: React.ComponentProps<'tr'>) {
|
|
23
|
+
return (
|
|
24
|
+
<tr
|
|
25
|
+
data-slot="table-row"
|
|
26
|
+
className={cn(
|
|
27
|
+
'border-b border-bp-elements-dividerColor transition-colors duration-150 hover:bg-bp-elements-item-backgroundHover data-[state=selected]:bg-bp-elements-item-backgroundActive',
|
|
28
|
+
className,
|
|
29
|
+
)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function TableHead({ className, ...props }: React.ComponentProps<'th'>) {
|
|
36
|
+
return (
|
|
37
|
+
<th
|
|
38
|
+
data-slot="table-head"
|
|
39
|
+
className={cn('h-11 px-4 text-left align-middle font-data text-xs font-semibold uppercase tracking-wider text-bp-elements-textSecondary', className)}
|
|
40
|
+
{...props}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function TableCell({ className, ...props }: React.ComponentProps<'td'>) {
|
|
46
|
+
return <td data-slot="table-cell" className={cn('px-4 py-3 align-middle', className)} {...props} />;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { Table, TableHeader, TableBody, TableRow, TableHead, TableCell };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
|
3
|
+
import { cn } from '../../utils';
|
|
4
|
+
|
|
5
|
+
function Tabs({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
|
6
|
+
return <TabsPrimitive.Root data-slot="tabs" className={cn('flex flex-col gap-2', className)} {...props} />;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function TabsList({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.List>) {
|
|
10
|
+
return (
|
|
11
|
+
<TabsPrimitive.List
|
|
12
|
+
data-slot="tabs-list"
|
|
13
|
+
className={cn('glass-card inline-flex h-10 w-fit items-center justify-center rounded-xl p-1 gap-0.5', className)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
|
20
|
+
return (
|
|
21
|
+
<TabsPrimitive.Trigger
|
|
22
|
+
data-slot="tabs-trigger"
|
|
23
|
+
className={cn(
|
|
24
|
+
'inline-flex items-center justify-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium font-display whitespace-nowrap transition-all duration-200',
|
|
25
|
+
'text-bp-elements-textTertiary hover:text-bp-elements-textSecondary',
|
|
26
|
+
'data-[state=active]:text-violet-700 dark:data-[state=active]:text-violet-400 data-[state=active]:bg-violet-500/10 data-[state=active]:shadow-[0_0_12px_rgba(142,89,255,0.1)]',
|
|
27
|
+
'disabled:pointer-events-none disabled:opacity-40',
|
|
28
|
+
className,
|
|
29
|
+
)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
|
36
|
+
return <TabsPrimitive.Content data-slot="tabs-content" className={cn('flex-1 outline-none', className)} {...props} />;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cn } from '../../utils';
|
|
3
|
+
|
|
4
|
+
function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
|
|
5
|
+
return (
|
|
6
|
+
<textarea
|
|
7
|
+
data-slot="textarea"
|
|
8
|
+
className={cn(
|
|
9
|
+
'min-h-[80px] w-full rounded-lg px-3.5 py-2.5 text-base font-body resize-y',
|
|
10
|
+
'bg-bp-elements-background-depth-3 dark:bg-bp-elements-background-depth-4 border border-bp-elements-borderColor text-bp-elements-textPrimary',
|
|
11
|
+
'placeholder:text-bp-elements-textTertiary',
|
|
12
|
+
'transition-all duration-200 outline-none',
|
|
13
|
+
'hover:border-bp-elements-borderColorActive/40',
|
|
14
|
+
'focus-visible:border-violet-500/40 focus-visible:ring-2 focus-visible:ring-violet-500/10',
|
|
15
|
+
'disabled:pointer-events-none disabled:opacity-40',
|
|
16
|
+
className,
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { Textarea };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { cn } from '../../utils';
|
|
2
|
+
|
|
3
|
+
interface ToggleProps {
|
|
4
|
+
checked: boolean;
|
|
5
|
+
onChange: (checked: boolean) => void;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function Toggle({ checked, onChange, disabled, className }: ToggleProps) {
|
|
11
|
+
return (
|
|
12
|
+
<button
|
|
13
|
+
type="button"
|
|
14
|
+
role="switch"
|
|
15
|
+
aria-checked={checked}
|
|
16
|
+
disabled={disabled}
|
|
17
|
+
onClick={() => onChange(!checked)}
|
|
18
|
+
className={cn(
|
|
19
|
+
'relative w-11 h-6 rounded-full transition-colors',
|
|
20
|
+
checked ? 'bg-violet-600' : 'bg-bp-elements-background-depth-4',
|
|
21
|
+
disabled && 'opacity-40 pointer-events-none',
|
|
22
|
+
className,
|
|
23
|
+
)}
|
|
24
|
+
>
|
|
25
|
+
<span
|
|
26
|
+
className={cn(
|
|
27
|
+
'absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-white transition-transform',
|
|
28
|
+
checked && 'translate-x-5',
|
|
29
|
+
)}
|
|
30
|
+
/>
|
|
31
|
+
</button>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { Toggle };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @tangle-network/blueprint-ui — shared UI components.
|
|
3
|
+
*
|
|
4
|
+
* Separated from index.ts so tree-shaking works cleanly for
|
|
5
|
+
* consumers that only need hooks/stores/contracts.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ── UI Primitives ──
|
|
9
|
+
export { Badge, badgeVariants } from './components/ui/badge';
|
|
10
|
+
export { Button, buttonVariants } from './components/ui/button';
|
|
11
|
+
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from './components/ui/card';
|
|
12
|
+
export {
|
|
13
|
+
Dialog,
|
|
14
|
+
DialogTrigger,
|
|
15
|
+
DialogContent,
|
|
16
|
+
DialogHeader,
|
|
17
|
+
DialogFooter,
|
|
18
|
+
DialogTitle,
|
|
19
|
+
DialogDescription,
|
|
20
|
+
} from './components/ui/dialog';
|
|
21
|
+
export { Input } from './components/ui/input';
|
|
22
|
+
export type { SelectOption } from './components/ui/select';
|
|
23
|
+
export { Select } from './components/ui/select';
|
|
24
|
+
export { Separator } from './components/ui/separator';
|
|
25
|
+
export { Skeleton } from './components/ui/skeleton';
|
|
26
|
+
export { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from './components/ui/table';
|
|
27
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent } from './components/ui/tabs';
|
|
28
|
+
export { Textarea } from './components/ui/textarea';
|
|
29
|
+
export { Toggle } from './components/ui/toggle';
|
|
30
|
+
|
|
31
|
+
// ── Motion ──
|
|
32
|
+
export { AnimatedPage, StaggerContainer, StaggerItem } from './components/motion/AnimatedPage';
|
|
33
|
+
|
|
34
|
+
// ── Shared ──
|
|
35
|
+
export { Identicon } from './components/shared/Identicon';
|
|
36
|
+
export { TangleLogo } from './components/shared/TangleLogo';
|
|
37
|
+
|
|
38
|
+
// ── Layout ──
|
|
39
|
+
export { AppDocument } from './components/layout/AppDocument';
|
|
40
|
+
export { AppFooter } from './components/layout/AppFooter';
|
|
41
|
+
export { AppToaster } from './components/layout/AppToaster';
|
|
42
|
+
export { Web3Shell } from './components/layout/Web3Shell';
|
|
43
|
+
export { ChainSwitcher } from './components/layout/ChainSwitcher';
|
|
44
|
+
export { ThemeToggle } from './components/layout/ThemeToggle';
|
|
45
|
+
|
|
46
|
+
// ── Forms ──
|
|
47
|
+
export { FormField } from './components/forms/FormField';
|
|
48
|
+
export type { FormSection } from './components/forms/BlueprintJobForm';
|
|
49
|
+
export { BlueprintJobForm } from './components/forms/BlueprintJobForm';
|
|
50
|
+
export { FormSummary } from './components/forms/FormSummary';
|
|
51
|
+
export { JobExecutionDialog } from './components/forms/JobExecutionDialog';
|