@allshift/ui 0.2.0 → 0.3.1
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/dist/index.cjs +599 -2
- package/dist/index.d.cts +195 -11
- package/dist/index.d.ts +195 -11
- package/dist/index.js +596 -1
- package/package.json +12 -3
- package/styles/shift-canvas.css +67 -0
package/dist/index.cjs
CHANGED
|
@@ -30,10 +30,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
ACCENT_RGB: () => ACCENT_RGB,
|
|
34
|
+
CanvasLauncher: () => CanvasLauncher,
|
|
35
|
+
CanvasTransition: () => CanvasTransition,
|
|
36
|
+
GenerativeView: () => GenerativeView,
|
|
33
37
|
HolographicShine: () => HolographicShine,
|
|
38
|
+
LiveCard: () => LiveCard,
|
|
39
|
+
LiveStat: () => LiveStat,
|
|
40
|
+
PageTransition: () => PageTransition,
|
|
34
41
|
ScrollGenerateCard: () => ScrollGenerateCard,
|
|
35
42
|
ShiftCard: () => ShiftCard,
|
|
36
|
-
TiltCard: () => TiltCard
|
|
43
|
+
TiltCard: () => TiltCard,
|
|
44
|
+
useGenerate: () => useGenerate
|
|
37
45
|
});
|
|
38
46
|
module.exports = __toCommonJS(index_exports);
|
|
39
47
|
|
|
@@ -232,10 +240,599 @@ function ScrollGenerateCard({
|
|
|
232
240
|
phase === "idle" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { visibility: "hidden" }, children: children("idle") })
|
|
233
241
|
] });
|
|
234
242
|
}
|
|
243
|
+
|
|
244
|
+
// src/canvas/LiveCard.tsx
|
|
245
|
+
var import_framer_motion6 = require("framer-motion");
|
|
246
|
+
|
|
247
|
+
// src/canvas/useGenerate.ts
|
|
248
|
+
var import_react4 = require("react");
|
|
249
|
+
var import_framer_motion5 = require("framer-motion");
|
|
250
|
+
function useGenerate(opts = {}) {
|
|
251
|
+
const {
|
|
252
|
+
enterDelay = 0,
|
|
253
|
+
skeletonMs = 420,
|
|
254
|
+
trigger = "view",
|
|
255
|
+
margin = "-60px 0px",
|
|
256
|
+
repeat = false
|
|
257
|
+
} = opts;
|
|
258
|
+
const ref = (0, import_react4.useRef)(null);
|
|
259
|
+
const inView = (0, import_framer_motion5.useInView)(ref, { once: !repeat, margin });
|
|
260
|
+
const [phase, setPhase] = (0, import_react4.useState)("idle");
|
|
261
|
+
(0, import_react4.useEffect)(() => {
|
|
262
|
+
const shouldRun = trigger === "mount" || inView;
|
|
263
|
+
if (!shouldRun) return;
|
|
264
|
+
if (!repeat && phase !== "idle") return;
|
|
265
|
+
let live;
|
|
266
|
+
const enter = setTimeout(() => {
|
|
267
|
+
setPhase("skeleton");
|
|
268
|
+
live = setTimeout(() => setPhase("live"), skeletonMs);
|
|
269
|
+
}, enterDelay);
|
|
270
|
+
return () => {
|
|
271
|
+
clearTimeout(enter);
|
|
272
|
+
clearTimeout(live);
|
|
273
|
+
};
|
|
274
|
+
}, [inView, trigger]);
|
|
275
|
+
return { ref, phase, isLive: phase === "live" };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// src/canvas/accents.ts
|
|
279
|
+
var ACCENT_RGB = {
|
|
280
|
+
teal: "0,229,240",
|
|
281
|
+
blue: "59,139,255",
|
|
282
|
+
purple: "168,124,255",
|
|
283
|
+
magenta: "232,48,248",
|
|
284
|
+
green: "0,224,128",
|
|
285
|
+
orange: "255,110,48",
|
|
286
|
+
neutral: "255,255,255"
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// src/canvas/LiveCard.tsx
|
|
290
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
291
|
+
function resolveRgb(accent) {
|
|
292
|
+
if (accent === "brand") return { rgb: "var(--shift-accent-rgb, 91,140,255)", isBrand: true };
|
|
293
|
+
return { rgb: ACCENT_RGB[accent], isBrand: false };
|
|
294
|
+
}
|
|
295
|
+
var SKEL_WIDTHS = [72, 88, 60, 80, 66, 78, 54, 84];
|
|
296
|
+
function Skeleton({ rows, minHeight }) {
|
|
297
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
298
|
+
import_framer_motion6.motion.div,
|
|
299
|
+
{
|
|
300
|
+
initial: { opacity: 0, y: 16 },
|
|
301
|
+
animate: { opacity: 1, y: 0 },
|
|
302
|
+
transition: { duration: 0.3 },
|
|
303
|
+
className: "ash-surface relative rounded-2xl border border-white/[0.07] p-5 overflow-hidden",
|
|
304
|
+
style: { minHeight },
|
|
305
|
+
children: [
|
|
306
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-5 w-28 rounded-full bg-white/[0.07] animate-pulse mb-5" }),
|
|
307
|
+
Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-3 mb-3", children: [
|
|
308
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-7 h-7 rounded-xl bg-white/5 animate-pulse shrink-0" }),
|
|
309
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
310
|
+
"div",
|
|
311
|
+
{
|
|
312
|
+
className: "h-2.5 rounded-full bg-white/5 animate-pulse",
|
|
313
|
+
style: { width: `${SKEL_WIDTHS[i % SKEL_WIDTHS.length]}%` }
|
|
314
|
+
}
|
|
315
|
+
)
|
|
316
|
+
] }, i)),
|
|
317
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
318
|
+
import_framer_motion6.motion.div,
|
|
319
|
+
{
|
|
320
|
+
className: "absolute inset-0 pointer-events-none",
|
|
321
|
+
style: { background: "linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.05) 50%, transparent 100%)" },
|
|
322
|
+
animate: { x: ["-100%", "200%"] },
|
|
323
|
+
transition: { duration: 1.25, ease: "easeInOut", repeat: Infinity }
|
|
324
|
+
}
|
|
325
|
+
)
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
function LiveCard({
|
|
331
|
+
children,
|
|
332
|
+
accent = "neutral",
|
|
333
|
+
tilt = true,
|
|
334
|
+
shine = true,
|
|
335
|
+
generate = true,
|
|
336
|
+
index = 0,
|
|
337
|
+
trigger = "view",
|
|
338
|
+
skeletonRows = 4,
|
|
339
|
+
topLine = true,
|
|
340
|
+
className = "",
|
|
341
|
+
minHeight = 180,
|
|
342
|
+
onClick
|
|
343
|
+
}) {
|
|
344
|
+
const { rgb } = resolveRgb(accent);
|
|
345
|
+
const { ref, phase } = useGenerate({
|
|
346
|
+
enterDelay: generate ? index * 75 : 0,
|
|
347
|
+
trigger
|
|
348
|
+
});
|
|
349
|
+
const effectivePhase = generate ? phase : "live";
|
|
350
|
+
const mx = (0, import_framer_motion6.useMotionValue)(0.5);
|
|
351
|
+
const my = (0, import_framer_motion6.useMotionValue)(0.5);
|
|
352
|
+
const rawRY = (0, import_framer_motion6.useTransform)(mx, [0, 1], [-7, 7]);
|
|
353
|
+
const rawRX = (0, import_framer_motion6.useTransform)(my, [0, 1], [4, -4]);
|
|
354
|
+
const rotateY = (0, import_framer_motion6.useSpring)(rawRY, { stiffness: 300, damping: 28 });
|
|
355
|
+
const rotateX = (0, import_framer_motion6.useSpring)(rawRX, { stiffness: 300, damping: 28 });
|
|
356
|
+
const shineX = (0, import_framer_motion6.useMotionValue)(50);
|
|
357
|
+
const shineY = (0, import_framer_motion6.useMotionValue)(50);
|
|
358
|
+
const shineBg = import_framer_motion6.useMotionTemplate`radial-gradient(circle at ${shineX}% ${shineY}%, rgba(${rgb},0.10) 0%, rgba(${rgb},0.035) 42%, transparent 66%)`;
|
|
359
|
+
function onMouseMove(e) {
|
|
360
|
+
if (!tilt && !shine) return;
|
|
361
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
362
|
+
const nx = (e.clientX - rect.left) / rect.width;
|
|
363
|
+
const ny = (e.clientY - rect.top) / rect.height;
|
|
364
|
+
mx.set(nx);
|
|
365
|
+
my.set(ny);
|
|
366
|
+
shineX.set(nx * 100);
|
|
367
|
+
shineY.set(ny * 100);
|
|
368
|
+
}
|
|
369
|
+
function onMouseLeave() {
|
|
370
|
+
mx.set(0.5);
|
|
371
|
+
my.set(0.5);
|
|
372
|
+
shineX.set(50);
|
|
373
|
+
shineY.set(50);
|
|
374
|
+
}
|
|
375
|
+
if (effectivePhase === "idle") {
|
|
376
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref, className: `rounded-2xl border border-white/[0.04] ${className}`, style: { minHeight } });
|
|
377
|
+
}
|
|
378
|
+
if (effectivePhase === "skeleton") {
|
|
379
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref, className, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Skeleton, { rows: skeletonRows, minHeight }) });
|
|
380
|
+
}
|
|
381
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
382
|
+
"div",
|
|
383
|
+
{
|
|
384
|
+
ref,
|
|
385
|
+
style: { perspective: tilt ? "1000px" : void 0 },
|
|
386
|
+
onMouseMove,
|
|
387
|
+
onMouseLeave,
|
|
388
|
+
className,
|
|
389
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
390
|
+
import_framer_motion6.motion.div,
|
|
391
|
+
{
|
|
392
|
+
style: {
|
|
393
|
+
rotateX: tilt ? rotateX : void 0,
|
|
394
|
+
rotateY: tilt ? rotateY : void 0,
|
|
395
|
+
background: shine ? shineBg : void 0,
|
|
396
|
+
transformStyle: tilt ? "preserve-3d" : void 0
|
|
397
|
+
},
|
|
398
|
+
initial: generate ? { opacity: 0, y: 12 } : false,
|
|
399
|
+
animate: { opacity: 1, y: 0 },
|
|
400
|
+
transition: { duration: 0.3 },
|
|
401
|
+
whileHover: tilt ? { scale: 1.012, y: -3 } : void 0,
|
|
402
|
+
onClick,
|
|
403
|
+
className: `ash-surface group relative rounded-2xl border border-white/[0.08] p-5 overflow-hidden transition-colors duration-300 ${onClick ? "cursor-pointer" : ""}`,
|
|
404
|
+
children: [
|
|
405
|
+
topLine && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
406
|
+
import_framer_motion6.motion.div,
|
|
407
|
+
{
|
|
408
|
+
className: "absolute top-0 left-0 right-0 h-px",
|
|
409
|
+
style: { background: `linear-gradient(90deg, transparent, rgba(${rgb},0.9), transparent)`, transformOrigin: "left" },
|
|
410
|
+
initial: { scaleX: 0, opacity: 0 },
|
|
411
|
+
animate: { scaleX: 1, opacity: 0.7 },
|
|
412
|
+
transition: { duration: 0.5, ease: "easeOut" }
|
|
413
|
+
}
|
|
414
|
+
),
|
|
415
|
+
children,
|
|
416
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
417
|
+
"div",
|
|
418
|
+
{
|
|
419
|
+
className: "absolute bottom-0 right-0 w-32 h-32 rounded-full blur-2xl opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none",
|
|
420
|
+
style: { background: `rgba(${rgb},0.18)` }
|
|
421
|
+
}
|
|
422
|
+
)
|
|
423
|
+
]
|
|
424
|
+
}
|
|
425
|
+
)
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// src/canvas/GenerativeView.tsx
|
|
431
|
+
var import_react5 = require("react");
|
|
432
|
+
var import_framer_motion7 = require("framer-motion");
|
|
433
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
434
|
+
function GenerativeView({
|
|
435
|
+
children,
|
|
436
|
+
stagger = 0.08,
|
|
437
|
+
delay = 0,
|
|
438
|
+
className = ""
|
|
439
|
+
}) {
|
|
440
|
+
const items = import_react5.Children.toArray(children);
|
|
441
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
442
|
+
import_framer_motion7.motion.div,
|
|
443
|
+
{
|
|
444
|
+
className,
|
|
445
|
+
initial: "hidden",
|
|
446
|
+
animate: "show",
|
|
447
|
+
variants: {
|
|
448
|
+
hidden: {},
|
|
449
|
+
show: { transition: { staggerChildren: stagger, delayChildren: delay } }
|
|
450
|
+
},
|
|
451
|
+
children: items.map(
|
|
452
|
+
(child, i) => (0, import_react5.isValidElement)(child) ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
453
|
+
import_framer_motion7.motion.div,
|
|
454
|
+
{
|
|
455
|
+
variants: {
|
|
456
|
+
hidden: { opacity: 0, y: 16, filter: "blur(6px)" },
|
|
457
|
+
show: {
|
|
458
|
+
opacity: 1,
|
|
459
|
+
y: 0,
|
|
460
|
+
filter: "blur(0px)",
|
|
461
|
+
transition: { type: "spring", stiffness: 260, damping: 28 }
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
children: child
|
|
465
|
+
},
|
|
466
|
+
child.key ?? i
|
|
467
|
+
) : child
|
|
468
|
+
)
|
|
469
|
+
}
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/canvas/LiveStat.tsx
|
|
474
|
+
var import_react6 = require("react");
|
|
475
|
+
var import_framer_motion8 = require("framer-motion");
|
|
476
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
477
|
+
function rgbFor(accent) {
|
|
478
|
+
if (accent === "brand") return "var(--shift-accent-rgb, 91,140,255)";
|
|
479
|
+
return ACCENT_RGB[accent];
|
|
480
|
+
}
|
|
481
|
+
function formatCompact(n, prefix, suffix) {
|
|
482
|
+
let body;
|
|
483
|
+
if (Math.abs(n) >= 1e6) body = `${(n / 1e6).toFixed(1)}M`;
|
|
484
|
+
else if (Math.abs(n) >= 1e3) body = `${(n / 1e3).toFixed(0)}K`;
|
|
485
|
+
else body = n.toLocaleString();
|
|
486
|
+
return `${prefix}${body}${suffix}`;
|
|
487
|
+
}
|
|
488
|
+
function LiveStat({
|
|
489
|
+
label,
|
|
490
|
+
value,
|
|
491
|
+
display,
|
|
492
|
+
prefix = "",
|
|
493
|
+
suffix = "",
|
|
494
|
+
sub,
|
|
495
|
+
icon: Icon,
|
|
496
|
+
accent = "neutral",
|
|
497
|
+
duration = 1200,
|
|
498
|
+
index = 0
|
|
499
|
+
}) {
|
|
500
|
+
const rgb = rgbFor(accent);
|
|
501
|
+
const [n, setN] = (0, import_react6.useState)(0);
|
|
502
|
+
const raf = (0, import_react6.useRef)(0);
|
|
503
|
+
(0, import_react6.useEffect)(() => {
|
|
504
|
+
if (value == null || display != null) return;
|
|
505
|
+
const start = performance.now();
|
|
506
|
+
const step = (now) => {
|
|
507
|
+
const pct = Math.min((now - start) / duration, 1);
|
|
508
|
+
const eased = 1 - Math.pow(1 - pct, 3);
|
|
509
|
+
setN(value * eased);
|
|
510
|
+
if (pct < 1) raf.current = requestAnimationFrame(step);
|
|
511
|
+
};
|
|
512
|
+
raf.current = requestAnimationFrame(step);
|
|
513
|
+
return () => cancelAnimationFrame(raf.current);
|
|
514
|
+
}, [value, display, duration]);
|
|
515
|
+
const shown = display ?? (value != null ? formatCompact(n, prefix, suffix) : "\u2014");
|
|
516
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
517
|
+
import_framer_motion8.motion.div,
|
|
518
|
+
{
|
|
519
|
+
initial: { opacity: 0, y: 16, scale: 0.96 },
|
|
520
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
521
|
+
transition: { type: "spring", stiffness: 280, damping: 26, delay: index * 0.06 },
|
|
522
|
+
className: "ash-surface relative rounded-2xl border border-white/[0.08] p-4 overflow-hidden",
|
|
523
|
+
children: [
|
|
524
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "absolute top-0 left-0 right-0 h-px", style: { background: `rgba(${rgb},0.6)` } }),
|
|
525
|
+
Icon && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "w-8 h-8 rounded-xl flex items-center justify-center mb-3", style: { background: `rgba(${rgb},0.15)` }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { size: 14, style: { color: `rgb(${rgb})` } }) }),
|
|
526
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-2xl font-black mb-1", style: { color: `rgb(${rgb})`, filter: `drop-shadow(0 0 10px rgba(${rgb},0.45))` }, children: shown }),
|
|
527
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-[11px] font-bold text-white/70", children: label }),
|
|
528
|
+
sub && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-[10px] text-white/30 mt-0.5", children: sub })
|
|
529
|
+
]
|
|
530
|
+
}
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/canvas/CanvasTransition.tsx
|
|
535
|
+
var import_navigation = require("next/navigation");
|
|
536
|
+
var import_react7 = require("react");
|
|
537
|
+
var import_framer_motion9 = require("framer-motion");
|
|
538
|
+
var import_lucide_react = require("lucide-react");
|
|
539
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
540
|
+
function CanvasTransition({
|
|
541
|
+
children,
|
|
542
|
+
labels = {},
|
|
543
|
+
seenKey = "ash-seen-views",
|
|
544
|
+
assemblerName = "Shift",
|
|
545
|
+
alwaysGenerate = false
|
|
546
|
+
}) {
|
|
547
|
+
const pathname = (0, import_navigation.usePathname)();
|
|
548
|
+
const [mounted, setMounted] = (0, import_react7.useState)(false);
|
|
549
|
+
const [showSheen, setShowSheen] = (0, import_react7.useState)(false);
|
|
550
|
+
const [seen] = (0, import_react7.useState)(() => /* @__PURE__ */ new Set());
|
|
551
|
+
function viewLabel(path) {
|
|
552
|
+
const seg = path.split("/").filter(Boolean);
|
|
553
|
+
const key = seg.find((s) => labels[s]) ?? seg[0] ?? "dashboard";
|
|
554
|
+
return labels[key] ?? key.replace(/-/g, " ");
|
|
555
|
+
}
|
|
556
|
+
(0, import_react7.useEffect)(() => {
|
|
557
|
+
try {
|
|
558
|
+
const raw = sessionStorage.getItem(seenKey);
|
|
559
|
+
if (raw) JSON.parse(raw).forEach((p) => seen.add(p));
|
|
560
|
+
} catch {
|
|
561
|
+
}
|
|
562
|
+
setMounted(true);
|
|
563
|
+
}, []);
|
|
564
|
+
const firstVisit = mounted && (alwaysGenerate || !seen.has(pathname));
|
|
565
|
+
(0, import_react7.useEffect)(() => {
|
|
566
|
+
if (!mounted) return;
|
|
567
|
+
const wasFirst = alwaysGenerate || !seen.has(pathname);
|
|
568
|
+
seen.add(pathname);
|
|
569
|
+
try {
|
|
570
|
+
sessionStorage.setItem(seenKey, JSON.stringify([...seen]));
|
|
571
|
+
} catch {
|
|
572
|
+
}
|
|
573
|
+
if (wasFirst) {
|
|
574
|
+
setShowSheen(true);
|
|
575
|
+
const t = setTimeout(() => setShowSheen(false), 900);
|
|
576
|
+
return () => clearTimeout(t);
|
|
577
|
+
}
|
|
578
|
+
setShowSheen(false);
|
|
579
|
+
}, [pathname, mounted]);
|
|
580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_framer_motion9.AnimatePresence, { mode: "wait", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
581
|
+
import_framer_motion9.motion.div,
|
|
582
|
+
{
|
|
583
|
+
initial: firstVisit ? { opacity: 0, y: 14, filter: "blur(7px)" } : { opacity: 0 },
|
|
584
|
+
animate: { opacity: 1, y: 0, filter: "blur(0px)" },
|
|
585
|
+
exit: { opacity: 0, filter: "blur(4px)", transition: { duration: 0.16 } },
|
|
586
|
+
transition: firstVisit ? { type: "spring", stiffness: 240, damping: 28 } : { duration: 0.16, ease: "easeOut" },
|
|
587
|
+
className: "relative min-h-full",
|
|
588
|
+
children: [
|
|
589
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_framer_motion9.AnimatePresence, { children: showSheen && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
590
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
591
|
+
import_framer_motion9.motion.div,
|
|
592
|
+
{
|
|
593
|
+
initial: { scaleX: 0, opacity: 0.8 },
|
|
594
|
+
animate: { scaleX: 1, opacity: 0 },
|
|
595
|
+
exit: { opacity: 0 },
|
|
596
|
+
transition: { duration: 0.9, ease: "easeOut" },
|
|
597
|
+
style: {
|
|
598
|
+
transformOrigin: "left",
|
|
599
|
+
background: "linear-gradient(90deg, transparent, var(--shift-accent), transparent)"
|
|
600
|
+
},
|
|
601
|
+
className: "pointer-events-none fixed top-0 left-0 right-0 h-0.5 z-[60]"
|
|
602
|
+
}
|
|
603
|
+
),
|
|
604
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
605
|
+
import_framer_motion9.motion.div,
|
|
606
|
+
{
|
|
607
|
+
initial: { opacity: 0, y: -6 },
|
|
608
|
+
animate: { opacity: 1, y: 0 },
|
|
609
|
+
exit: { opacity: 0, y: -6 },
|
|
610
|
+
transition: { duration: 0.25 },
|
|
611
|
+
style: {
|
|
612
|
+
borderColor: "color-mix(in srgb, var(--shift-accent) 25%, transparent)",
|
|
613
|
+
boxShadow: "0 0 24px color-mix(in srgb, var(--shift-accent) 18%, transparent)"
|
|
614
|
+
},
|
|
615
|
+
className: "ash-surface pointer-events-none fixed top-3 left-1/2 -translate-x-1/2 z-[60] flex items-center gap-1.5 rounded-full border px-3 py-1",
|
|
616
|
+
children: [
|
|
617
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react.Sparkles, { size: 10, style: { color: "var(--shift-accent)" }, className: "animate-pulse" }),
|
|
618
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "text-[10px] font-bold", style: { color: "var(--shift-accent)" }, children: [
|
|
619
|
+
assemblerName,
|
|
620
|
+
" is assembling ",
|
|
621
|
+
viewLabel(pathname),
|
|
622
|
+
"\u2026"
|
|
623
|
+
] })
|
|
624
|
+
]
|
|
625
|
+
}
|
|
626
|
+
)
|
|
627
|
+
] }) }),
|
|
628
|
+
children
|
|
629
|
+
]
|
|
630
|
+
},
|
|
631
|
+
pathname
|
|
632
|
+
) });
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// src/canvas/CanvasLauncher.tsx
|
|
636
|
+
var import_react8 = require("react");
|
|
637
|
+
var import_navigation2 = require("next/navigation");
|
|
638
|
+
var import_framer_motion10 = require("framer-motion");
|
|
639
|
+
var import_lucide_react2 = require("lucide-react");
|
|
640
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
641
|
+
function CanvasLauncher({
|
|
642
|
+
groups,
|
|
643
|
+
title = "Everything Shift can build",
|
|
644
|
+
subtitle = "Pick a resource \u2014 I'll bring it to the canvas",
|
|
645
|
+
buttonLabel = "Everything",
|
|
646
|
+
hotkey = "j",
|
|
647
|
+
openEvent = "shift:open-launcher",
|
|
648
|
+
onNavigate
|
|
649
|
+
}) {
|
|
650
|
+
const router = (0, import_navigation2.useRouter)();
|
|
651
|
+
const pathname = (0, import_navigation2.usePathname)();
|
|
652
|
+
const [open, setOpen] = (0, import_react8.useState)(false);
|
|
653
|
+
const [query, setQuery] = (0, import_react8.useState)("");
|
|
654
|
+
(0, import_react8.useEffect)(() => {
|
|
655
|
+
function onKey(e) {
|
|
656
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === hotkey) {
|
|
657
|
+
e.preventDefault();
|
|
658
|
+
setOpen((v) => !v);
|
|
659
|
+
}
|
|
660
|
+
if (e.key === "Escape") setOpen(false);
|
|
661
|
+
}
|
|
662
|
+
document.addEventListener("keydown", onKey);
|
|
663
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
664
|
+
}, [hotkey]);
|
|
665
|
+
(0, import_react8.useEffect)(() => {
|
|
666
|
+
function onOpen() {
|
|
667
|
+
setOpen(true);
|
|
668
|
+
}
|
|
669
|
+
window.addEventListener(openEvent, onOpen);
|
|
670
|
+
return () => window.removeEventListener(openEvent, onOpen);
|
|
671
|
+
}, [openEvent]);
|
|
672
|
+
const filtered = (0, import_react8.useMemo)(() => {
|
|
673
|
+
if (!query.trim()) return groups;
|
|
674
|
+
const q = query.toLowerCase();
|
|
675
|
+
return groups.map((g) => ({
|
|
676
|
+
...g,
|
|
677
|
+
items: g.items.filter((i) => i.label.toLowerCase().includes(q) || i.desc.toLowerCase().includes(q))
|
|
678
|
+
})).filter((g) => g.items.length > 0);
|
|
679
|
+
}, [query, groups]);
|
|
680
|
+
function go(href) {
|
|
681
|
+
setOpen(false);
|
|
682
|
+
setQuery("");
|
|
683
|
+
if (href === pathname) return;
|
|
684
|
+
if (onNavigate) onNavigate(href);
|
|
685
|
+
else router.push(href);
|
|
686
|
+
}
|
|
687
|
+
let flatIndex = 0;
|
|
688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
690
|
+
"button",
|
|
691
|
+
{
|
|
692
|
+
type: "button",
|
|
693
|
+
onClick: () => setOpen(true),
|
|
694
|
+
"aria-label": "Open menu",
|
|
695
|
+
title: `Everything (\u2318${hotkey.toUpperCase()})`,
|
|
696
|
+
style: { borderColor: "color-mix(in srgb, var(--shift-accent) 20%, transparent)", color: "var(--shift-accent)" },
|
|
697
|
+
className: "ash-surface flex items-center gap-2 px-2.5 py-1.5 rounded-xl border transition-all hover:brightness-110",
|
|
698
|
+
children: [
|
|
699
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.LayoutGrid, { size: 15 }),
|
|
700
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "hidden lg:inline text-xs font-bold", children: buttonLabel })
|
|
701
|
+
]
|
|
702
|
+
}
|
|
703
|
+
),
|
|
704
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_framer_motion10.AnimatePresence, { children: open && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
705
|
+
import_framer_motion10.motion.div,
|
|
706
|
+
{
|
|
707
|
+
initial: { opacity: 0 },
|
|
708
|
+
animate: { opacity: 1 },
|
|
709
|
+
exit: { opacity: 0 },
|
|
710
|
+
transition: { duration: 0.2 },
|
|
711
|
+
className: "fixed inset-0 z-[8000] flex flex-col",
|
|
712
|
+
style: { background: "rgba(2,4,10,0.86)", backdropFilter: "blur(20px)", WebkitBackdropFilter: "blur(20px)" },
|
|
713
|
+
onClick: () => setOpen(false),
|
|
714
|
+
children: [
|
|
715
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "shrink-0 px-6 pt-6 pb-4", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "max-w-6xl mx-auto", children: [
|
|
716
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
|
|
717
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
718
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
719
|
+
"div",
|
|
720
|
+
{
|
|
721
|
+
className: "w-7 h-7 rounded-full flex items-center justify-center",
|
|
722
|
+
style: { background: "linear-gradient(135deg, var(--shift-accent), var(--shift-accent-2))", boxShadow: "0 0 14px color-mix(in srgb, var(--shift-accent) 50%, transparent)" },
|
|
723
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.Sparkles, { size: 13, className: "text-white" })
|
|
724
|
+
}
|
|
725
|
+
),
|
|
726
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
|
|
727
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-sm font-black text-white leading-none", children: title }),
|
|
728
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-[11px] text-white/40 mt-1", children: subtitle })
|
|
729
|
+
] })
|
|
730
|
+
] }),
|
|
731
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", onClick: () => setOpen(false), className: "w-8 h-8 rounded-xl flex items-center justify-center text-white/40 hover:text-white hover:bg-white/[0.08] transition-all", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.X, { size: 16 }) })
|
|
732
|
+
] }),
|
|
733
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ash-surface flex items-center gap-2.5 rounded-2xl border border-white/10 px-4 py-3", children: [
|
|
734
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.Search, { size: 15, className: "text-white/30" }),
|
|
735
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
736
|
+
"input",
|
|
737
|
+
{
|
|
738
|
+
autoFocus: true,
|
|
739
|
+
value: query,
|
|
740
|
+
onChange: (e) => setQuery(e.target.value),
|
|
741
|
+
placeholder: "Search resources\u2026",
|
|
742
|
+
className: "flex-1 bg-transparent text-sm text-white placeholder:text-white/25 outline-none"
|
|
743
|
+
}
|
|
744
|
+
),
|
|
745
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("kbd", { className: "text-[10px] text-white/25 border border-white/10 rounded px-1.5 py-0.5", children: "esc" })
|
|
746
|
+
] })
|
|
747
|
+
] }) }),
|
|
748
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex-1 overflow-y-auto px-6 pb-10", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "max-w-6xl mx-auto flex flex-col gap-7", children: [
|
|
749
|
+
filtered.map((group) => {
|
|
750
|
+
const rgb = ACCENT_RGB[group.accent];
|
|
751
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
|
|
752
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1.5 mb-3", style: { color: `rgb(${rgb})` }, children: [
|
|
753
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-1.5 h-1.5 rounded-full", style: { background: `rgb(${rgb})` } }),
|
|
754
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-[11px] font-black uppercase tracking-widest", children: group.label })
|
|
755
|
+
] }),
|
|
756
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3", children: group.items.map((item) => {
|
|
757
|
+
const Icon = item.icon;
|
|
758
|
+
const isActive = pathname === item.href;
|
|
759
|
+
const idx = flatIndex++;
|
|
760
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
761
|
+
import_framer_motion10.motion.button,
|
|
762
|
+
{
|
|
763
|
+
type: "button",
|
|
764
|
+
onClick: () => go(item.href),
|
|
765
|
+
initial: { opacity: 0, y: 14, filter: "blur(5px)" },
|
|
766
|
+
animate: { opacity: 1, y: 0, filter: "blur(0px)" },
|
|
767
|
+
transition: { duration: 0.28, delay: Math.min(idx * 0.018, 0.5), ease: "easeOut" },
|
|
768
|
+
whileHover: { y: -3, scale: 1.015 },
|
|
769
|
+
style: isActive ? { borderColor: `rgba(${rgb},0.4)` } : void 0,
|
|
770
|
+
className: `ash-surface group relative text-left rounded-2xl border p-4 overflow-hidden transition-colors ${isActive ? "" : "border-white/[0.08] hover:border-white/[0.15]"}`,
|
|
771
|
+
children: [
|
|
772
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "absolute top-0 left-0 right-0 h-px opacity-60", style: { background: `rgba(${rgb},0.7)` } }),
|
|
773
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-9 h-9 rounded-xl flex items-center justify-center mb-3", style: { background: `rgba(${rgb},0.12)` }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Icon, { size: 16, style: { color: `rgb(${rgb})` } }) }),
|
|
774
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-sm font-bold text-white mb-0.5", children: item.label }),
|
|
775
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-[11px] text-white/40 leading-snug", children: item.desc }),
|
|
776
|
+
isActive && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "absolute top-3 right-3 text-[9px] font-bold", style: { color: `rgb(${rgb})` }, children: "on canvas" }),
|
|
777
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "absolute bottom-0 right-0 w-24 h-24 rounded-full blur-2xl opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none", style: { background: `rgba(${rgb},0.18)` } })
|
|
778
|
+
]
|
|
779
|
+
},
|
|
780
|
+
item.href
|
|
781
|
+
);
|
|
782
|
+
}) })
|
|
783
|
+
] }, group.label);
|
|
784
|
+
}),
|
|
785
|
+
filtered.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "text-center text-white/30 text-sm py-20", children: [
|
|
786
|
+
"No resources match \u201C",
|
|
787
|
+
query,
|
|
788
|
+
"\u201D"
|
|
789
|
+
] })
|
|
790
|
+
] }) })
|
|
791
|
+
]
|
|
792
|
+
}
|
|
793
|
+
) })
|
|
794
|
+
] });
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// src/canvas/PageTransition.tsx
|
|
798
|
+
var import_framer_motion11 = require("framer-motion");
|
|
799
|
+
var import_navigation3 = require("next/navigation");
|
|
800
|
+
var import_react9 = require("react");
|
|
801
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
802
|
+
function PageTransition({ children, className }) {
|
|
803
|
+
const pathname = (0, import_navigation3.usePathname)();
|
|
804
|
+
const depthRef = (0, import_react9.useRef)(0);
|
|
805
|
+
const dirRef = (0, import_react9.useRef)(0);
|
|
806
|
+
const depth = pathname.split("/").filter(Boolean).length;
|
|
807
|
+
if (depth !== depthRef.current) {
|
|
808
|
+
dirRef.current = dirRef.current === 0 ? 0 : depth >= depthRef.current ? 1 : -1;
|
|
809
|
+
depthRef.current = depth;
|
|
810
|
+
}
|
|
811
|
+
const dir = dirRef.current;
|
|
812
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
813
|
+
import_framer_motion11.motion.div,
|
|
814
|
+
{
|
|
815
|
+
initial: { opacity: 0, x: dir * 22, filter: "blur(3px)" },
|
|
816
|
+
animate: { opacity: 1, x: 0, filter: "blur(0px)" },
|
|
817
|
+
transition: { type: "spring", stiffness: 400, damping: 34 },
|
|
818
|
+
className: className ?? "flex flex-col flex-1 min-h-0",
|
|
819
|
+
children
|
|
820
|
+
},
|
|
821
|
+
pathname
|
|
822
|
+
);
|
|
823
|
+
}
|
|
235
824
|
// Annotate the CommonJS export names for ESM import in node:
|
|
236
825
|
0 && (module.exports = {
|
|
826
|
+
ACCENT_RGB,
|
|
827
|
+
CanvasLauncher,
|
|
828
|
+
CanvasTransition,
|
|
829
|
+
GenerativeView,
|
|
237
830
|
HolographicShine,
|
|
831
|
+
LiveCard,
|
|
832
|
+
LiveStat,
|
|
833
|
+
PageTransition,
|
|
238
834
|
ScrollGenerateCard,
|
|
239
835
|
ShiftCard,
|
|
240
|
-
TiltCard
|
|
836
|
+
TiltCard,
|
|
837
|
+
useGenerate
|
|
241
838
|
});
|