@mrigx/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/package.json +73 -0
- package/src/blocks/ContactPanel.tsx +99 -0
- package/src/blocks/FeatureGrid.tsx +38 -0
- package/src/blocks/OpticalCTA.tsx +33 -0
- package/src/blocks/OpticalHero.tsx +51 -0
- package/src/blocks/styles.ts +175 -0
- package/src/components/accordion/optical-accordion.tsx +199 -0
- package/src/components/alert/optical-alert.tsx +59 -0
- package/src/components/alert-dialog/optical-alert-dialog.tsx +143 -0
- package/src/components/ambient-light.tsx +27 -0
- package/src/components/aspect-ratio/optical-aspect-ratio.tsx +7 -0
- package/src/components/attachment/optical-attachment.tsx +25 -0
- package/src/components/avatar/optical-avatar.tsx +50 -0
- package/src/components/badge/optical-badge.tsx +36 -0
- package/src/components/breadcrumb/optical-breadcrumb.tsx +115 -0
- package/src/components/bubble/optical-bubble.tsx +25 -0
- package/src/components/button/optical-button.tsx +67 -0
- package/src/components/button-group/optical-button-group.tsx +83 -0
- package/src/components/calendar/optical-calendar.tsx +214 -0
- package/src/components/card/optical-card.tsx +44 -0
- package/src/components/carousel/optical-carousel.tsx +262 -0
- package/src/components/chart/optical-chart.tsx +369 -0
- package/src/components/checkbox/optical-checkbox.tsx +42 -0
- package/src/components/collapsible/optical-collapsible.tsx +11 -0
- package/src/components/combobox/optical-combobox.tsx +25 -0
- package/src/components/command/optical-command.tsx +153 -0
- package/src/components/context-menu/optical-context-menu.tsx +201 -0
- package/src/components/cursor/optical-cursor.tsx +10 -0
- package/src/components/data-table/optical-data-table.tsx +25 -0
- package/src/components/date-picker/optical-date-picker.tsx +25 -0
- package/src/components/dialog/optical-dialog.tsx +110 -0
- package/src/components/direction/optical-direction.tsx +25 -0
- package/src/components/drawer/optical-drawer.tsx +120 -0
- package/src/components/dropdown-menu/optical-dropdown-menu.tsx +194 -0
- package/src/components/empty/optical-empty.tsx +104 -0
- package/src/components/field/optical-field.tsx +244 -0
- package/src/components/glass-card.tsx +13 -0
- package/src/components/hover-card/optical-hover-card.tsx +30 -0
- package/src/components/icon-button/optical-icon-button.tsx +22 -0
- package/src/components/input/optical-input.tsx +29 -0
- package/src/components/input-group/optical-input-group.tsx +170 -0
- package/src/components/input-otp/optical-input-otp.tsx +71 -0
- package/src/components/item/optical-item.tsx +193 -0
- package/src/components/kbd/optical-kbd.tsx +28 -0
- package/src/components/label/optical-label.tsx +25 -0
- package/src/components/marker/optical-marker.tsx +25 -0
- package/src/components/menubar/optical-menubar.tsx +257 -0
- package/src/components/message/optical-message.tsx +25 -0
- package/src/components/message-scroller/optical-message-scroller.tsx +25 -0
- package/src/components/native-select/optical-native-select.tsx +25 -0
- package/src/components/navigation-menu/optical-navigation-menu.tsx +68 -0
- package/src/components/pagination/optical-pagination.tsx +118 -0
- package/src/components/panel/optical-panel.tsx +26 -0
- package/src/components/popover/optical-popover.tsx +32 -0
- package/src/components/prism-button.tsx +17 -0
- package/src/components/progress/optical-progress.tsx +28 -0
- package/src/components/questionnaire/optical-questionnaire.tsx +25 -0
- package/src/components/radio-group/optical-radio-group.tsx +25 -0
- package/src/components/resizable/optical-resizable.tsx +45 -0
- package/src/components/scroll-area/optical-scroll-area.tsx +48 -0
- package/src/components/select/optical-select.tsx +110 -0
- package/src/components/separator/optical-separator.tsx +31 -0
- package/src/components/sheet/optical-sheet.tsx +143 -0
- package/src/components/sidebar/optical-sidebar.tsx +762 -0
- package/src/components/skeleton/optical-skeleton.tsx +15 -0
- package/src/components/slider/optical-slider.tsx +34 -0
- package/src/components/sonner/optical-toast.tsx +45 -0
- package/src/components/spinner/optical-spinner.tsx +16 -0
- package/src/components/stained-glass-card.tsx +93 -0
- package/src/components/switch/optical-switch.tsx +31 -0
- package/src/components/table/optical-table.tsx +83 -0
- package/src/components/tabs/optical-tabs.tsx +56 -0
- package/src/components/text/liquid-tension-text.tsx +65 -0
- package/src/components/text/optical-tension-text.tsx +65 -0
- package/src/components/text/optical-text.tsx +20 -0
- package/src/components/text/prismatic-selection.tsx +5 -0
- package/src/components/textarea/optical-textarea.tsx +22 -0
- package/src/components/theme-toggle/optical-theme-toggle.tsx +45 -0
- package/src/components/toast/optical-toast.tsx +25 -0
- package/src/components/toggle/optical-toggle.tsx +45 -0
- package/src/components/toggle-group/optical-toggle-group.tsx +61 -0
- package/src/components/tooltip/optical-tooltip.tsx +33 -0
- package/src/components/typography/optical-typography.tsx +49 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/index.ts +88 -0
- package/src/templates/ContactPageTemplate.tsx +42 -0
- package/src/templates/LandingPageTemplate.tsx +29 -0
- package/src/templates/ProductPageTemplate.tsx +46 -0
- package/src/templates/styles.ts +23 -0
- package/src/utils/button-variants.ts +26 -0
- package/src/utils/cn.ts +6 -0
- package/tsconfig.json +27 -0
- package/vite.config.ts +42 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { cn } from '../../utils/cn';
|
|
2
|
+
|
|
3
|
+
function Skeleton({
|
|
4
|
+
className,
|
|
5
|
+
...props
|
|
6
|
+
}: React.HTMLAttributes<HTMLDivElement>) {
|
|
7
|
+
return (
|
|
8
|
+
<div
|
|
9
|
+
className={cn("animate-pulse rounded-md bg-white/10", className)}
|
|
10
|
+
{...props}
|
|
11
|
+
/>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { Skeleton }
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as SliderPrimitive from "@radix-ui/react-slider"
|
|
5
|
+
import { useMrigSurface } from '@mrigx/react';
|
|
6
|
+
import { cn } from '../../utils/cn';
|
|
7
|
+
|
|
8
|
+
const Slider = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof SliderPrimitive.Root>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
|
|
11
|
+
>(({ className, ...props }, forwardedRef) => {
|
|
12
|
+
const mrigRef = useMrigSurface<HTMLSpanElement>({ material: 'none', isDynamic: true }, forwardedRef as any);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<SliderPrimitive.Root
|
|
16
|
+
ref={mrigRef as any}
|
|
17
|
+
className={cn(
|
|
18
|
+
"relative flex w-full touch-none select-none items-center group",
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
>
|
|
23
|
+
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-white/[0.05] border border-white/10 shadow-[inset_0_1px_3px_rgba(0,0,0,0.8)]">
|
|
24
|
+
<SliderPrimitive.Range className="absolute h-full bg-gradient-to-r from-white/10 to-white/40 shadow-[0_0_10px_rgba(255,255,255,0.2)]" />
|
|
25
|
+
</SliderPrimitive.Track>
|
|
26
|
+
<SliderPrimitive.Thumb className="block h-6 w-6 rounded-full border border-white/30 bg-black/40 backdrop-blur-xl shadow-[0_4px_12px_rgba(0,0,0,0.8),inset_0_1px_2px_rgba(255,255,255,0.4)] transition-all hover:bg-white/10 hover:border-white/50 hover:scale-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/20 focus-visible:ring-offset-2 focus-visible:ring-offset-black disabled:pointer-events-none disabled:opacity-50 cursor-grab active:cursor-grabbing active:scale-95 flex items-center justify-center">
|
|
27
|
+
<div className="w-2 h-2 rounded-full bg-white/50 shadow-[0_0_5px_rgba(255,255,255,0.5)] transition-all group-hover:bg-white" />
|
|
28
|
+
</SliderPrimitive.Thumb>
|
|
29
|
+
</SliderPrimitive.Root>
|
|
30
|
+
);
|
|
31
|
+
})
|
|
32
|
+
Slider.displayName = SliderPrimitive.Root.displayName
|
|
33
|
+
|
|
34
|
+
export { Slider }
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
CircleCheck,
|
|
5
|
+
Info,
|
|
6
|
+
LoaderCircle,
|
|
7
|
+
OctagonX,
|
|
8
|
+
TriangleAlert,
|
|
9
|
+
} from "lucide-react"
|
|
10
|
+
import { useTheme } from "next-themes"
|
|
11
|
+
import { Toaster as Sonner } from "sonner"
|
|
12
|
+
|
|
13
|
+
type ToasterProps = React.ComponentProps<typeof Sonner>
|
|
14
|
+
|
|
15
|
+
const Toaster = ({ ...props }: ToasterProps) => {
|
|
16
|
+
const { theme = "system" } = useTheme()
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Sonner
|
|
20
|
+
theme={theme as ToasterProps["theme"]}
|
|
21
|
+
className="toaster group"
|
|
22
|
+
icons={{
|
|
23
|
+
success: <CircleCheck className="h-4 w-4" />,
|
|
24
|
+
info: <Info className="h-4 w-4" />,
|
|
25
|
+
warning: <TriangleAlert className="h-4 w-4" />,
|
|
26
|
+
error: <OctagonX className="h-4 w-4" />,
|
|
27
|
+
loading: <LoaderCircle className="h-4 w-4 animate-spin" />,
|
|
28
|
+
}}
|
|
29
|
+
toastOptions={{
|
|
30
|
+
classNames: {
|
|
31
|
+
toast:
|
|
32
|
+
"group toast group-[.toaster]:bg-transparent group-[.toaster]:text-white group-[.toaster]:border-white/10 group-[.toaster]:shadow-lg",
|
|
33
|
+
description: "group-[.toast]:text-white/50",
|
|
34
|
+
actionButton:
|
|
35
|
+
"group-[.toast]:bg-white/20 group-[.toast]:text-white",
|
|
36
|
+
cancelButton:
|
|
37
|
+
"group-[.toast]:bg-white/10 group-[.toast]:text-white/50",
|
|
38
|
+
},
|
|
39
|
+
}}
|
|
40
|
+
{...props}
|
|
41
|
+
/>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { Toaster }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Loader2Icon } from "lucide-react"
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../utils/cn';
|
|
4
|
+
|
|
5
|
+
function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
|
|
6
|
+
return (
|
|
7
|
+
<Loader2Icon
|
|
8
|
+
role="status"
|
|
9
|
+
aria-label="Loading"
|
|
10
|
+
className={cn("size-4 animate-spin", className)}
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { Spinner }
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { useMrigSurface, useMrigInteraction } from '@mrigx/react';
|
|
3
|
+
import { type OpticalMaterial } from '@mrigx/core';
|
|
4
|
+
|
|
5
|
+
export interface StainedGlassCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
6
|
+
material?: OpticalMaterial;
|
|
7
|
+
materialStrength?: number;
|
|
8
|
+
glowColor?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const StainedGlassCard = forwardRef<HTMLDivElement, StainedGlassCardProps>(({
|
|
12
|
+
children,
|
|
13
|
+
material = 'glass',
|
|
14
|
+
materialStrength = 1.0,
|
|
15
|
+
glowColor = "rgba(217, 70, 239, 0.3)", // fuchsia-500/30
|
|
16
|
+
className = "",
|
|
17
|
+
style,
|
|
18
|
+
onClick,
|
|
19
|
+
...props
|
|
20
|
+
}, forwardedRef) => {
|
|
21
|
+
// We use useMrigSurface to create a thick optical refractive layer
|
|
22
|
+
const rootRef = useMrigSurface<HTMLDivElement>({
|
|
23
|
+
material,
|
|
24
|
+
materialStrength: 1.0,
|
|
25
|
+
borderRadius: 16
|
|
26
|
+
}, forwardedRef);
|
|
27
|
+
|
|
28
|
+
const { pulseCenter } = useMrigInteraction();
|
|
29
|
+
|
|
30
|
+
const containerStyle: React.CSSProperties = {
|
|
31
|
+
minHeight: '16rem',
|
|
32
|
+
width: '100%',
|
|
33
|
+
border: '1px solid rgba(255, 255, 255, 0.05)',
|
|
34
|
+
backgroundColor: 'rgba(255, 255, 255, 0.01)',
|
|
35
|
+
borderRadius: '1rem',
|
|
36
|
+
display: 'flex',
|
|
37
|
+
alignItems: 'center',
|
|
38
|
+
justifyContent: 'center',
|
|
39
|
+
position: 'relative',
|
|
40
|
+
overflow: 'hidden',
|
|
41
|
+
cursor: 'crosshair',
|
|
42
|
+
...style
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const glowStyle: React.CSSProperties = {
|
|
46
|
+
position: 'absolute',
|
|
47
|
+
width: '50%',
|
|
48
|
+
height: '50%',
|
|
49
|
+
borderRadius: '9999px',
|
|
50
|
+
filter: 'blur(40px)',
|
|
51
|
+
pointerEvents: 'none',
|
|
52
|
+
backgroundColor: glowColor,
|
|
53
|
+
zIndex: 0,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const innerStyle: React.CSSProperties = {
|
|
57
|
+
position: 'relative',
|
|
58
|
+
zIndex: 1,
|
|
59
|
+
width: '80%',
|
|
60
|
+
minHeight: '8rem',
|
|
61
|
+
padding: '2rem',
|
|
62
|
+
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
63
|
+
borderRadius: '0.75rem',
|
|
64
|
+
backgroundColor: 'rgba(255, 255, 255, 0.02)',
|
|
65
|
+
display: 'flex',
|
|
66
|
+
flexDirection: 'column',
|
|
67
|
+
alignItems: 'center',
|
|
68
|
+
justifyContent: 'center',
|
|
69
|
+
pointerEvents: 'none', // let clicks fall through to root
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
ref={rootRef}
|
|
75
|
+
style={containerStyle}
|
|
76
|
+
className={className}
|
|
77
|
+
onClick={(e) => {
|
|
78
|
+
pulseCenter(e.currentTarget, 0.3);
|
|
79
|
+
onClick?.(e);
|
|
80
|
+
}}
|
|
81
|
+
{...props}
|
|
82
|
+
>
|
|
83
|
+
<div style={glowStyle} />
|
|
84
|
+
<div style={innerStyle}>
|
|
85
|
+
{children}
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
StainedGlassCard.displayName = 'StainedGlassCard';
|
|
92
|
+
|
|
93
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
|
5
|
+
|
|
6
|
+
import { cn } from '../../utils/cn';
|
|
7
|
+
|
|
8
|
+
const Switch = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof SwitchPrimitives.Root>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
|
11
|
+
>(({ className, ...props }, ref) => (
|
|
12
|
+
<SwitchPrimitives.Root
|
|
13
|
+
className={cn(
|
|
14
|
+
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border border-white/10 transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/20 focus-visible:ring-offset-2 focus-visible:ring-offset-black disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-white/20 data-[state=unchecked]:bg-white/5 data-[state=checked]:shadow-[inset_0_1px_3px_rgba(255,255,255,0.2)] data-[state=unchecked]:shadow-[inset_0_1px_3px_rgba(0,0,0,0.8)]",
|
|
15
|
+
className
|
|
16
|
+
)}
|
|
17
|
+
{...props}
|
|
18
|
+
ref={ref}
|
|
19
|
+
>
|
|
20
|
+
<SwitchPrimitives.Thumb
|
|
21
|
+
className={cn(
|
|
22
|
+
"pointer-events-none block h-5 w-5 rounded-full border border-white/30 bg-black/40 backdrop-blur-xl shadow-[0_4px_12px_rgba(0,0,0,0.8),inset_0_1px_2px_rgba(255,255,255,0.4)] ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0 flex items-center justify-center"
|
|
23
|
+
)}
|
|
24
|
+
>
|
|
25
|
+
<div className="w-1.5 h-1.5 rounded-full bg-white/50 transition-colors" />
|
|
26
|
+
</SwitchPrimitives.Thumb>
|
|
27
|
+
</SwitchPrimitives.Root>
|
|
28
|
+
))
|
|
29
|
+
Switch.displayName = SwitchPrimitives.Root.displayName
|
|
30
|
+
|
|
31
|
+
export { Switch }
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { GlassSurface } from '@mrigx/fx';
|
|
3
|
+
|
|
4
|
+
const OpticalTable = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(({ className = "", ...props }, ref) => (
|
|
5
|
+
<div className="relative w-full overflow-auto">
|
|
6
|
+
<table
|
|
7
|
+
ref={ref}
|
|
8
|
+
className={`w-full caption-bottom text-sm ${className}`}
|
|
9
|
+
{...props}
|
|
10
|
+
/>
|
|
11
|
+
</div>
|
|
12
|
+
))
|
|
13
|
+
OpticalTable.displayName = "OpticalTable"
|
|
14
|
+
|
|
15
|
+
const OpticalTableHeader = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(({ className = "", ...props }, ref) => (
|
|
16
|
+
<thead ref={ref} className={`[&_tr]:border-b border-white/10 ${className}`} {...props} />
|
|
17
|
+
))
|
|
18
|
+
OpticalTableHeader.displayName = "OpticalTableHeader"
|
|
19
|
+
|
|
20
|
+
const OpticalTableBody = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(({ className = "", ...props }, ref) => (
|
|
21
|
+
<tbody
|
|
22
|
+
ref={ref}
|
|
23
|
+
className={`[&_tr:last-child]:border-0 ${className}`}
|
|
24
|
+
{...props}
|
|
25
|
+
/>
|
|
26
|
+
))
|
|
27
|
+
OpticalTableBody.displayName = "OpticalTableBody"
|
|
28
|
+
|
|
29
|
+
const OpticalTableFooter = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(({ className = "", ...props }, ref) => (
|
|
30
|
+
<tfoot
|
|
31
|
+
ref={ref}
|
|
32
|
+
className={`border-t border-white/10 bg-white/[0.02] font-medium text-white/80 ${className}`}
|
|
33
|
+
{...props}
|
|
34
|
+
/>
|
|
35
|
+
))
|
|
36
|
+
OpticalTableFooter.displayName = "OpticalTableFooter"
|
|
37
|
+
|
|
38
|
+
const OpticalTableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(({ className = "", ...props }, ref) => (
|
|
39
|
+
<tr
|
|
40
|
+
ref={ref}
|
|
41
|
+
className={`border-b border-white/5 transition-colors hover:bg-white/[0.02] data-[state=selected]:bg-white/[0.05] ${className}`}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
))
|
|
45
|
+
OpticalTableRow.displayName = "OpticalTableRow"
|
|
46
|
+
|
|
47
|
+
const OpticalTableHead = React.forwardRef<HTMLTableCellElement, React.ThHTMLAttributes<HTMLTableCellElement>>(({ className = "", ...props }, ref) => (
|
|
48
|
+
<th
|
|
49
|
+
ref={ref}
|
|
50
|
+
className={`h-12 px-4 text-left align-middle font-light text-white/50 [&:has([role=checkbox])]:pr-0 ${className}`}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
))
|
|
54
|
+
OpticalTableHead.displayName = "OpticalTableHead"
|
|
55
|
+
|
|
56
|
+
const OpticalTableCell = React.forwardRef<HTMLTableCellElement, React.TdHTMLAttributes<HTMLTableCellElement>>(({ className = "", ...props }, ref) => (
|
|
57
|
+
<td
|
|
58
|
+
ref={ref}
|
|
59
|
+
className={`p-4 align-middle text-white/80 font-light [&:has([role=checkbox])]:pr-0 ${className}`}
|
|
60
|
+
{...props}
|
|
61
|
+
/>
|
|
62
|
+
))
|
|
63
|
+
OpticalTableCell.displayName = "OpticalTableCell"
|
|
64
|
+
|
|
65
|
+
const OpticalTableCaption = React.forwardRef<HTMLTableCaptionElement, React.HTMLAttributes<HTMLTableCaptionElement>>(({ className = "", ...props }, ref) => (
|
|
66
|
+
<caption
|
|
67
|
+
ref={ref}
|
|
68
|
+
className={`mt-4 text-sm text-white/50 ${className}`}
|
|
69
|
+
{...props}
|
|
70
|
+
/>
|
|
71
|
+
))
|
|
72
|
+
OpticalTableCaption.displayName = "OpticalTableCaption"
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
OpticalTable,
|
|
76
|
+
OpticalTableHeader,
|
|
77
|
+
OpticalTableBody,
|
|
78
|
+
OpticalTableFooter,
|
|
79
|
+
OpticalTableHead,
|
|
80
|
+
OpticalTableRow,
|
|
81
|
+
OpticalTableCell,
|
|
82
|
+
OpticalTableCaption,
|
|
83
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
|
3
|
+
import { cn } from '../../utils/cn';
|
|
4
|
+
import { RippleSurface, GlassSurface } from '@mrigx/fx';
|
|
5
|
+
|
|
6
|
+
const OpticalTabs = TabsPrimitive.Root
|
|
7
|
+
|
|
8
|
+
const OpticalTabsList = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof TabsPrimitive.List>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> & { material?: string; materialStrength?: number }
|
|
11
|
+
>(({ className, material = "glass", materialStrength = 0.5, ...props }, ref) => (
|
|
12
|
+
<TabsPrimitive.List
|
|
13
|
+
ref={ref}
|
|
14
|
+
className={cn(
|
|
15
|
+
"inline-flex h-10 items-center justify-center rounded-lg p-1 text-white/50 relative",
|
|
16
|
+
className
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
>
|
|
20
|
+
<GlassSurface material={material} materialStrength={materialStrength} borderRadius={8} className="absolute inset-0 -z-10 border border-white/5" />
|
|
21
|
+
{props.children}
|
|
22
|
+
</TabsPrimitive.List>
|
|
23
|
+
))
|
|
24
|
+
OpticalTabsList.displayName = TabsPrimitive.List.displayName
|
|
25
|
+
|
|
26
|
+
const OpticalTabsTrigger = React.forwardRef<
|
|
27
|
+
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
|
28
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
|
29
|
+
>(({ className, ...props }, ref) => (
|
|
30
|
+
<TabsPrimitive.Trigger
|
|
31
|
+
ref={ref}
|
|
32
|
+
className={cn(
|
|
33
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white/10 data-[state=active]:text-white data-[state=active]:shadow-sm cursor-pointer",
|
|
34
|
+
className
|
|
35
|
+
)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
))
|
|
39
|
+
OpticalTabsTrigger.displayName = TabsPrimitive.Trigger.displayName
|
|
40
|
+
|
|
41
|
+
const OpticalTabsContent = React.forwardRef<
|
|
42
|
+
React.ElementRef<typeof TabsPrimitive.Content>,
|
|
43
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
|
44
|
+
>(({ className, ...props }, ref) => (
|
|
45
|
+
<TabsPrimitive.Content
|
|
46
|
+
ref={ref}
|
|
47
|
+
className={cn(
|
|
48
|
+
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
49
|
+
className
|
|
50
|
+
)}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
))
|
|
54
|
+
OpticalTabsContent.displayName = TabsPrimitive.Content.displayName
|
|
55
|
+
|
|
56
|
+
export { OpticalTabs, OpticalTabsList, OpticalTabsTrigger, OpticalTabsContent }
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export function LiquidTensionText({ children, className = "", distance = 100, strength = 15, as: Component = "span" }: any) {
|
|
4
|
+
const ref = useRef<HTMLElement>(null);
|
|
5
|
+
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const el = ref.current;
|
|
8
|
+
if (!el) return;
|
|
9
|
+
|
|
10
|
+
let rect = el.getBoundingClientRect();
|
|
11
|
+
let centerX = rect.left + rect.width / 2;
|
|
12
|
+
let centerY = rect.top + rect.height / 2;
|
|
13
|
+
let isActive = false;
|
|
14
|
+
let rafId = 0;
|
|
15
|
+
let mouseX = 0;
|
|
16
|
+
let mouseY = 0;
|
|
17
|
+
|
|
18
|
+
const updateTransform = () => {
|
|
19
|
+
if (!isActive) return;
|
|
20
|
+
const distX = mouseX - centerX;
|
|
21
|
+
const distY = mouseY - centerY;
|
|
22
|
+
const dist = Math.sqrt(distX * distX + distY * distY);
|
|
23
|
+
|
|
24
|
+
if (dist < distance) {
|
|
25
|
+
const pull = (distance - dist) / strength;
|
|
26
|
+
el.style.transform = `translate(${distX > 0 ? pull : -pull}px, ${distY > 0 ? pull : -pull}px)`;
|
|
27
|
+
} else {
|
|
28
|
+
el.style.transform = 'translate(0px, 0px)';
|
|
29
|
+
}
|
|
30
|
+
rafId = 0;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const handleMove = (e: MouseEvent) => {
|
|
34
|
+
mouseX = e.clientX;
|
|
35
|
+
mouseY = e.clientY;
|
|
36
|
+
if (isActive && !rafId) rafId = requestAnimationFrame(updateTransform);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const handleEnter = () => {
|
|
40
|
+
isActive = true;
|
|
41
|
+
rect = el.getBoundingClientRect();
|
|
42
|
+
centerX = rect.left + rect.width / 2;
|
|
43
|
+
centerY = rect.top + rect.height / 2;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const handleLeave = () => {
|
|
47
|
+
isActive = false;
|
|
48
|
+
el.style.transform = 'translate(0px, 0px)';
|
|
49
|
+
if (rafId) { cancelAnimationFrame(rafId); rafId = 0; }
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
el.addEventListener('mouseenter', handleEnter);
|
|
53
|
+
el.addEventListener('mouseleave', handleLeave);
|
|
54
|
+
window.addEventListener('mousemove', handleMove, { passive: true });
|
|
55
|
+
|
|
56
|
+
return () => {
|
|
57
|
+
el.removeEventListener('mouseenter', handleEnter);
|
|
58
|
+
el.removeEventListener('mouseleave', handleLeave);
|
|
59
|
+
window.removeEventListener('mousemove', handleMove);
|
|
60
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
61
|
+
};
|
|
62
|
+
}, [distance, strength]);
|
|
63
|
+
|
|
64
|
+
return <Component ref={ref} className={`inline-block transition-transform duration-75 ease-out ${className}`}>{children}</Component>;
|
|
65
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export function LiquidTensionText({ children, className = "", distance = 100, strength = 15, as: Component = "span" }: any) {
|
|
4
|
+
const ref = useRef<HTMLElement>(null);
|
|
5
|
+
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const el = ref.current;
|
|
8
|
+
if (!el) return;
|
|
9
|
+
|
|
10
|
+
let rect = el.getBoundingClientRect();
|
|
11
|
+
let centerX = rect.left + rect.width / 2;
|
|
12
|
+
let centerY = rect.top + rect.height / 2;
|
|
13
|
+
let isActive = false;
|
|
14
|
+
let rafId = 0;
|
|
15
|
+
let mouseX = 0;
|
|
16
|
+
let mouseY = 0;
|
|
17
|
+
|
|
18
|
+
const updateTransform = () => {
|
|
19
|
+
if (!isActive) return;
|
|
20
|
+
const distX = mouseX - centerX;
|
|
21
|
+
const distY = mouseY - centerY;
|
|
22
|
+
const dist = Math.sqrt(distX * distX + distY * distY);
|
|
23
|
+
|
|
24
|
+
if (dist < distance) {
|
|
25
|
+
const pull = (distance - dist) / strength;
|
|
26
|
+
el.style.transform = `translate(${distX > 0 ? pull : -pull}px, ${distY > 0 ? pull : -pull}px)`;
|
|
27
|
+
} else {
|
|
28
|
+
el.style.transform = 'translate(0px, 0px)';
|
|
29
|
+
}
|
|
30
|
+
rafId = 0;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const handleMove = (e: MouseEvent) => {
|
|
34
|
+
mouseX = e.clientX;
|
|
35
|
+
mouseY = e.clientY;
|
|
36
|
+
if (isActive && !rafId) rafId = requestAnimationFrame(updateTransform);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const handleEnter = () => {
|
|
40
|
+
isActive = true;
|
|
41
|
+
rect = el.getBoundingClientRect();
|
|
42
|
+
centerX = rect.left + rect.width / 2;
|
|
43
|
+
centerY = rect.top + rect.height / 2;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const handleLeave = () => {
|
|
47
|
+
isActive = false;
|
|
48
|
+
el.style.transform = 'translate(0px, 0px)';
|
|
49
|
+
if (rafId) { cancelAnimationFrame(rafId); rafId = 0; }
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
el.addEventListener('mouseenter', handleEnter);
|
|
53
|
+
el.addEventListener('mouseleave', handleLeave);
|
|
54
|
+
window.addEventListener('mousemove', handleMove, { passive: true });
|
|
55
|
+
|
|
56
|
+
return () => {
|
|
57
|
+
el.removeEventListener('mouseenter', handleEnter);
|
|
58
|
+
el.removeEventListener('mouseleave', handleLeave);
|
|
59
|
+
window.removeEventListener('mousemove', handleMove);
|
|
60
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
61
|
+
};
|
|
62
|
+
}, [distance, strength]);
|
|
63
|
+
|
|
64
|
+
return <Component ref={ref} className={`inline-block transition-transform duration-75 ease-out ${className}`}>{children}</Component>;
|
|
65
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
|
+
import { useMrigSurface, useMrigInteraction } from '@mrigx/react';
|
|
4
|
+
export const OpticalText = forwardRef<any, any>(({ children, className = "", as = "span", ...props }, forwardedRef) => {
|
|
5
|
+
const Component = as;
|
|
6
|
+
const internalRef = useMrigSurface({ material: 'soft-glass', materialStrength: 0.5, borderRadius: 4 }, forwardedRef);
|
|
7
|
+
const { pulseCenter } = useMrigInteraction();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<Component
|
|
11
|
+
ref={internalRef as any}
|
|
12
|
+
className={`inline-block px-1 rounded bg-white/5 ${className}`}
|
|
13
|
+
onMouseEnter={(e: any) => pulseCenter(e.currentTarget, 0.2)}
|
|
14
|
+
{...props}
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</Component>
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
OpticalText.displayName = "OpticalText";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../utils/cn';
|
|
4
|
+
|
|
5
|
+
const Textarea = React.forwardRef<
|
|
6
|
+
HTMLTextAreaElement,
|
|
7
|
+
React.ComponentProps<"textarea">
|
|
8
|
+
>(({ className, ...props }, ref) => {
|
|
9
|
+
return (
|
|
10
|
+
<textarea
|
|
11
|
+
className={cn(
|
|
12
|
+
"flex min-h-[80px] w-full rounded-md border border-white/10 bg-transparent px-3 py-2 text-base ring-offset-black placeholder:text-white/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
ref={ref}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
19
|
+
})
|
|
20
|
+
Textarea.displayName = "Textarea"
|
|
21
|
+
|
|
22
|
+
export { Textarea }
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { useMrigSurface } from '@mrigx/react';
|
|
3
|
+
|
|
4
|
+
const THEMES = ['default', 'theme-cyan', 'theme-magenta', 'theme-toxic', 'theme-amber', 'theme-electric', 'theme-laser', 'theme-hotpink', 'theme-crimson'];
|
|
5
|
+
const THEME_COLORS = ['#ffffff', '#00ffcc', '#ff00cc', '#39ff14', '#ffb000', '#0077ff', '#ffff00', '#ff1493', '#ff0033'];
|
|
6
|
+
|
|
7
|
+
export function OpticalThemeToggle() {
|
|
8
|
+
const [themeIdx, setThemeIdx] = useState(0);
|
|
9
|
+
// Add an internal dynamic surface for the toggle itself so its glow updates cleanly
|
|
10
|
+
const toggleRef = useMrigSurface<HTMLButtonElement>({ isDynamic: true });
|
|
11
|
+
|
|
12
|
+
const toggleTheme = (e: React.MouseEvent) => {
|
|
13
|
+
e.preventDefault();
|
|
14
|
+
e.stopPropagation();
|
|
15
|
+
const nextIdx = (themeIdx + 1) % THEMES.length;
|
|
16
|
+
setThemeIdx(nextIdx);
|
|
17
|
+
|
|
18
|
+
THEMES.forEach(t => {
|
|
19
|
+
if (t !== 'default') document.documentElement.classList.remove(t); document.getElementById("mrig-app-root")?.classList.remove(t);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const nextTheme = THEMES[nextIdx];
|
|
23
|
+
if (nextTheme !== 'default') {
|
|
24
|
+
document.documentElement.classList.add(nextTheme); document.getElementById("mrig-app-root")?.classList.add(nextTheme);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Force the optical engine to re-rasterize the entire DOM to capture the new colors
|
|
28
|
+
setTimeout(() => {
|
|
29
|
+
window.dispatchEvent(new Event('resize'));
|
|
30
|
+
}, 10);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<button
|
|
35
|
+
ref={toggleRef}
|
|
36
|
+
onClick={(e) => toggleTheme(e)}
|
|
37
|
+
className="p-3 rounded-full border border-white/20 bg-white/5 hover:bg-white/20 transition-all cursor-pointer flex items-center justify-center text-white pointer-events-auto shadow-2xl hover:scale-110"
|
|
38
|
+
style={{ boxShadow: `0 0 15px ${THEME_COLORS[themeIdx]}50` }}
|
|
39
|
+
aria-label="Toggle Glass Theme"
|
|
40
|
+
>
|
|
41
|
+
<div className="w-5 h-5 rounded-full shadow-inner border border-black/30" style={{ backgroundColor: THEME_COLORS[themeIdx] }} />
|
|
42
|
+
</button>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import { useMrigSurface } from "@mrigx/react";
|
|
3
|
+
|
|
4
|
+
export interface OpticalToastProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
material?: 'glass' | 'crystal' | 'abyss';
|
|
6
|
+
materialStrength?: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function OpticalToast({ children, className = "", material = 'glass', materialStrength = 1.0, ...props }: OpticalToastProps) {
|
|
10
|
+
const localRef = useRef<HTMLDivElement>(null);
|
|
11
|
+
const ref = useMrigSurface<HTMLDivElement>({ material, materialStrength, borderRadius: 8 }, localRef);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div
|
|
15
|
+
ref={ref as any}
|
|
16
|
+
className={`p-6 border border-white/10 bg-white/5 rounded-xl shadow-lg backdrop-blur-md flex items-center justify-center text-white/80 font-light ${className}`}
|
|
17
|
+
{...props}
|
|
18
|
+
>
|
|
19
|
+
{children || 'Toast Interface'}
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|