@alkimi.org/ui-kit 0.1.8 → 0.1.10
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.github.md +63 -11
- package/README.md +2 -33
- package/README.npm.md +2 -33
- package/dist/components/GlitchLink.d.mts +12 -0
- package/dist/components/GlitchLink.d.ts +12 -0
- package/dist/components/GlitchLink.js +74 -0
- package/dist/components/GlitchLink.js.map +1 -0
- package/dist/components/GlitchLink.mjs +44 -0
- package/dist/components/GlitchLink.mjs.map +1 -0
- package/dist/components/PixelLoad.d.mts +20 -0
- package/dist/components/PixelLoad.d.ts +20 -0
- package/dist/components/PixelLoad.js +182 -0
- package/dist/components/PixelLoad.js.map +1 -0
- package/dist/components/PixelLoad.mjs +148 -0
- package/dist/components/PixelLoad.mjs.map +1 -0
- package/dist/components/TextDecoder.d.mts +15 -0
- package/dist/components/TextDecoder.d.ts +15 -0
- package/dist/components/TextDecoder.js +293 -0
- package/dist/components/TextDecoder.js.map +1 -0
- package/dist/components/TextDecoder.mjs +265 -0
- package/dist/components/TextDecoder.mjs.map +1 -0
- package/dist/components/button.d.mts +16 -0
- package/dist/components/button.d.ts +16 -0
- package/dist/components/button.js +109 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/button.mjs +74 -0
- package/dist/components/button.mjs.map +1 -0
- package/dist/components/card.d.mts +10 -0
- package/dist/components/card.d.ts +10 -0
- package/dist/components/card.js +115 -0
- package/dist/components/card.js.map +1 -0
- package/dist/components/card.mjs +76 -0
- package/dist/components/card.mjs.map +1 -0
- package/dist/index.css +250 -11
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +16 -21
- package/dist/index.d.ts +16 -21
- package/dist/index.js +467 -52
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +467 -47
- package/dist/index.mjs.map +1 -1
- package/dist/lib/utils.d.mts +5 -0
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +36 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/utils.mjs +12 -0
- package/dist/lib/utils.mjs.map +1 -0
- package/dist/styles.css +250 -11
- package/dist/styles.css.map +1 -1
- package/package.json +48 -12
package/dist/index.js
CHANGED
|
@@ -32,12 +32,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
32
|
var index_exports = {};
|
|
33
33
|
__export(index_exports, {
|
|
34
34
|
Button: () => Button,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
GlitchLink: () => GlitchLink_default,
|
|
36
|
+
PixelLoad: () => PixelLoad,
|
|
37
|
+
Tabs: () => Tabs,
|
|
38
|
+
TabsContent: () => TabsContent,
|
|
39
|
+
TabsList: () => TabsList,
|
|
40
|
+
TabsTrigger: () => TabsTrigger,
|
|
41
|
+
TextDecoder: () => TextDecoder_default,
|
|
41
42
|
buttonVariants: () => buttonVariants,
|
|
42
43
|
cn: () => cn
|
|
43
44
|
});
|
|
@@ -58,22 +59,22 @@ function cn(...inputs) {
|
|
|
58
59
|
// src/components/button.tsx
|
|
59
60
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
60
61
|
var buttonVariants = (0, import_class_variance_authority.cva)(
|
|
61
|
-
"inline-flex items-center justify-center whitespace-nowrap rounded-
|
|
62
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-[3.75rem] text-[0.875rem] font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
62
63
|
{
|
|
63
64
|
variants: {
|
|
64
65
|
variant: {
|
|
65
66
|
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
66
67
|
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
67
68
|
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
68
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary
|
|
69
|
+
secondary: "bg-secondary/80 text-secondary-foreground hover:bg-secondary",
|
|
69
70
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
70
71
|
link: "text-primary underline-offset-4 hover:underline"
|
|
71
72
|
},
|
|
72
73
|
size: {
|
|
73
|
-
default: "h-
|
|
74
|
-
sm: "h-
|
|
75
|
-
lg: "h-
|
|
76
|
-
icon: "h-
|
|
74
|
+
default: "h-9 px-4 py-2",
|
|
75
|
+
sm: "h-8 text-[0.75rem] px-3 py-2",
|
|
76
|
+
lg: "h-10 px-8 py-2",
|
|
77
|
+
icon: "h-9 w-9"
|
|
77
78
|
}
|
|
78
79
|
},
|
|
79
80
|
defaultVariants: {
|
|
@@ -83,85 +84,499 @@ var buttonVariants = (0, import_class_variance_authority.cva)(
|
|
|
83
84
|
}
|
|
84
85
|
);
|
|
85
86
|
var Button = React.forwardRef(
|
|
86
|
-
({
|
|
87
|
+
({
|
|
88
|
+
className,
|
|
89
|
+
variant,
|
|
90
|
+
size,
|
|
91
|
+
asChild = false,
|
|
92
|
+
loading = false,
|
|
93
|
+
icon,
|
|
94
|
+
...props
|
|
95
|
+
}, ref) => {
|
|
87
96
|
const Comp = asChild ? import_react_slot.Slot : "button";
|
|
88
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
97
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
89
98
|
Comp,
|
|
90
99
|
{
|
|
91
100
|
className: cn(buttonVariants({ variant, size, className })),
|
|
92
101
|
ref,
|
|
93
|
-
|
|
102
|
+
disabled: loading || props.disabled,
|
|
103
|
+
...props,
|
|
104
|
+
children: [
|
|
105
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mr-2 h-4 w-4 animate-spin rounded-full border-[1.33px] border-primary-foreground border-t-transparent" }),
|
|
106
|
+
!loading && icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "mr-2", children: icon }),
|
|
107
|
+
props.children
|
|
108
|
+
]
|
|
94
109
|
}
|
|
95
110
|
);
|
|
96
111
|
}
|
|
97
112
|
);
|
|
98
113
|
Button.displayName = "Button";
|
|
99
114
|
|
|
100
|
-
// src/components/
|
|
115
|
+
// src/components/tabs.tsx
|
|
101
116
|
var React2 = __toESM(require("react"));
|
|
117
|
+
var TabsPrimitive = __toESM(require("@radix-ui/react-tabs"));
|
|
102
118
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
103
|
-
var
|
|
104
|
-
|
|
119
|
+
var Tabs = TabsPrimitive.Root;
|
|
120
|
+
var TabsList = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
121
|
+
TabsPrimitive.List,
|
|
105
122
|
{
|
|
106
123
|
ref,
|
|
107
124
|
className: cn(
|
|
108
|
-
"rounded-
|
|
125
|
+
"inline-flex items-center justify-center rounded-[3.75rem] bg-muted p-1 text-muted-foreground",
|
|
109
126
|
className
|
|
110
127
|
),
|
|
111
128
|
...props
|
|
112
129
|
}
|
|
113
130
|
));
|
|
114
|
-
|
|
115
|
-
var
|
|
116
|
-
|
|
131
|
+
TabsList.displayName = TabsPrimitive.List.displayName;
|
|
132
|
+
var TabsTrigger = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
133
|
+
TabsPrimitive.Trigger,
|
|
117
134
|
{
|
|
118
135
|
ref,
|
|
119
|
-
className: cn(
|
|
136
|
+
className: cn(
|
|
137
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-[3.75rem] px-3 py-1 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-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
|
138
|
+
className
|
|
139
|
+
),
|
|
120
140
|
...props
|
|
121
141
|
}
|
|
122
142
|
));
|
|
123
|
-
|
|
124
|
-
var
|
|
125
|
-
|
|
143
|
+
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
|
144
|
+
var TabsContent = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
145
|
+
TabsPrimitive.Content,
|
|
126
146
|
{
|
|
127
147
|
ref,
|
|
128
148
|
className: cn(
|
|
129
|
-
"
|
|
149
|
+
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
130
150
|
className
|
|
131
151
|
),
|
|
132
152
|
...props
|
|
133
153
|
}
|
|
134
154
|
));
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
155
|
+
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
|
156
|
+
|
|
157
|
+
// src/components/TextDecoder.tsx
|
|
158
|
+
var import_react = __toESM(require("react"));
|
|
159
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
160
|
+
var SYMBOLS = ["\\", "-", "?", "/", "#", "!", "_", "+", "<", ">"];
|
|
161
|
+
var MAX_ITERATIONS = 3;
|
|
162
|
+
var SPEED = 400;
|
|
163
|
+
var scrambleText = (input, symbols) => {
|
|
164
|
+
if (!input) return "";
|
|
165
|
+
return input.split(" ").map((word) => {
|
|
166
|
+
if (!word) return "";
|
|
167
|
+
const randomSymbol = symbols[Math.floor(Math.random() * symbols.length)];
|
|
168
|
+
return randomSymbol.repeat(word.length);
|
|
169
|
+
}).join(" ");
|
|
170
|
+
};
|
|
171
|
+
var extractText = (node) => {
|
|
172
|
+
if (typeof node === "string" || typeof node === "number") {
|
|
173
|
+
return String(node);
|
|
142
174
|
}
|
|
143
|
-
))
|
|
144
|
-
|
|
145
|
-
var CardContent = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, className: cn("p-6 pt-0", className), ...props }));
|
|
146
|
-
CardContent.displayName = "CardContent";
|
|
147
|
-
var CardFooter = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
148
|
-
"div",
|
|
149
|
-
{
|
|
150
|
-
ref,
|
|
151
|
-
className: cn("flex items-center p-6 pt-0", className),
|
|
152
|
-
...props
|
|
175
|
+
if (Array.isArray(node)) {
|
|
176
|
+
return node.map(extractText).join("");
|
|
153
177
|
}
|
|
154
|
-
))
|
|
155
|
-
|
|
178
|
+
if (import_react.default.isValidElement(node)) {
|
|
179
|
+
const props = node.props;
|
|
180
|
+
let result = "";
|
|
181
|
+
if (typeof props.text === "string") {
|
|
182
|
+
result += props.text;
|
|
183
|
+
}
|
|
184
|
+
if (typeof props.label === "string") {
|
|
185
|
+
result += props.label;
|
|
186
|
+
}
|
|
187
|
+
if (typeof props.title === "string") {
|
|
188
|
+
result += props.title;
|
|
189
|
+
}
|
|
190
|
+
if (props.children) {
|
|
191
|
+
result += extractText(props.children);
|
|
192
|
+
}
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
return "";
|
|
196
|
+
};
|
|
197
|
+
var scrambleReactNode = (node, scrambledText, textStartIndex) => {
|
|
198
|
+
if (typeof node === "string" || typeof node === "number") {
|
|
199
|
+
const text = String(node);
|
|
200
|
+
let scrambled = "";
|
|
201
|
+
for (let i = 0; i < text.length; i++) {
|
|
202
|
+
if (textStartIndex.current < scrambledText.length) {
|
|
203
|
+
scrambled += scrambledText[textStartIndex.current];
|
|
204
|
+
textStartIndex.current++;
|
|
205
|
+
} else {
|
|
206
|
+
scrambled += text[i];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return scrambled;
|
|
210
|
+
}
|
|
211
|
+
if (Array.isArray(node)) {
|
|
212
|
+
return node.map((child, index) => {
|
|
213
|
+
const scrambledChild = scrambleReactNode(
|
|
214
|
+
child,
|
|
215
|
+
scrambledText,
|
|
216
|
+
textStartIndex
|
|
217
|
+
);
|
|
218
|
+
if (import_react.default.isValidElement(scrambledChild)) {
|
|
219
|
+
const originalKey = import_react.default.isValidElement(child) ? child.key : null;
|
|
220
|
+
if (scrambledChild.key == null && originalKey == null) {
|
|
221
|
+
return import_react.default.cloneElement(scrambledChild, { key: `decoded-${index}` });
|
|
222
|
+
}
|
|
223
|
+
if (scrambledChild.key == null && originalKey != null) {
|
|
224
|
+
return import_react.default.cloneElement(scrambledChild, { key: originalKey });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return scrambledChild;
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
if (import_react.default.isValidElement(node)) {
|
|
231
|
+
const props = node.props;
|
|
232
|
+
const newProps = { ...props };
|
|
233
|
+
if (typeof props.text === "string") {
|
|
234
|
+
const text = props.text;
|
|
235
|
+
let scrambled = "";
|
|
236
|
+
for (let i = 0; i < text.length; i++) {
|
|
237
|
+
if (textStartIndex.current < scrambledText.length) {
|
|
238
|
+
scrambled += scrambledText[textStartIndex.current];
|
|
239
|
+
textStartIndex.current++;
|
|
240
|
+
} else {
|
|
241
|
+
scrambled += text[i];
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
newProps.text = scrambled;
|
|
245
|
+
}
|
|
246
|
+
if (typeof props.label === "string") {
|
|
247
|
+
const label = props.label;
|
|
248
|
+
let scrambled = "";
|
|
249
|
+
for (let i = 0; i < label.length; i++) {
|
|
250
|
+
if (textStartIndex.current < scrambledText.length) {
|
|
251
|
+
scrambled += scrambledText[textStartIndex.current];
|
|
252
|
+
textStartIndex.current++;
|
|
253
|
+
} else {
|
|
254
|
+
scrambled += label[i];
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
newProps.label = scrambled;
|
|
258
|
+
}
|
|
259
|
+
if (typeof props.title === "string") {
|
|
260
|
+
const title = props.title;
|
|
261
|
+
let scrambled = "";
|
|
262
|
+
for (let i = 0; i < title.length; i++) {
|
|
263
|
+
if (textStartIndex.current < scrambledText.length) {
|
|
264
|
+
scrambled += scrambledText[textStartIndex.current];
|
|
265
|
+
textStartIndex.current++;
|
|
266
|
+
} else {
|
|
267
|
+
scrambled += title[i];
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
newProps.title = scrambled;
|
|
271
|
+
}
|
|
272
|
+
if (props.children) {
|
|
273
|
+
newProps.children = scrambleReactNode(
|
|
274
|
+
props.children,
|
|
275
|
+
scrambledText,
|
|
276
|
+
textStartIndex
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
return import_react.default.cloneElement(node, newProps);
|
|
280
|
+
}
|
|
281
|
+
return node;
|
|
282
|
+
};
|
|
283
|
+
var TextDecoder = ({
|
|
284
|
+
children,
|
|
285
|
+
className,
|
|
286
|
+
delay = 0,
|
|
287
|
+
symbols = SYMBOLS,
|
|
288
|
+
maxIterations = MAX_ITERATIONS,
|
|
289
|
+
speed = SPEED
|
|
290
|
+
}) => {
|
|
291
|
+
const [displayContent, setDisplayContent] = (0, import_react.useState)(null);
|
|
292
|
+
const [hasAnimated, setHasAnimated] = (0, import_react.useState)(false);
|
|
293
|
+
const elementRef = (0, import_react.useRef)(null);
|
|
294
|
+
const fullText = (0, import_react.useMemo)(() => extractText(children), [children]);
|
|
295
|
+
const initialScrambled = (0, import_react.useMemo)(
|
|
296
|
+
() => scrambleText(fullText, symbols),
|
|
297
|
+
[fullText, symbols]
|
|
298
|
+
);
|
|
299
|
+
(0, import_react.useEffect)(() => {
|
|
300
|
+
if (!hasAnimated && fullText) {
|
|
301
|
+
const textStartIndex = { current: 0 };
|
|
302
|
+
const scrambledContent = scrambleReactNode(
|
|
303
|
+
children,
|
|
304
|
+
initialScrambled,
|
|
305
|
+
textStartIndex
|
|
306
|
+
);
|
|
307
|
+
setDisplayContent(scrambledContent);
|
|
308
|
+
}
|
|
309
|
+
}, [children, initialScrambled, hasAnimated, fullText]);
|
|
310
|
+
(0, import_react.useEffect)(() => {
|
|
311
|
+
if (!fullText) {
|
|
312
|
+
setDisplayContent(null);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (hasAnimated) {
|
|
316
|
+
setDisplayContent(children);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const element = elementRef.current;
|
|
320
|
+
if (!element) return;
|
|
321
|
+
let iteration = 0;
|
|
322
|
+
let intervalId = null;
|
|
323
|
+
let delayTimeoutId = null;
|
|
324
|
+
const observer = new IntersectionObserver(
|
|
325
|
+
(entries) => {
|
|
326
|
+
const entry = entries[0];
|
|
327
|
+
if (entry.isIntersecting && !hasAnimated) {
|
|
328
|
+
delayTimeoutId = setTimeout(() => {
|
|
329
|
+
const textStartIndex = { current: 0 };
|
|
330
|
+
const scrambledContent = scrambleReactNode(
|
|
331
|
+
children,
|
|
332
|
+
initialScrambled,
|
|
333
|
+
textStartIndex
|
|
334
|
+
);
|
|
335
|
+
setDisplayContent(scrambledContent);
|
|
336
|
+
intervalId = setInterval(() => {
|
|
337
|
+
iteration++;
|
|
338
|
+
if (iteration >= maxIterations) {
|
|
339
|
+
setDisplayContent(children);
|
|
340
|
+
setHasAnimated(true);
|
|
341
|
+
if (intervalId) clearInterval(intervalId);
|
|
342
|
+
} else {
|
|
343
|
+
const newScrambled = scrambleText(fullText, symbols);
|
|
344
|
+
const textStartIndex2 = { current: 0 };
|
|
345
|
+
const scrambledContent2 = scrambleReactNode(
|
|
346
|
+
children,
|
|
347
|
+
newScrambled,
|
|
348
|
+
textStartIndex2
|
|
349
|
+
);
|
|
350
|
+
setDisplayContent(scrambledContent2);
|
|
351
|
+
}
|
|
352
|
+
}, speed);
|
|
353
|
+
}, delay);
|
|
354
|
+
observer.disconnect();
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
threshold: 0.1
|
|
359
|
+
// Trigger when 10% of the element is visible
|
|
360
|
+
}
|
|
361
|
+
);
|
|
362
|
+
observer.observe(element);
|
|
363
|
+
return () => {
|
|
364
|
+
observer.disconnect();
|
|
365
|
+
if (intervalId) clearInterval(intervalId);
|
|
366
|
+
if (delayTimeoutId) clearTimeout(delayTimeoutId);
|
|
367
|
+
};
|
|
368
|
+
}, [
|
|
369
|
+
children,
|
|
370
|
+
fullText,
|
|
371
|
+
initialScrambled,
|
|
372
|
+
hasAnimated,
|
|
373
|
+
delay,
|
|
374
|
+
symbols,
|
|
375
|
+
maxIterations,
|
|
376
|
+
speed
|
|
377
|
+
]);
|
|
378
|
+
const ariaLabel = (0, import_react.useMemo)(() => extractText(children), [children]);
|
|
379
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
380
|
+
"span",
|
|
381
|
+
{
|
|
382
|
+
ref: elementRef,
|
|
383
|
+
"aria-label": ariaLabel,
|
|
384
|
+
className,
|
|
385
|
+
children: displayContent
|
|
386
|
+
}
|
|
387
|
+
);
|
|
388
|
+
};
|
|
389
|
+
var TextDecoder_default = TextDecoder;
|
|
390
|
+
|
|
391
|
+
// src/components/GlitchLink.tsx
|
|
392
|
+
var import_link = __toESM(require("next/link"));
|
|
393
|
+
var import_react2 = require("react");
|
|
394
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
395
|
+
var DEFAULT_SYMBOLS = ["/", "#", "*"];
|
|
396
|
+
var GlitchLink = ({
|
|
397
|
+
href,
|
|
398
|
+
children,
|
|
399
|
+
symbols = DEFAULT_SYMBOLS,
|
|
400
|
+
className = "underline",
|
|
401
|
+
...props
|
|
402
|
+
}) => {
|
|
403
|
+
const [isHovering, setIsHovering] = (0, import_react2.useState)(false);
|
|
404
|
+
const text = typeof children === "string" ? children : "";
|
|
405
|
+
const getRandomGlitch = () => {
|
|
406
|
+
if (!isHovering || !text) return children;
|
|
407
|
+
return text.split(" ").map((word) => {
|
|
408
|
+
const randomLetterIndex = Math.floor(Math.random() * word.length);
|
|
409
|
+
return word.replace(
|
|
410
|
+
word[randomLetterIndex],
|
|
411
|
+
symbols[Math.floor(Math.random() * symbols.length)]
|
|
412
|
+
);
|
|
413
|
+
}).join(" ");
|
|
414
|
+
};
|
|
415
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
416
|
+
import_link.default,
|
|
417
|
+
{
|
|
418
|
+
href,
|
|
419
|
+
className,
|
|
420
|
+
onMouseEnter: () => setIsHovering(true),
|
|
421
|
+
onMouseLeave: () => setIsHovering(false),
|
|
422
|
+
...props,
|
|
423
|
+
children: text ? isHovering ? getRandomGlitch() : children : children
|
|
424
|
+
}
|
|
425
|
+
);
|
|
426
|
+
};
|
|
427
|
+
var GlitchLink_default = GlitchLink;
|
|
428
|
+
|
|
429
|
+
// src/components/PixelLoad.tsx
|
|
430
|
+
var import_image = __toESM(require("next/image"));
|
|
431
|
+
var import_react3 = require("react");
|
|
432
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
433
|
+
function isStaticImageData(src) {
|
|
434
|
+
return typeof src === "object" && "src" in src;
|
|
435
|
+
}
|
|
436
|
+
function getImageSrc(src) {
|
|
437
|
+
return isStaticImageData(src) ? src.src : src;
|
|
438
|
+
}
|
|
439
|
+
function PixelLoad({
|
|
440
|
+
src,
|
|
441
|
+
alt,
|
|
442
|
+
duration = 600,
|
|
443
|
+
steps = 15,
|
|
444
|
+
className,
|
|
445
|
+
onAnimationComplete,
|
|
446
|
+
priority,
|
|
447
|
+
quality,
|
|
448
|
+
placeholder = "empty",
|
|
449
|
+
blurDataURL,
|
|
450
|
+
objectFit = "cover"
|
|
451
|
+
}) {
|
|
452
|
+
const containerRef = (0, import_react3.useRef)(null);
|
|
453
|
+
const canvasRef = (0, import_react3.useRef)(null);
|
|
454
|
+
const [status, setStatus] = (0, import_react3.useState)("loading");
|
|
455
|
+
const [dimensions, setDimensions] = (0, import_react3.useState)(null);
|
|
456
|
+
const imageSrc = getImageSrc(src);
|
|
457
|
+
const drawPixelated = (0, import_react3.useCallback)(
|
|
458
|
+
(ctx, img, pixelSize, w, h) => {
|
|
459
|
+
ctx.imageSmoothingEnabled = false;
|
|
460
|
+
const sw = Math.max(1, Math.floor(w / pixelSize));
|
|
461
|
+
const sh = Math.max(1, Math.floor(h / pixelSize));
|
|
462
|
+
ctx.clearRect(0, 0, w, h);
|
|
463
|
+
ctx.drawImage(img, 0, 0, sw, sh);
|
|
464
|
+
ctx.drawImage(canvasRef.current, 0, 0, sw, sh, 0, 0, w, h);
|
|
465
|
+
},
|
|
466
|
+
[]
|
|
467
|
+
);
|
|
468
|
+
const runAnimation = (0, import_react3.useCallback)(
|
|
469
|
+
(ctx, img, w, h) => {
|
|
470
|
+
const minPixelSize = Math.max(w, h) / 4;
|
|
471
|
+
const intervalMs = duration / steps;
|
|
472
|
+
let currentStep = 0;
|
|
473
|
+
setStatus("animating");
|
|
474
|
+
const animate = () => {
|
|
475
|
+
const progress = currentStep / steps;
|
|
476
|
+
const pixelSize = Math.max(1, Math.floor(minPixelSize * (1 - progress)));
|
|
477
|
+
drawPixelated(ctx, img, pixelSize, w, h);
|
|
478
|
+
currentStep++;
|
|
479
|
+
if (currentStep <= steps) {
|
|
480
|
+
window.setTimeout(animate, intervalMs);
|
|
481
|
+
} else {
|
|
482
|
+
setStatus("complete");
|
|
483
|
+
onAnimationComplete?.();
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
animate();
|
|
487
|
+
},
|
|
488
|
+
[duration, steps, drawPixelated, onAnimationComplete]
|
|
489
|
+
);
|
|
490
|
+
(0, import_react3.useEffect)(() => {
|
|
491
|
+
const container = containerRef.current;
|
|
492
|
+
if (!container) return;
|
|
493
|
+
const updateDimensions = () => {
|
|
494
|
+
const { width, height } = container.getBoundingClientRect();
|
|
495
|
+
setDimensions({ width: Math.floor(width), height: Math.floor(height) });
|
|
496
|
+
};
|
|
497
|
+
const resizeObserver = new ResizeObserver(updateDimensions);
|
|
498
|
+
resizeObserver.observe(container);
|
|
499
|
+
updateDimensions();
|
|
500
|
+
return () => {
|
|
501
|
+
resizeObserver.disconnect();
|
|
502
|
+
};
|
|
503
|
+
}, []);
|
|
504
|
+
(0, import_react3.useEffect)(() => {
|
|
505
|
+
if (!dimensions) return;
|
|
506
|
+
if (dimensions.width <= 0 || dimensions.height <= 0) return;
|
|
507
|
+
const canvas = canvasRef.current;
|
|
508
|
+
if (!canvas) return;
|
|
509
|
+
const ctx = canvas.getContext("2d");
|
|
510
|
+
if (!ctx) return;
|
|
511
|
+
canvas.width = dimensions.width;
|
|
512
|
+
canvas.height = dimensions.height;
|
|
513
|
+
const img = new window.Image();
|
|
514
|
+
img.crossOrigin = "anonymous";
|
|
515
|
+
img.onload = () => {
|
|
516
|
+
const minPixelSize = Math.max(dimensions.width, dimensions.height) / 4;
|
|
517
|
+
drawPixelated(ctx, img, minPixelSize, dimensions.width, dimensions.height);
|
|
518
|
+
runAnimation(ctx, img, dimensions.width, dimensions.height);
|
|
519
|
+
};
|
|
520
|
+
img.onerror = () => {
|
|
521
|
+
console.error("PixelLoad: Failed to load image");
|
|
522
|
+
};
|
|
523
|
+
img.src = imageSrc;
|
|
524
|
+
return () => {
|
|
525
|
+
img.onload = null;
|
|
526
|
+
img.onerror = null;
|
|
527
|
+
};
|
|
528
|
+
}, [imageSrc, dimensions, runAnimation, drawPixelated]);
|
|
529
|
+
const isComplete = status === "complete";
|
|
530
|
+
const isAnimating = status === "animating" || status === "loading";
|
|
531
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
532
|
+
"div",
|
|
533
|
+
{
|
|
534
|
+
ref: containerRef,
|
|
535
|
+
className: `relative w-full h-full ${className || ""}`,
|
|
536
|
+
children: [
|
|
537
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
538
|
+
"canvas",
|
|
539
|
+
{
|
|
540
|
+
ref: canvasRef,
|
|
541
|
+
className: "absolute top-0 left-0 w-full h-full",
|
|
542
|
+
style: {
|
|
543
|
+
objectFit,
|
|
544
|
+
opacity: isComplete ? 0 : 1,
|
|
545
|
+
zIndex: isAnimating ? 2 : 1
|
|
546
|
+
},
|
|
547
|
+
"aria-hidden": isComplete
|
|
548
|
+
}
|
|
549
|
+
),
|
|
550
|
+
isComplete && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
551
|
+
import_image.default,
|
|
552
|
+
{
|
|
553
|
+
src,
|
|
554
|
+
alt,
|
|
555
|
+
fill: true,
|
|
556
|
+
priority,
|
|
557
|
+
quality,
|
|
558
|
+
placeholder,
|
|
559
|
+
blurDataURL,
|
|
560
|
+
className: "opacity-100 transition-opacity duration-150 ease-out z-[1]",
|
|
561
|
+
style: {
|
|
562
|
+
objectFit
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
)
|
|
566
|
+
]
|
|
567
|
+
}
|
|
568
|
+
);
|
|
569
|
+
}
|
|
156
570
|
// Annotate the CommonJS export names for ESM import in node:
|
|
157
571
|
0 && (module.exports = {
|
|
158
572
|
Button,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
573
|
+
GlitchLink,
|
|
574
|
+
PixelLoad,
|
|
575
|
+
Tabs,
|
|
576
|
+
TabsContent,
|
|
577
|
+
TabsList,
|
|
578
|
+
TabsTrigger,
|
|
579
|
+
TextDecoder,
|
|
165
580
|
buttonVariants,
|
|
166
581
|
cn
|
|
167
582
|
});
|