@reactberry/system 2.0.0-beta
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 +48 -0
- package/package.json +74 -0
- package/src/blocks/Accordion/index.tsx +158 -0
- package/src/blocks/AnimatedCarousel/index.tsx +188 -0
- package/src/blocks/AppleGlow/index.tsx +144 -0
- package/src/blocks/Avatar/index.tsx +167 -0
- package/src/blocks/Await/index.tsx +45 -0
- package/src/blocks/Cards/AnimatedCard/index.tsx +175 -0
- package/src/blocks/Cards/FluorescentCard/index.tsx +180 -0
- package/src/blocks/Cards/InfoCard/index.tsx +206 -0
- package/src/blocks/Cards/TickerCard/index.tsx +125 -0
- package/src/blocks/Carousel/index.tsx +216 -0
- package/src/blocks/Checkbox/index.tsx +101 -0
- package/src/blocks/Collection/index.tsx +59 -0
- package/src/blocks/Container/index.tsx +55 -0
- package/src/blocks/Controls/Control.tsx +67 -0
- package/src/blocks/Controls/index.tsx +11 -0
- package/src/blocks/CyclingNumber/index.tsx +78 -0
- package/src/blocks/DisplaySet/index.tsx +42 -0
- package/src/blocks/Divider/index.tsx +14 -0
- package/src/blocks/Draggable/index.tsx +266 -0
- package/src/blocks/Drawer/index.tsx +136 -0
- package/src/blocks/DynamicIsland/DynamicIsland.tsx +89 -0
- package/src/blocks/DynamicIsland/index.tsx +2 -0
- package/src/blocks/Fader/index.tsx +145 -0
- package/src/blocks/FamilyDrawer/README.md +116 -0
- package/src/blocks/FamilyDrawer/example.tsx +108 -0
- package/src/blocks/FamilyDrawer/index.tsx +119 -0
- package/src/blocks/FamilyDrawer/views/DefaultView.tsx +93 -0
- package/src/blocks/FamilyDrawer/views/KeyView.tsx +129 -0
- package/src/blocks/FamilyDrawer/views/PhraseView.tsx +129 -0
- package/src/blocks/FamilyDrawer/views/RemoveView.tsx +81 -0
- package/src/blocks/FieldSet/index.tsx +173 -0
- package/src/blocks/Filesystem/index.tsx +198 -0
- package/src/blocks/Gallery/Carousel/index.tsx +257 -0
- package/src/blocks/Gallery/Modal/index.tsx +83 -0
- package/src/blocks/Gallery/index.tsx +57 -0
- package/src/blocks/Gallery/utils/animationVariants.ts +18 -0
- package/src/blocks/Gallery/utils/aspectRatio.ts +14 -0
- package/src/blocks/Gallery/utils/downloadPhoto.ts +24 -0
- package/src/blocks/Gallery/utils/range.ts +11 -0
- package/src/blocks/GradientMesh/index.tsx +106 -0
- package/src/blocks/Group/index.tsx +152 -0
- package/src/blocks/Heading/index.tsx +111 -0
- package/src/blocks/HorizontalScroller/index.tsx +135 -0
- package/src/blocks/Icon/index.tsx +45 -0
- package/src/blocks/Indicator/index.tsx +27 -0
- package/src/blocks/InlineEditor/index.tsx +216 -0
- package/src/blocks/List/index.tsx +657 -0
- package/src/blocks/Main/index.tsx +17 -0
- package/src/blocks/Marquee/index.tsx +116 -0
- package/src/blocks/MaskedField/index.tsx +199 -0
- package/src/blocks/Menu/MenuContent.tsx +246 -0
- package/src/blocks/Menu/MenuContext.tsx +34 -0
- package/src/blocks/Menu/MenuItem.tsx +104 -0
- package/src/blocks/Menu/index.tsx +60 -0
- package/src/blocks/Modal/index.tsx +268 -0
- package/src/blocks/MorphingPopover/index.tsx +294 -0
- package/src/blocks/Overlay/Backdrop.tsx +48 -0
- package/src/blocks/Overlay/OverscrollGuard.tsx +36 -0
- package/src/blocks/Overlay/index.ts +2 -0
- package/src/blocks/Parallax/index.tsx +117 -0
- package/src/blocks/ParallaxSection/index.tsx +61 -0
- package/src/blocks/Placeholder/index.tsx +48 -0
- package/src/blocks/Popover/index.tsx +402 -0
- package/src/blocks/Progress/getProgressColor.ts +61 -0
- package/src/blocks/Progress/index.tsx +179 -0
- package/src/blocks/ProgressiveBlur/index.tsx +75 -0
- package/src/blocks/README.md +15 -0
- package/src/blocks/RenderAsset/index.tsx +18 -0
- package/src/blocks/ScrollContainer/index.tsx +93 -0
- package/src/blocks/ShinyText/index.tsx +72 -0
- package/src/blocks/Skeleton/index.tsx +71 -0
- package/src/blocks/Slider/SliderControls.tsx +119 -0
- package/src/blocks/Slider/index.tsx +140 -0
- package/src/blocks/Slider/useSlider.ts +126 -0
- package/src/blocks/Slideshow/index.tsx +177 -0
- package/src/blocks/Spotlight/index.tsx +144 -0
- package/src/blocks/Steps/StepIndicator.tsx +149 -0
- package/src/blocks/Steps/StepProgress.tsx +164 -0
- package/src/blocks/Steps/Steps.tsx +197 -0
- package/src/blocks/Steps/StepsNav.tsx +30 -0
- package/src/blocks/Steps/StepsTracker.tsx +80 -0
- package/src/blocks/Steps/hooks.ts +71 -0
- package/src/blocks/Steps/index.tsx +16 -0
- package/src/blocks/Steps/types.ts +71 -0
- package/src/blocks/StickySectionStack/index.tsx +136 -0
- package/src/blocks/Switch/index.tsx +85 -0
- package/src/blocks/SystemNotice/index.tsx +81 -0
- package/src/blocks/Table/README.md +251 -0
- package/src/blocks/Table/Table.tsx +207 -0
- package/src/blocks/Table/TablePagination.tsx +189 -0
- package/src/blocks/Table/index.ts +33 -0
- package/src/blocks/Table/useTableControls.ts +331 -0
- package/src/blocks/Tag/index.tsx +27 -0
- package/src/blocks/TextBreak/index.tsx +96 -0
- package/src/blocks/TextReveal/index.tsx +104 -0
- package/src/blocks/Thumbnail/index.tsx +26 -0
- package/src/blocks/Ticker/index.tsx +112 -0
- package/src/blocks/Toast/index.tsx +77 -0
- package/src/blocks/Tooltip/index.tsx +174 -0
- package/src/blocks/Underlay/index.tsx +104 -0
- package/src/blocks/Upload/Dropzone.tsx +92 -0
- package/src/blocks/Upload/UploadBtn.tsx +38 -0
- package/src/blocks/Upload/index.tsx +61 -0
- package/src/blocks/Upload/types.ts +37 -0
- package/src/blocks/VideoMarquee/index.tsx +511 -0
- package/src/blocks/index.ts +119 -0
- package/src/blocks/pagination/Pagination.tsx +148 -0
- package/src/blocks/pagination/PaginationList.tsx +41 -0
- package/src/blocks/pagination/index.ts +2 -0
- package/src/charts/BarChart.tsx +63 -0
- package/src/charts/PieChart.tsx +39 -0
- package/src/charts/index.ts +3 -0
- package/src/charts/utils.ts +103 -0
- package/src/docs/README.md +373 -0
- package/src/docs/reference/README.md +299 -0
- package/src/elements/box.ts +163 -0
- package/src/elements/button.ts +49 -0
- package/src/elements/field.ts +129 -0
- package/src/elements/index.ts +8 -0
- package/src/elements/text.ts +47 -0
- package/src/elements/utils.js +97 -0
- package/src/hooks/use-copy-to-clipboard.tsx +33 -0
- package/src/hooks/use-enter-submit.tsx +23 -0
- package/src/hooks/use-local-storage.ts +42 -0
- package/src/hooks/use-sidebar.tsx +109 -0
- package/src/hooks/useAnimatedText.ts +32 -0
- package/src/hooks/useAutosizeTextArea.ts +45 -0
- package/src/hooks/useBreakpoint.tsx +123 -0
- package/src/hooks/useClickOutside.tsx +38 -0
- package/src/hooks/useHover.tsx +33 -0
- package/src/hooks/useHoverList.tsx +17 -0
- package/src/hooks/useKeyboardShortcuts.ts +91 -0
- package/src/hooks/useKeypress.ts +27 -0
- package/src/hooks/useOverlay.ts +32 -0
- package/src/hooks/useReducedMotion.ts +25 -0
- package/src/hooks/useStandaloneMode.ts +35 -0
- package/src/hooks/useTouchDevice.ts +34 -0
- package/src/icons/index.tsx +129 -0
- package/src/index.ts +12 -0
- package/src/providers/DesignSystemProvider.tsx +35 -0
- package/src/providers/StyledComponentsRegistry.tsx +30 -0
- package/src/providers/index.ts +2 -0
- package/src/themes/README.md +30 -0
- package/src/themes/default/assets/badge-avatar.tsx +45 -0
- package/src/themes/default/assets/logo.tsx +42 -0
- package/src/themes/default/global.ts +138 -0
- package/src/themes/default/modes/dark/config.js +49 -0
- package/src/themes/default/modes/dark/skins.js +631 -0
- package/src/themes/default/modes/dark/theme.js +87 -0
- package/src/themes/default/modes/light/config.js +48 -0
- package/src/themes/default/modes/light/skins.js +1026 -0
- package/src/themes/default/modes/light/theme.js +74 -0
- package/src/themes/default/tokens/controls.js +53 -0
- package/src/themes/default/tokens/shadows.js +63 -0
- package/src/themes/default/tokens/shapes.js +37 -0
- package/src/themes/default/tokens/space.js +143 -0
- package/src/themes/default/tokens/spectre.js +16 -0
- package/src/themes/default/utils.js +523 -0
- package/src/themes/index.ts +11 -0
- package/src/types.ts +394 -0
- package/src/utils/overlayTheme.ts +61 -0
- package/src/utils/pickColor.ts +15 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { Box } from "@/design-system/elements";
|
|
2
|
+
import { motion } from "motion/react";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
const defaults = {
|
|
6
|
+
size: "2rem",
|
|
7
|
+
progress: 0,
|
|
8
|
+
progressColor: "brand",
|
|
9
|
+
trackColor: "transparent.light.1",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
interface ProgressProps {
|
|
13
|
+
variant?: "pie" | "bar" | "circle";
|
|
14
|
+
progress?: number;
|
|
15
|
+
progressColor?: string;
|
|
16
|
+
trackColor?: string;
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const PieProgress: React.FC<ProgressProps> = ({
|
|
21
|
+
progress = defaults.progress,
|
|
22
|
+
progressColor = defaults.progressColor,
|
|
23
|
+
trackColor = defaults.trackColor,
|
|
24
|
+
size = "2rem",
|
|
25
|
+
...props
|
|
26
|
+
}) => {
|
|
27
|
+
return (
|
|
28
|
+
<Box
|
|
29
|
+
as="svg"
|
|
30
|
+
viewBox="0 0 64 64"
|
|
31
|
+
bg="transparent"
|
|
32
|
+
size={size}
|
|
33
|
+
shape="circle"
|
|
34
|
+
color={trackColor}
|
|
35
|
+
border="1.5px solid transparent"
|
|
36
|
+
boxShadow={`0 0 0 1.5px currentColor`}
|
|
37
|
+
style={{
|
|
38
|
+
transform: "rotate(-90deg)",
|
|
39
|
+
}}
|
|
40
|
+
{...props}
|
|
41
|
+
>
|
|
42
|
+
<Box
|
|
43
|
+
as="circle"
|
|
44
|
+
color={progressColor}
|
|
45
|
+
r="25%"
|
|
46
|
+
cx="50%"
|
|
47
|
+
cy="50%"
|
|
48
|
+
fill="none"
|
|
49
|
+
stroke={"currentColor"}
|
|
50
|
+
strokeWidth={32}
|
|
51
|
+
strokeDasharray={`${progress * 10} 100`}
|
|
52
|
+
/>
|
|
53
|
+
</Box>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
interface CircleProgressProps {
|
|
58
|
+
sqSize?: number;
|
|
59
|
+
progress?: number;
|
|
60
|
+
strokeWidth?: number;
|
|
61
|
+
progressColor?: string;
|
|
62
|
+
trackColor?: string;
|
|
63
|
+
fontSize?: string;
|
|
64
|
+
label?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const CircleProgress: React.FC<CircleProgressProps> = ({
|
|
68
|
+
sqSize = 100,
|
|
69
|
+
progress = 25,
|
|
70
|
+
strokeWidth = 1,
|
|
71
|
+
progressColor = defaults.progressColor,
|
|
72
|
+
trackColor = defaults.trackColor,
|
|
73
|
+
label,
|
|
74
|
+
...props
|
|
75
|
+
}) => {
|
|
76
|
+
// Size of the enclosing square
|
|
77
|
+
// SVG centers the stroke width on the radius, subtract out so circle fits in square
|
|
78
|
+
const radius = (sqSize - strokeWidth) / 2;
|
|
79
|
+
// Enclose circle in a circumscribing square
|
|
80
|
+
const viewBox = `0 0 ${sqSize} ${sqSize}`;
|
|
81
|
+
// Arc length at 100% coverage is the circle circumference
|
|
82
|
+
const dashArray = radius * Math.PI * 2;
|
|
83
|
+
// Scale 100% coverage overlay with the actual percent
|
|
84
|
+
const dashOffset = dashArray - (dashArray * progress) / 100;
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<Box as="svg" size={sqSize} viewBox={viewBox} {...props}>
|
|
88
|
+
<Box
|
|
89
|
+
as="circle"
|
|
90
|
+
color={trackColor}
|
|
91
|
+
cx={sqSize / 2}
|
|
92
|
+
cy={sqSize / 2}
|
|
93
|
+
r={radius}
|
|
94
|
+
strokeWidth={`${strokeWidth}px`}
|
|
95
|
+
style={{ stroke: "currentColor", fill: "none" }}
|
|
96
|
+
/>
|
|
97
|
+
<Box
|
|
98
|
+
as="circle"
|
|
99
|
+
color={progressColor}
|
|
100
|
+
cx={sqSize / 2}
|
|
101
|
+
cy={sqSize / 2}
|
|
102
|
+
r={radius}
|
|
103
|
+
strokeWidth={`${strokeWidth}px`}
|
|
104
|
+
// Start progress marker at 12 O'Clock
|
|
105
|
+
transform={`rotate(-90 ${sqSize / 2} ${sqSize / 2})`}
|
|
106
|
+
style={{
|
|
107
|
+
fill: "none",
|
|
108
|
+
strokeDasharray: dashArray,
|
|
109
|
+
strokeDashoffset: dashOffset,
|
|
110
|
+
stroke: "currentColor",
|
|
111
|
+
strokeLinecap: "round",
|
|
112
|
+
strokeLinejoin: "round",
|
|
113
|
+
}}
|
|
114
|
+
/>
|
|
115
|
+
<Box
|
|
116
|
+
as="text"
|
|
117
|
+
x="50%"
|
|
118
|
+
y="50%"
|
|
119
|
+
dy="0.375em"
|
|
120
|
+
textAnchor="middle"
|
|
121
|
+
color={"secondary"}
|
|
122
|
+
fill="currentColor"
|
|
123
|
+
fontWeight={"600"}
|
|
124
|
+
fontSize="1em"
|
|
125
|
+
>
|
|
126
|
+
{label ? label : `${progress}%`}
|
|
127
|
+
</Box>
|
|
128
|
+
</Box>
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const BarProgress: React.FC<ProgressProps> = ({
|
|
133
|
+
progress = 0,
|
|
134
|
+
reverse = false,
|
|
135
|
+
trackColor = defaults.trackColor,
|
|
136
|
+
progressColor = defaults.progressColor,
|
|
137
|
+
...props
|
|
138
|
+
}) => {
|
|
139
|
+
return (
|
|
140
|
+
<Box
|
|
141
|
+
position="relative"
|
|
142
|
+
display="block"
|
|
143
|
+
overflow="hidden"
|
|
144
|
+
height={"0.25rem"}
|
|
145
|
+
bg={trackColor}
|
|
146
|
+
{...props}
|
|
147
|
+
>
|
|
148
|
+
<Box
|
|
149
|
+
as={motion.div}
|
|
150
|
+
height="100%"
|
|
151
|
+
//width={`${progress}%`}
|
|
152
|
+
animate={{ width: `${progress}%` }}
|
|
153
|
+
position="absolute"
|
|
154
|
+
bg={progressColor}
|
|
155
|
+
top={0}
|
|
156
|
+
shape="rounded"
|
|
157
|
+
left={reverse ? "auto" : 0}
|
|
158
|
+
right={reverse ? 0 : "auto"}
|
|
159
|
+
/>
|
|
160
|
+
</Box>
|
|
161
|
+
);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const Progress: React.FC<ProgressProps> = ({
|
|
165
|
+
variant = "bar",
|
|
166
|
+
progress = 0,
|
|
167
|
+
...props
|
|
168
|
+
}) => {
|
|
169
|
+
switch (variant) {
|
|
170
|
+
case "pie":
|
|
171
|
+
return <PieProgress progress={progress} {...props} />;
|
|
172
|
+
case "circle":
|
|
173
|
+
return <CircleProgress progress={progress} {...props} />;
|
|
174
|
+
default:
|
|
175
|
+
return <BarProgress progress={progress} {...props} />;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export default Progress;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { motion, HTMLMotionProps } from "motion/react";
|
|
4
|
+
import Box, { BoxProps } from "@/design-system/elements/box";
|
|
5
|
+
|
|
6
|
+
export const GRADIENT_ANGLES = {
|
|
7
|
+
top: 0,
|
|
8
|
+
right: 90,
|
|
9
|
+
bottom: 180,
|
|
10
|
+
left: 270,
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
export type ProgressiveBlurProps = Omit<BoxProps, "children"> & {
|
|
14
|
+
direction?: keyof typeof GRADIENT_ANGLES;
|
|
15
|
+
blurLayers?: number;
|
|
16
|
+
blurIntensity?: number;
|
|
17
|
+
children?: React.ReactNode;
|
|
18
|
+
motionProps?: Omit<HTMLMotionProps<"div">, "style">;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default function ProgressiveBlur({
|
|
22
|
+
direction = "bottom",
|
|
23
|
+
blurLayers = 8,
|
|
24
|
+
blurIntensity = 0.25,
|
|
25
|
+
children,
|
|
26
|
+
motionProps,
|
|
27
|
+
...boxProps
|
|
28
|
+
}: ProgressiveBlurProps) {
|
|
29
|
+
const layers = Math.max(blurLayers, 2);
|
|
30
|
+
const segmentSize = 1 / (blurLayers + 1);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<Box position="relative" {...boxProps}>
|
|
34
|
+
{children}
|
|
35
|
+
{Array.from({ length: layers }).map((_, index) => {
|
|
36
|
+
const angle = GRADIENT_ANGLES[direction];
|
|
37
|
+
const gradientStops = [
|
|
38
|
+
index * segmentSize,
|
|
39
|
+
(index + 1) * segmentSize,
|
|
40
|
+
(index + 2) * segmentSize,
|
|
41
|
+
(index + 3) * segmentSize,
|
|
42
|
+
].map(
|
|
43
|
+
(pos, posIndex) =>
|
|
44
|
+
`rgba(255, 255, 255, ${posIndex === 1 || posIndex === 2 ? 1 : 0}) ${pos * 100}%`
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const gradient = `linear-gradient(${angle}deg, ${gradientStops.join(
|
|
48
|
+
", "
|
|
49
|
+
)})`;
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<Box
|
|
53
|
+
key={index}
|
|
54
|
+
as={motion.div}
|
|
55
|
+
position="absolute"
|
|
56
|
+
top={0}
|
|
57
|
+
left={0}
|
|
58
|
+
right={0}
|
|
59
|
+
bottom={0}
|
|
60
|
+
borderRadius="inherit"
|
|
61
|
+
style={{
|
|
62
|
+
pointerEvents: "none",
|
|
63
|
+
maskImage: gradient,
|
|
64
|
+
WebkitMaskImage: gradient,
|
|
65
|
+
backdropFilter: `blur(${index * blurIntensity}px)`,
|
|
66
|
+
WebkitBackdropFilter: `blur(${index * blurIntensity}px)`,
|
|
67
|
+
}}
|
|
68
|
+
{...motionProps}
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
})}
|
|
72
|
+
</Box>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Documentation Moved
|
|
2
|
+
|
|
3
|
+
The design system blocks documentation has been moved to:
|
|
4
|
+
|
|
5
|
+
**📄 [src/docs/blocks.md](../docs/blocks.md)**
|
|
6
|
+
|
|
7
|
+
## New Documentation Structure
|
|
8
|
+
|
|
9
|
+
All design system documentation is now centralized in the `src/docs/` folder for better organization and easier AI reference:
|
|
10
|
+
|
|
11
|
+
- **[docs/elements.md](../docs/elements.md)** - Core components (Box, Text, Button, Field)
|
|
12
|
+
- **[docs/blocks.md](../docs/blocks.md)** - Composed components (Card, Modal, etc.)
|
|
13
|
+
- **[docs/themes.md](../docs/themes.md)** - Theme system and customization
|
|
14
|
+
- **[docs/README.md](../docs/README.md)** - Complete overview and getting started
|
|
15
|
+
- **[docs/index.md](../docs/index.md)** - Quick reference for AI assistants
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ComponentType, createElement } from "react";
|
|
2
|
+
|
|
3
|
+
interface RenderAssetProps {
|
|
4
|
+
asset: ComponentType<any>;
|
|
5
|
+
assetProps?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default function RenderAsset({
|
|
9
|
+
asset,
|
|
10
|
+
assetProps = {},
|
|
11
|
+
}: RenderAssetProps) {
|
|
12
|
+
if (!asset) {
|
|
13
|
+
console.warn("RenderAsset: No asset provided");
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return createElement(asset, assetProps, null);
|
|
18
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import Box, { BoxProps } from "@/design-system/elements/box";
|
|
3
|
+
import React, { useRef, useEffect } from "react";
|
|
4
|
+
|
|
5
|
+
type ScrollContainerProps = BoxProps & {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
watch?: any;
|
|
8
|
+
scrollToId?: string;
|
|
9
|
+
onScrollStart?: () => void;
|
|
10
|
+
scrollOffset?: number;
|
|
11
|
+
scrollBehavior?: ScrollBehavior;
|
|
12
|
+
scrollBlock?: ScrollLogicalPosition;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default function ScrollContainer({
|
|
16
|
+
children,
|
|
17
|
+
watch,
|
|
18
|
+
scrollToId,
|
|
19
|
+
onScrollStart,
|
|
20
|
+
scrollOffset = 0,
|
|
21
|
+
scrollBehavior = "smooth",
|
|
22
|
+
scrollBlock = "start",
|
|
23
|
+
...props
|
|
24
|
+
}: ScrollContainerProps) {
|
|
25
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
26
|
+
const bottomRef = useRef<HTMLDivElement>(null);
|
|
27
|
+
const endRef = useRef<HTMLDivElement>(null);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (scrollToId) {
|
|
31
|
+
onScrollStart?.();
|
|
32
|
+
const targetElement = document.getElementById(scrollToId);
|
|
33
|
+
if (targetElement && containerRef.current) {
|
|
34
|
+
// Calculate position relative to the container
|
|
35
|
+
const containerRect = containerRef.current.getBoundingClientRect();
|
|
36
|
+
const targetRect = targetElement.getBoundingClientRect();
|
|
37
|
+
const relativeTop =
|
|
38
|
+
targetRect.top -
|
|
39
|
+
containerRect.top +
|
|
40
|
+
containerRef.current.scrollTop -
|
|
41
|
+
scrollOffset;
|
|
42
|
+
|
|
43
|
+
containerRef.current.scrollTo({
|
|
44
|
+
top: relativeTop,
|
|
45
|
+
behavior: "smooth",
|
|
46
|
+
});
|
|
47
|
+
} else if (targetElement) {
|
|
48
|
+
if (scrollOffset !== 0) {
|
|
49
|
+
// Set CSS scroll margin for offset
|
|
50
|
+
targetElement.style.scrollMarginTop = `${scrollOffset}px`;
|
|
51
|
+
}
|
|
52
|
+
targetElement.scrollIntoView({
|
|
53
|
+
behavior: scrollBehavior,
|
|
54
|
+
block: scrollBlock,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
} else if (watch !== undefined && containerRef.current && endRef.current) {
|
|
58
|
+
// Scroll the container to show the end ref
|
|
59
|
+
endRef.current.scrollIntoView({
|
|
60
|
+
behavior: scrollBehavior,
|
|
61
|
+
block: scrollBlock,
|
|
62
|
+
});
|
|
63
|
+
} else if (watch && containerRef.current) {
|
|
64
|
+
// Scroll to bottom within the container only
|
|
65
|
+
containerRef.current.scrollTo({
|
|
66
|
+
top: containerRef.current.scrollHeight,
|
|
67
|
+
behavior: "smooth",
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}, [
|
|
71
|
+
watch,
|
|
72
|
+
scrollToId,
|
|
73
|
+
onScrollStart,
|
|
74
|
+
scrollOffset,
|
|
75
|
+
scrollBehavior,
|
|
76
|
+
scrollBlock,
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<Box
|
|
81
|
+
ref={containerRef}
|
|
82
|
+
width="100%"
|
|
83
|
+
flex="auto"
|
|
84
|
+
display="flex"
|
|
85
|
+
flexDirection="column"
|
|
86
|
+
{...props}
|
|
87
|
+
>
|
|
88
|
+
{children}
|
|
89
|
+
<div ref={bottomRef} />
|
|
90
|
+
<Box pt="1rem" ref={endRef} />
|
|
91
|
+
</Box>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Text } from "@/design-system/elements";
|
|
3
|
+
import { motion, useAnimation } from "motion/react";
|
|
4
|
+
import { useEffect } from "react";
|
|
5
|
+
|
|
6
|
+
type ShinyTextProps = {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
speed?: number;
|
|
10
|
+
color?: string;
|
|
11
|
+
fontSize?: string;
|
|
12
|
+
fontWeight?: string | number;
|
|
13
|
+
textTransform?: string;
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const ShinyText = ({
|
|
18
|
+
children,
|
|
19
|
+
disabled = false,
|
|
20
|
+
speed = 10,
|
|
21
|
+
color = "tertiary",
|
|
22
|
+
fontSize = "medium",
|
|
23
|
+
fontWeight = "normal",
|
|
24
|
+
textTransform,
|
|
25
|
+
...props
|
|
26
|
+
}: ShinyTextProps) => {
|
|
27
|
+
const controls = useAnimation();
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!disabled) {
|
|
31
|
+
controls.start({
|
|
32
|
+
backgroundPosition: ["200% 0", "-200% 0"],
|
|
33
|
+
transition: {
|
|
34
|
+
duration: speed,
|
|
35
|
+
delay: 3,
|
|
36
|
+
ease: "linear",
|
|
37
|
+
repeat: Infinity,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
} else {
|
|
41
|
+
controls.stop();
|
|
42
|
+
}
|
|
43
|
+
}, [disabled, speed, controls]);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Text
|
|
47
|
+
as={motion.div}
|
|
48
|
+
animate={controls}
|
|
49
|
+
color={color}
|
|
50
|
+
fontSize={fontSize}
|
|
51
|
+
fontWeight={fontWeight}
|
|
52
|
+
textTransform={textTransform}
|
|
53
|
+
display="inline-block"
|
|
54
|
+
style={{
|
|
55
|
+
background: `linear-gradient(
|
|
56
|
+
120deg,
|
|
57
|
+
rgba(255, 255, 255, 0) 40%,
|
|
58
|
+
rgba(255, 255, 255,0.8) 50%,
|
|
59
|
+
rgba(255, 255, 255, 0) 60%
|
|
60
|
+
)`,
|
|
61
|
+
backgroundSize: "200% 100%",
|
|
62
|
+
WebkitBackgroundClip: "text",
|
|
63
|
+
backgroundClip: "text",
|
|
64
|
+
}}
|
|
65
|
+
{...props}
|
|
66
|
+
>
|
|
67
|
+
<span>{children}</span>
|
|
68
|
+
</Text>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export default ShinyText;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Text } from "@/design-system/elements";
|
|
3
|
+
import { motion } from "motion/react";
|
|
4
|
+
import Collection from "@/design-system/blocks/Collection";
|
|
5
|
+
import Placeholder from "@/design-system/blocks/Placeholder";
|
|
6
|
+
|
|
7
|
+
interface SkeletonProps {
|
|
8
|
+
count?: number; // Number of placeholder items to show
|
|
9
|
+
aspect?: string; // Aspect ratio of placeholders
|
|
10
|
+
colsize?:
|
|
11
|
+
| "small"
|
|
12
|
+
| "medium"
|
|
13
|
+
| "large"
|
|
14
|
+
| "xlarge"
|
|
15
|
+
| "xxlarge"
|
|
16
|
+
| "auto"
|
|
17
|
+
| "row"; // Optional column size
|
|
18
|
+
showText?: boolean; // Optional flag to show/hide "Loading..." text
|
|
19
|
+
variant?: "grid" | "component";
|
|
20
|
+
width?: string;
|
|
21
|
+
height?: string;
|
|
22
|
+
[key: string]: any; // Allow additional props
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default function Skeleton({
|
|
26
|
+
count = 9,
|
|
27
|
+
aspect = "1.5/1",
|
|
28
|
+
colsize = "xlarge",
|
|
29
|
+
showText = true,
|
|
30
|
+
variant = "grid",
|
|
31
|
+
width = "100%",
|
|
32
|
+
height = "40px",
|
|
33
|
+
...rest
|
|
34
|
+
}: SkeletonProps) {
|
|
35
|
+
if (variant === "component") {
|
|
36
|
+
return (
|
|
37
|
+
<Placeholder
|
|
38
|
+
as={motion.div}
|
|
39
|
+
width={width}
|
|
40
|
+
height={height}
|
|
41
|
+
bg="transparent.light.0"
|
|
42
|
+
shape="rounded"
|
|
43
|
+
icon="IconDotsAnim"
|
|
44
|
+
animate={{ opacity: [0.5, 1, 0.5] }}
|
|
45
|
+
transition={{ duration: 1.5, repeat: Infinity }}
|
|
46
|
+
{...rest}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Original grid variant
|
|
52
|
+
return (
|
|
53
|
+
<Collection colsize={colsize}>
|
|
54
|
+
{[...Array(count)].map((_, i) => (
|
|
55
|
+
<Placeholder
|
|
56
|
+
key={i}
|
|
57
|
+
as={motion.div}
|
|
58
|
+
aspect={aspect}
|
|
59
|
+
bg="transparent.light.0"
|
|
60
|
+
shape="rounded"
|
|
61
|
+
icon="IconDotsAnim"
|
|
62
|
+
animate={{ opacity: [0.5, 1, 0.5] }}
|
|
63
|
+
transition={{ duration: 1.5, repeat: Infinity }}
|
|
64
|
+
{...rest}
|
|
65
|
+
>
|
|
66
|
+
{showText && <Text fontSize="small">Loading...</Text>}
|
|
67
|
+
</Placeholder>
|
|
68
|
+
))}
|
|
69
|
+
</Collection>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Box } from "@/design-system/elements";
|
|
2
|
+
import { IconArrowLeft, IconArrowRight } from "@/design-system/icons";
|
|
3
|
+
import { AnimatePresence, motion } from "motion/react";
|
|
4
|
+
import { Control } from "../Controls/Control";
|
|
5
|
+
|
|
6
|
+
interface SliderControlsProps {
|
|
7
|
+
onPrev: () => void;
|
|
8
|
+
onNext: () => void;
|
|
9
|
+
canGoPrev: boolean;
|
|
10
|
+
canGoNext: boolean;
|
|
11
|
+
slides: number;
|
|
12
|
+
activeSlide: number;
|
|
13
|
+
onChange: (index: number) => void;
|
|
14
|
+
showDots?: boolean;
|
|
15
|
+
showArrows?: boolean;
|
|
16
|
+
paddingX?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const controlVariants = {
|
|
20
|
+
enter: {
|
|
21
|
+
opacity: 0.2,
|
|
22
|
+
width: ".5rem",
|
|
23
|
+
},
|
|
24
|
+
center: {
|
|
25
|
+
opacity: 0.7,
|
|
26
|
+
width: "2rem",
|
|
27
|
+
},
|
|
28
|
+
exit: {
|
|
29
|
+
opacity: 0.1,
|
|
30
|
+
width: ".5rem",
|
|
31
|
+
},
|
|
32
|
+
hover: {
|
|
33
|
+
opacity: 1,
|
|
34
|
+
scale: 1.1,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const SliderControls = ({
|
|
39
|
+
onPrev,
|
|
40
|
+
onNext,
|
|
41
|
+
canGoPrev,
|
|
42
|
+
canGoNext,
|
|
43
|
+
slides,
|
|
44
|
+
activeSlide,
|
|
45
|
+
onChange,
|
|
46
|
+
showDots = true,
|
|
47
|
+
showArrows = true,
|
|
48
|
+
paddingX = 0,
|
|
49
|
+
}: SliderControlsProps) => {
|
|
50
|
+
return (
|
|
51
|
+
<Box
|
|
52
|
+
display="flex"
|
|
53
|
+
alignItems={"center"}
|
|
54
|
+
justifyContent={"center"}
|
|
55
|
+
//position={"absolute"}
|
|
56
|
+
left={`${paddingX}px`}
|
|
57
|
+
right={`${paddingX}px`}
|
|
58
|
+
width="auto"
|
|
59
|
+
gap="s"
|
|
60
|
+
py="m"
|
|
61
|
+
// height={"3rem"}
|
|
62
|
+
//bg="red"
|
|
63
|
+
>
|
|
64
|
+
{showArrows && (
|
|
65
|
+
<Control
|
|
66
|
+
//ml="small"
|
|
67
|
+
position="initial"
|
|
68
|
+
onClick={onPrev}
|
|
69
|
+
disabled={!canGoPrev}
|
|
70
|
+
opacity={canGoPrev ? 1 : 0.1}
|
|
71
|
+
>
|
|
72
|
+
<Box as={IconArrowLeft} size="1.125rem" />
|
|
73
|
+
</Control>
|
|
74
|
+
)}
|
|
75
|
+
|
|
76
|
+
{showDots && (
|
|
77
|
+
<AnimatePresence>
|
|
78
|
+
<Box
|
|
79
|
+
display="flex"
|
|
80
|
+
alignItems="center"
|
|
81
|
+
justifyContent="center"
|
|
82
|
+
gap="xsmall"
|
|
83
|
+
>
|
|
84
|
+
{Array.from({ length: slides }).map((_, i) => (
|
|
85
|
+
<Box
|
|
86
|
+
as={motion.div}
|
|
87
|
+
key={i}
|
|
88
|
+
variants={controlVariants}
|
|
89
|
+
initial="enter"
|
|
90
|
+
animate={i === activeSlide ? "center" : "none"}
|
|
91
|
+
whileHover="hover"
|
|
92
|
+
exit="exit"
|
|
93
|
+
flex="none"
|
|
94
|
+
size="0.5rem"
|
|
95
|
+
bg="black"
|
|
96
|
+
shape="rounded"
|
|
97
|
+
cursor="pointer"
|
|
98
|
+
onClick={() => onChange(i)}
|
|
99
|
+
/>
|
|
100
|
+
))}
|
|
101
|
+
</Box>
|
|
102
|
+
</AnimatePresence>
|
|
103
|
+
)}
|
|
104
|
+
{showArrows && (
|
|
105
|
+
<Control
|
|
106
|
+
//mr="small"
|
|
107
|
+
position="initial"
|
|
108
|
+
onClick={onNext}
|
|
109
|
+
disabled={!canGoNext}
|
|
110
|
+
opacity={canGoNext ? 1 : 0.1}
|
|
111
|
+
>
|
|
112
|
+
<Box as={IconArrowRight} size="1.125rem" />
|
|
113
|
+
</Control>
|
|
114
|
+
)}
|
|
115
|
+
</Box>
|
|
116
|
+
);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export default SliderControls;
|