apex-ui-kit 2.1.0 → 2.1.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/ApexUI-Kit/templates/CardStack/CardStack.jsx +2 -2
- package/dist/ApexUI-Kit/templates/Cards/BasicCard.jsx +3 -3
- package/dist/ApexUI-Kit/templates/FlipProfile/FlipProfile.jsx +2 -1
- package/dist/ApexUI-Kit/templates/MeteorCard/MeteorCard.jsx +2 -2
- package/dist/ApexUI-Kit/templates/OrbsBackground/FloatingOrbs.jsx +59 -59
- package/dist/ApexUI-Kit/templates/ParallaxProfile/ParallaxProfile.jsx +1 -1
- package/dist/ApexUI-Kit/templates/SmartGridCard/SmartGridCard.jsx +10 -9
- package/package.json +1 -1
|
@@ -63,7 +63,7 @@ export default function CardStack({
|
|
|
63
63
|
return (
|
|
64
64
|
<div
|
|
65
65
|
ref={containerRef}
|
|
66
|
-
className="relative flex justify-center items-end h-[
|
|
66
|
+
className="relative flex justify-center items-end h-[27.5rem] w-full max-w-lg mx-auto pb-2"
|
|
67
67
|
onMouseEnter={() => setIsHovered(true)}
|
|
68
68
|
onMouseLeave={() => setIsHovered(false)}
|
|
69
69
|
>
|
|
@@ -78,7 +78,7 @@ export default function CardStack({
|
|
|
78
78
|
<div
|
|
79
79
|
key={idx}
|
|
80
80
|
onClick={isTop ? next : undefined}
|
|
81
|
-
className={`card-item group absolute bottom-2 left-0 right-0 mx-auto h-[
|
|
81
|
+
className={`card-item group absolute bottom-2 left-0 right-0 mx-auto h-[22.5rem] w-[17.5rem] max-w-[calc(100%-1rem)] origin-bottom overflow-hidden rounded-[1.75rem] border border-white/15 bg-slate-950 shadow-[0_24px_60px_-20px_rgba(0,0,0,0.8)] select-none ${isTop ? "cursor-pointer" : "pointer-events-none"}`}
|
|
82
82
|
style={{ opacity: 0 }}
|
|
83
83
|
>
|
|
84
84
|
{/* Full-bleed image */}
|
|
@@ -9,10 +9,10 @@ const ProfileCard = ({ title, summary, image, link }) => {
|
|
|
9
9
|
initial={{ y: 20, opacity: 0 }}
|
|
10
10
|
animate={{ y: 0, opacity: 1 }}
|
|
11
11
|
transition={{ type: "spring", stiffness: 300, damping: 20 }}
|
|
12
|
-
className="w-[
|
|
12
|
+
className="w-[17.5rem] max-w-full rounded-2xl bg-slate-950 border border-gray-800 shadow-2xl overflow-hidden p-2 shadow-lime-700/20"
|
|
13
13
|
>
|
|
14
|
-
{/* Image: fixed
|
|
15
|
-
<div className="h-[
|
|
14
|
+
{/* Image: fixed size (in rem, like the text) so the card keeps its shape on every screen */}
|
|
15
|
+
<div className="h-[12.5rem] w-full rounded-b-4xl rounded-t-lg overflow-hidden">
|
|
16
16
|
<motion.img
|
|
17
17
|
src={image}
|
|
18
18
|
alt={title}
|
|
@@ -69,7 +69,8 @@ const FlipProfile = ({
|
|
|
69
69
|
return (
|
|
70
70
|
<div className="w-full flex items-center justify-center p-4" style={{ perspective: "1200px" }}>
|
|
71
71
|
<motion.div
|
|
72
|
-
|
|
72
|
+
// Sized in rem (300×420 at a 16px root) so the card grows with its rem-based content.
|
|
73
|
+
className="relative w-[18.75rem] max-w-full h-[26.25rem] cursor-pointer"
|
|
73
74
|
style={{ transformStyle: "preserve-3d" }}
|
|
74
75
|
variants={cardVariants}
|
|
75
76
|
animate={isFlipped ? "flipped" : "initial"}
|
|
@@ -42,7 +42,7 @@ const MeteorCard = ({ data, particleNumber, particleColor, particleSpeed }) => {
|
|
|
42
42
|
return (
|
|
43
43
|
<div className="flex flex-wrap justify-center gap-6">
|
|
44
44
|
{data.map((item, index) => (
|
|
45
|
-
<div key={index} className="relative w-[
|
|
45
|
+
<div key={index} className="relative w-[20rem] max-w-full bg-slate-800/80 p-0.5 rounded-2xl moving-border-card">
|
|
46
46
|
{/* Card ka content container */}
|
|
47
47
|
<div className="relative bg-slate-900 rounded-[calc(1rem-2px)] p-3 flex flex-col overflow-hidden">
|
|
48
48
|
{/* Background Effects */}
|
|
@@ -59,7 +59,7 @@ const MeteorCard = ({ data, particleNumber, particleColor, particleSpeed }) => {
|
|
|
59
59
|
<div className="absolute -top-1/4 -left-1/4 w-3/4 h-1/2 bg-blue-400/60 rounded-full blur-[90px] pointer-events-none z-0"></div>
|
|
60
60
|
|
|
61
61
|
{/* Image */}
|
|
62
|
-
<div className="relative h-[
|
|
62
|
+
<div className="relative h-[13.75rem] w-full rounded-xl overflow-hidden z-10 ring-1 ring-white/10">
|
|
63
63
|
<img src={item.imageUrl} alt={item.title} className="w-full h-full object-cover object-[center_25%]" />
|
|
64
64
|
</div>
|
|
65
65
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/* eslint-disable no-unused-vars */
|
|
2
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import React, { useState, useEffect, useMemo, useRef } from 'react';
|
|
3
3
|
import { motion } from 'framer-motion';
|
|
4
4
|
|
|
5
5
|
// --- FloatingOrbsBackground Component (Optimized for Mobile) ---
|
|
6
|
+
// Orbs start together in the centre and drift outwards inside the container, then glide back.
|
|
6
7
|
const FloatingOrbsBackground = ({
|
|
7
8
|
children,
|
|
8
9
|
className,
|
|
@@ -11,78 +12,77 @@ const FloatingOrbsBackground = ({
|
|
|
11
12
|
desktopOrbs = 20, // Orbs for desktop
|
|
12
13
|
mobileOrbs = 10, // Orbs for mobile
|
|
13
14
|
}) => {
|
|
14
|
-
const
|
|
15
|
-
const [
|
|
15
|
+
const boxRef = useRef(null);
|
|
16
|
+
const [box, setBox] = useState({ w: 0, h: 0 });
|
|
17
|
+
const isMobile = box.w > 0 && box.w < 768;
|
|
18
|
+
const numberOfOrbs = isMobile ? mobileOrbs : desktopOrbs;
|
|
16
19
|
|
|
17
|
-
//
|
|
20
|
+
// Measure the container so the orbs roam inside it (not the whole window).
|
|
18
21
|
useEffect(() => {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// Cleanup
|
|
29
|
-
return () => window.removeEventListener('resize', checkScreenSize);
|
|
30
|
-
}, [desktopOrbs, mobileOrbs]);
|
|
22
|
+
const el = boxRef.current;
|
|
23
|
+
if (!el) return;
|
|
24
|
+
const measure = () => setBox({ w: el.offsetWidth, h: el.offsetHeight });
|
|
25
|
+
measure();
|
|
26
|
+
const ro = new ResizeObserver(measure);
|
|
27
|
+
ro.observe(el);
|
|
28
|
+
return () => ro.disconnect();
|
|
29
|
+
}, []);
|
|
31
30
|
|
|
32
31
|
const orbColors = colors ?? [
|
|
33
32
|
"#10b981", "#06b6d4", "#6366f1", "#a855f7",
|
|
34
33
|
"#d946ef", "#ec4899", "#f43f5e", "#f97316",
|
|
35
34
|
];
|
|
36
35
|
|
|
36
|
+
// Random paths are picked once per size change, so re-renders don't make the orbs jump.
|
|
37
|
+
const orbs = useMemo(() => {
|
|
38
|
+
const rangeX = box.w * 0.42;
|
|
39
|
+
const rangeY = box.h * 0.38;
|
|
40
|
+
const rand = (range) => Math.round((Math.random() * 2 - 1) * range);
|
|
41
|
+
return Array.from({ length: numberOfOrbs }, () => ({
|
|
42
|
+
size: Math.random() * 160 + (isMobile ? 90 : 130),
|
|
43
|
+
duration: Math.random() * 14 + 12,
|
|
44
|
+
x: [0, rand(rangeX), rand(rangeX), rand(rangeX)],
|
|
45
|
+
y: [0, rand(rangeY), rand(rangeY), rand(rangeY)],
|
|
46
|
+
}));
|
|
47
|
+
}, [numberOfOrbs, box.w, box.h, isMobile]);
|
|
48
|
+
|
|
37
49
|
return (
|
|
38
50
|
<div
|
|
51
|
+
ref={boxRef}
|
|
39
52
|
className={`relative h-[60vh] lg:h-[80vh] w-full flex flex-col items-center justify-center overflow-hidden bg-slate-950 ${containerClassName}`}
|
|
40
53
|
>
|
|
41
54
|
{/* Orbs Container */}
|
|
42
55
|
<div className="absolute inset-0 z-0 w-full h-full">
|
|
43
|
-
{
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
`${Math.random() * 150 - 75}vh`,
|
|
74
|
-
],
|
|
75
|
-
scale: [1, 1.2, 1],
|
|
76
|
-
}}
|
|
77
|
-
transition={{
|
|
78
|
-
duration: duration,
|
|
79
|
-
repeat: Infinity,
|
|
80
|
-
ease: 'easeInOut',
|
|
81
|
-
repeatType: 'mirror',
|
|
82
|
-
}}
|
|
83
|
-
/>
|
|
84
|
-
);
|
|
85
|
-
})}
|
|
56
|
+
{box.w > 0 && orbs.map((orb, index) => (
|
|
57
|
+
<motion.div
|
|
58
|
+
key={index}
|
|
59
|
+
className="absolute left-1/2 top-1/2 rounded-full"
|
|
60
|
+
style={{
|
|
61
|
+
width: orb.size,
|
|
62
|
+
height: orb.size,
|
|
63
|
+
marginLeft: -orb.size / 2,
|
|
64
|
+
marginTop: -orb.size / 2,
|
|
65
|
+
backgroundColor: orbColors[index % orbColors.length],
|
|
66
|
+
filter: `blur(${isMobile ? 45 : 60}px)`,
|
|
67
|
+
mixBlendMode: 'screen',
|
|
68
|
+
// Performance behtar karne ke liye browser ko hint dena
|
|
69
|
+
willChange: 'transform, opacity',
|
|
70
|
+
}}
|
|
71
|
+
initial={{ x: 0, y: 0, scale: 0.6, opacity: 0 }}
|
|
72
|
+
animate={{
|
|
73
|
+
x: orb.x,
|
|
74
|
+
y: orb.y,
|
|
75
|
+
scale: [0.8, 1.15, 0.95, 1.1],
|
|
76
|
+
opacity: [0.85, 0.7, 0.8, 0.7],
|
|
77
|
+
}}
|
|
78
|
+
transition={{
|
|
79
|
+
duration: orb.duration,
|
|
80
|
+
repeat: Infinity,
|
|
81
|
+
ease: 'easeInOut',
|
|
82
|
+
repeatType: 'mirror',
|
|
83
|
+
}}
|
|
84
|
+
/>
|
|
85
|
+
))}
|
|
86
86
|
</div>
|
|
87
87
|
|
|
88
88
|
<div className={`relative z-10 ${className}`}>
|
|
@@ -57,7 +57,7 @@ const ParallaxProfileCard = ({ profile }) => {
|
|
|
57
57
|
return (
|
|
58
58
|
<div
|
|
59
59
|
ref={cardRef}
|
|
60
|
-
className="relative w-[
|
|
60
|
+
className="relative w-[18.75rem] max-w-full bg-[#1D2B3A] rounded-3xl p-6 border border-cyan-400/30 shadow-2xl shadow-cyan-900/40"
|
|
61
61
|
style={{ transformStyle: "preserve-3d" }}
|
|
62
62
|
>
|
|
63
63
|
<div className="absolute inset-0 bg-gradient-to-br from-[#1D2B3A] to-[#0b1220] rounded-3xl"></div>
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
LaptopMinimal,
|
|
10
10
|
} from "lucide-react";
|
|
11
11
|
|
|
12
|
-
const CARD_HEIGHT =
|
|
13
|
-
const CARD_EXPANDED_HEIGHT =
|
|
12
|
+
const CARD_HEIGHT = 264;
|
|
13
|
+
const CARD_EXPANDED_HEIGHT = 2 * CARD_HEIGHT + 10; // two rows plus the grid gap
|
|
14
14
|
|
|
15
15
|
const SmartGridCard = ({
|
|
16
16
|
cards = defaultCards(),
|
|
@@ -157,20 +157,21 @@ const SmartGridCard = ({
|
|
|
157
157
|
/>
|
|
158
158
|
|
|
159
159
|
{/* Card Content */}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
<div>
|
|
163
|
-
|
|
164
|
-
<
|
|
160
|
+
{/* Compact enough that the button always fits inside the fixed card height */}
|
|
161
|
+
<div className="relative z-10 flex flex-col items-start h-full w-full p-5 rounded-2xl bg-zinc-900 text-white gap-3">
|
|
162
|
+
<div className="flex h-11 w-11 shrink-0 items-center justify-center border border-dashed rounded-lg border-purple-600">{card.icon}</div>
|
|
163
|
+
<div className="min-h-0">
|
|
164
|
+
<h3 className="text-lg font-bold mb-1.5 break-words leading-tight">{card.title}</h3>
|
|
165
|
+
<p className="text-sm leading-relaxed w-full text-white/70 break-words line-clamp-3">{card.description}</p>
|
|
165
166
|
</div>
|
|
166
167
|
<button
|
|
167
168
|
type="button"
|
|
168
|
-
className="mt-auto relative overflow-hidden whitespace-nowrap px-4 py-
|
|
169
|
+
className="mt-auto shrink-0 relative overflow-hidden whitespace-nowrap px-4 py-2 rounded-lg border border-purple-400/60 text-white transition hover:text-white bg-black/20 group flex items-center gap-2 text-sm"
|
|
169
170
|
>
|
|
170
171
|
<span className="relative z-10 flex items-center gap-2">
|
|
171
172
|
{card.buttonText}
|
|
172
173
|
<span className="arrow-icon transition-transform duration-200 group-hover:translate-x-2 flex items-center">
|
|
173
|
-
<svg width="
|
|
174
|
+
<svg width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24">
|
|
174
175
|
<path d="M5 12h14M13 6l6 6-6 6" />
|
|
175
176
|
</svg>
|
|
176
177
|
</span>
|