apex-ui-kit 2.0.7 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/ApexUI-Kit/templates/AccordionMarquee/AccordionMarquee.jsx +74 -53
  2. package/dist/ApexUI-Kit/templates/BeamBar/BeamBar.jsx +5 -3
  3. package/dist/ApexUI-Kit/templates/BluePrintBackground/BluePrintBackground.jsx +14 -2
  4. package/dist/ApexUI-Kit/templates/CardStack/CardStack.jsx +56 -28
  5. package/dist/ApexUI-Kit/templates/Cards/BasicCard.jsx +3 -3
  6. package/dist/ApexUI-Kit/templates/DragCarousel/DragCarousel.jsx +1 -1
  7. package/dist/ApexUI-Kit/templates/EdgeGlowForm/EdgeGlowFrom.jsx +116 -98
  8. package/dist/ApexUI-Kit/templates/FlipProfile/FlipProfile.jsx +69 -37
  9. package/dist/ApexUI-Kit/templates/GlareCard/GlareCard.jsx +2 -2
  10. package/dist/ApexUI-Kit/templates/HoverText/HoverText.jsx +14 -13
  11. package/dist/ApexUI-Kit/templates/HyperCard/HyperCard.jsx +59 -42
  12. package/dist/ApexUI-Kit/templates/KineticThreadsBackground/KineticThreadBackground.jsx +17 -2
  13. package/dist/ApexUI-Kit/templates/LensFlareBackground/LensFlareBackground.jsx +18 -3
  14. package/dist/ApexUI-Kit/templates/LuminousParticleOcean/LuminousParticleOcean.jsx +15 -1
  15. package/dist/ApexUI-Kit/templates/MaskView/MaskView.jsx +345 -0
  16. package/dist/ApexUI-Kit/templates/MeteorCard/MeteorCard.jsx +34 -45
  17. package/dist/ApexUI-Kit/templates/NavDropDown/NavDropDown.jsx +272 -101
  18. package/dist/ApexUI-Kit/templates/NavMenu/NavMenu.jsx +8 -2
  19. package/dist/ApexUI-Kit/templates/ParallaxCard/ParallaxCard.jsx +13 -11
  20. package/dist/ApexUI-Kit/templates/ParallaxCarousel/ParallaxCarousel.jsx +9 -9
  21. package/dist/ApexUI-Kit/templates/ParallaxProfile/ParallaxProfile.jsx +41 -38
  22. package/dist/ApexUI-Kit/templates/PointerFollower/PointerFollower.jsx +7 -7
  23. package/dist/ApexUI-Kit/templates/SmartGridCard/SmartGridCard.jsx +4 -3
  24. package/dist/ApexUI-Kit/templates/SmokeBackground/SmokeBackground.jsx +13 -2
  25. package/dist/ApexUI-Kit/templates/Testimonials/Testimonials.jsx +11 -8
  26. package/dist/ApexUI-Kit/templates/ThemeToggle/ThemeAnimation.js +40 -69
  27. package/dist/ApexUI-Kit/templates/ThemeToggle/ThemeToggle.css +1 -1
  28. package/dist/ApexUI-Kit/templates/ThemeToggle/ThemeToggle.jsx +25 -7
  29. package/dist/ApexUI-Kit/templates/ToolTip/ToolTip.jsx +71 -52
  30. package/dist/cli/index.js +24 -13
  31. package/package.json +2 -2
  32. package/dist/ApexUI-Kit/templates/WaterDropReveal/WaterDropReveal.jsx +0 -151
@@ -2,12 +2,15 @@ import React, { useRef, useState, useEffect } from 'react';
2
2
  import gsap from 'gsap';
3
3
 
4
4
  const fields = [
5
- { name: 'firstName', label: 'First Name', type: 'text' },
6
- { name: 'lastName', label: 'Last Name', type: 'text' },
5
+ { name: 'firstName', label: 'First Name', type: 'text', half: true },
6
+ { name: 'lastName', label: 'Last Name', type: 'text', half: true },
7
7
  { name: 'email', label: 'Email Address', type: 'email' },
8
8
  { name: 'mobile', label: 'Mobile Number', type: 'tel' },
9
9
  ];
10
10
 
11
+ // '#a78bfa88' + 'cc' -> '#a78bfacc'; works for #rrggbb and #rrggbbaa colours.
12
+ const withAlpha = (hex, alpha) => `${hex.slice(0, 7)}${alpha}`;
13
+
11
14
  const EdgeGlowForm = ({
12
15
  GlowColor = 'violet',
13
16
  borderGlowColor = '#a78bfa88',
@@ -24,49 +27,51 @@ const EdgeGlowForm = ({
24
27
  const ballsRef = [useRef(), useRef(), useRef()];
25
28
  const checkTick = useRef();
26
29
 
27
- // Mouse movement for glassy background
30
+ // Edge glow that follows the pointer (mouse, pen or touch)
28
31
  const [radialPos, setRadialPos] = useState({ x: 50, y: 50 });
32
+ const [glowing, setGlowing] = useState(false);
29
33
  const bgRef = useRef();
30
34
 
31
- const handleBgMouseMove = e => {
35
+ const edgeColor = withAlpha(borderGlowColor, '');
36
+
37
+ const handlePointerMove = e => {
32
38
  if (!bgRef.current) return;
33
39
  const rect = bgRef.current.getBoundingClientRect();
34
40
  const x = ((e.clientX - rect.left) / rect.width) * 100;
35
41
  const y = ((e.clientY - rect.top) / rect.height) * 100;
36
42
  setRadialPos({ x, y });
43
+ setGlowing(true);
37
44
  };
38
- const handleBgMouseLeave = () => {
45
+ const handlePointerLeave = () => {
39
46
  setRadialPos({ x: 50, y: 50 });
47
+ setGlowing(false);
40
48
  };
41
49
 
42
50
  const floatLabel = (name, up, color = null) => {
43
51
  const label = labelRefs.current[name];
44
52
  if (label) {
45
53
  gsap.to(label, {
46
- top: up ? '-2px' : '23%',
47
- left: '5px',
48
- scale: up ? 0.85 : 1,
49
- color: color ?? (up ? '#a78bfa' : '#bdbdbd'),
50
- transform: 'translateY(-4%)',
54
+ top: up ? '6px' : '50%',
55
+ yPercent: up ? 0 : -50,
56
+ scale: up ? 0.78 : 1,
57
+ color: color ?? (up ? edgeColor : '#a1a1aa'),
51
58
  fontWeight: up ? 500 : 400,
52
59
  duration: 0.2,
53
- ease: 'easeInOut',
54
- zIndex: 10,
60
+ ease: 'power2.out',
55
61
  });
56
62
  }
57
63
  };
58
64
 
59
- const showBorder = (name, show, color = '#a78bfa88') => {
60
- const [top, bottom] = borderRefs.current[name] || [];
61
- [top, bottom].forEach(border => {
65
+ const showBorder = (name, show, color = borderGlowColor) => {
66
+ (borderRefs.current[name] || []).forEach(border => {
62
67
  if (border) {
63
68
  gsap.to(border, {
64
69
  opacity: show ? 1 : 0,
65
- scaleX: show ? 1 : 0.7,
70
+ scaleX: show ? 1 : 0.6,
66
71
  background: `linear-gradient(90deg, transparent 0%, ${color} 50%, transparent 100%)`,
67
- boxShadow: `0 0 8px 0 ${color.replace('88', '33')}`,
68
- duration: 0.2,
69
- ease: show ? 'ease.out' : 'ease.in',
72
+ boxShadow: `0 0 10px 1px ${color === borderGlowColor ? borderGlowShadow : withAlpha(color, '44')}`,
73
+ duration: 0.25,
74
+ ease: show ? 'power2.out' : 'power2.in',
70
75
  });
71
76
  }
72
77
  });
@@ -87,31 +92,34 @@ const EdgeGlowForm = ({
87
92
  const handleChange = (e, name) => {
88
93
  const v = e.target.value;
89
94
  setValues(vals => ({ ...vals, [name]: v }));
95
+ if (errors[name] && v) setErrors(errs => ({ ...errs, [name]: false }));
90
96
  if (v) floatLabel(name, true);
91
97
  else if (focused !== name) floatLabel(name, false);
92
98
  };
93
99
 
94
100
  useEffect(() => {
95
101
  fields.forEach(f => {
96
- const [top, bottom] = borderRefs.current[f.name] || [];
97
- if (top) gsap.set(top, { opacity: 0, scaleX: 0.7 });
98
- if (bottom) gsap.set(bottom, { opacity: 0, scaleX: 0.7 });
102
+ (borderRefs.current[f.name] || []).forEach(border => border && gsap.set(border, { opacity: 0, scaleX: 0.6 }));
99
103
  if (labelRefs.current[f.name]) gsap.set(labelRefs.current[f.name], {
100
- top: '23%',
101
- left: '5px',
104
+ top: '50%',
105
+ yPercent: -50,
102
106
  scale: 1,
103
- color: '#bdbdbd',
104
- transform: 'translateY(-4%)',
105
- fontWeight: 400,
106
- position: 'absolute',
107
- pointerEvents: 'none',
108
- backgroundColor: '',
109
- padding: '0 4px',
110
- zIndex: 10,
107
+ color: '#a1a1aa',
108
+ transformOrigin: 'left center',
111
109
  });
112
110
  });
113
111
  }, []);
114
112
 
113
+ // Re-colour open borders and labels when the edge colour prop changes.
114
+ useEffect(() => {
115
+ fields.forEach(f => {
116
+ const up = focused === f.name || values[f.name];
117
+ if (up && !errors[f.name]) floatLabel(f.name, true);
118
+ if (focused === f.name) showBorder(f.name, true);
119
+ });
120
+ // eslint-disable-next-line react-hooks/exhaustive-deps
121
+ }, [borderGlowColor, borderGlowShadow]);
122
+
115
123
  const handleCheckbox = () => {
116
124
  setChecked(v => {
117
125
  const next = !v;
@@ -152,7 +160,7 @@ const EdgeGlowForm = ({
152
160
  setBtnState('loading');
153
161
  ballsRef.forEach((ref, i) => {
154
162
  gsap.fromTo(ref.current, { y: 0 }, {
155
- y: -12,
163
+ y: -10,
156
164
  repeat: -1,
157
165
  yoyo: true,
158
166
  delay: i * 0.12,
@@ -162,57 +170,76 @@ const EdgeGlowForm = ({
162
170
  });
163
171
  setTimeout(() => {
164
172
  setBtnState('success');
165
- ballsRef.forEach(ref => gsap.set(ref.current, { y: 0 }));
173
+ ballsRef.forEach(ref => {
174
+ gsap.killTweensOf(ref.current);
175
+ gsap.set(ref.current, { y: 0 });
176
+ });
166
177
  setTimeout(() => {
167
178
  setBtnState('default');
168
179
  }, 1200);
169
180
  }, 1600);
170
181
  };
171
182
 
172
- return (
183
+ const glow = `radial-gradient(circle at ${radialPos.x}% ${radialPos.y}%, ${GlowColor} 0%, transparent 55%)`;
173
184
 
174
- <div className=" rounded-xl w-full">
185
+ return (
186
+ <div className="w-full">
175
187
  <div
176
- className="w-full max-w-sm mx-auto rounded-xl shadow-2xl p-1 flex flex-col justify-center text-white relative overflow-hidden"
188
+ className="relative w-full max-w-sm mx-auto rounded-[1.4rem] p-[2px] text-white touch-pan-y"
177
189
  ref={bgRef}
178
- onMouseMove={handleBgMouseMove}
179
- onMouseLeave={handleBgMouseLeave}
190
+ onPointerMove={handlePointerMove}
191
+ onPointerLeave={handlePointerLeave}
180
192
  >
181
- {/* 🎯 Glassy Background */}
182
- <div className="absolute inset-0 z-0 hidden md:block pointer-events-none rounded-xl">
193
+ {/* Soft halo outside the card */}
194
+ <div
195
+ className="pointer-events-none absolute -inset-3 rounded-[2rem] blur-2xl transition-opacity duration-500"
196
+ style={{ background: glow, opacity: glowing ? 0.55 : 0.25 }}
197
+ />
198
+ {/* 🎯 Edge glow: the gradient only shows through the 2px edge around the panel */}
199
+ <div
200
+ className="pointer-events-none absolute inset-0 rounded-[1.4rem]"
201
+ style={{ background: `${glow}, linear-gradient(rgba(255,255,255,0.08), rgba(255,255,255,0.08))` }}
202
+ />
203
+
204
+ <div className="relative z-10 rounded-[calc(1.4rem-2px)] bg-[#0a0a0f] px-5 py-6 sm:px-7 sm:py-7 overflow-hidden">
205
+ {/* faint dotted texture */}
183
206
  <div
184
- className="absolute inset-0 opacity-95"
185
- style={{
186
- background: `radial-gradient(circle at ${radialPos.x}% ${radialPos.y}%, ${GlowColor} 10%, transparent 60%)`
187
- }}
188
- ></div>
189
- </div>
190
- <div className={`relative z-10 bg-black h-full w-full p-6 border border-purple-600 rounded-xl`}>
191
- <h2 className="text-2xl font-bold mb-6 flex items-center gap-2">
192
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" className="w-6 h-6 text-purple-400">
193
- <path strokeLinecap="round" strokeLinejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25H4.5a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5H4.5a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-.659 1.591l-7.5 7.5a2.25 2.25 0 01-3.182 0l-7.5-7.5A2.25 2.25 0 012.25 6.993V6.75" />
194
- </svg>
195
- Get In Touch
196
- </h2>
197
- <form className="space-y-6 w-full" onSubmit={handleBtnClick}>
207
+ className="pointer-events-none absolute inset-0 opacity-[0.07]"
208
+ style={{ backgroundImage: 'radial-gradient(rgba(255,255,255,0.9) 1px, transparent 1px)', backgroundSize: '14px 14px' }}
209
+ />
210
+
211
+ <div className="relative mb-6 flex items-start gap-3">
212
+ <span
213
+ className="flex h-11 w-11 shrink-0 items-center justify-center rounded-xl border border-white/10"
214
+ style={{ background: `linear-gradient(135deg, ${withAlpha(borderGlowColor, '40')}, transparent)`, color: edgeColor }}
215
+ >
216
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.6" stroke="currentColor" className="h-5 w-5">
217
+ <path strokeLinecap="round" strokeLinejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25H4.5a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5H4.5a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-.659 1.591l-7.5 7.5a2.25 2.25 0 01-3.182 0l-7.5-7.5A2.25 2.25 0 012.25 6.993V6.75" />
218
+ </svg>
219
+ </span>
220
+ <div>
221
+ <h2 className="text-xl font-semibold tracking-tight">Get in touch</h2>
222
+ <p className="mt-0.5 text-[0.8rem] text-zinc-400">We usually reply within a day.</p>
223
+ </div>
224
+ </div>
225
+
226
+ <form className="relative grid grid-cols-2 gap-3" onSubmit={handleBtnClick} noValidate>
198
227
  {fields.map(f => (
199
- <div key={f.name} className="relative flex flex-col justify-center">
228
+ <div key={f.name} className={`relative ${f.half ? 'col-span-2 sm:col-span-1' : 'col-span-2'}`}>
200
229
  <label
201
230
  ref={el => (labelRefs.current[f.name] = el)}
202
- className="absolute text-white/60 text-sm transition-all pointer-events-none"
231
+ htmlFor={`edge-glow-${f.name}`}
232
+ className="pointer-events-none absolute left-3.5 z-10 whitespace-nowrap text-sm"
203
233
  >{f.label}</label>
204
234
  <span
205
235
  ref={el => {
206
236
  if (!borderRefs.current[f.name]) borderRefs.current[f.name] = [];
207
237
  borderRefs.current[f.name][0] = el;
208
238
  }}
209
- className="pointer-events-none absolute left-1/2 -translate-x-1/2 top-0 w-[80%] h-[2px] rounded-full opacity-0 scale-x-70 origin-center z-20"
210
- style={{
211
- background: `linear-gradient(90deg, transparent 0%, yellow 20%, transparent 100%)`,
212
- boxShadow: `0 0 8px 0 ${borderGlowShadow}`,
213
- }}
239
+ className="pointer-events-none absolute left-1/2 top-0 z-20 h-[1.5px] w-[80%] -translate-x-1/2 rounded-full opacity-0"
214
240
  />
215
241
  <input
242
+ id={`edge-glow-${f.name}`}
216
243
  type={f.type}
217
244
  name={f.name}
218
245
  value={values[f.name]}
@@ -220,78 +247,69 @@ const EdgeGlowForm = ({
220
247
  onFocus={() => handleFocus(f.name)}
221
248
  onBlur={() => handleBlur(f.name)}
222
249
  autoComplete="off"
223
- className={`w-full px-4 pt-5 pb-2 rounded-lg bg-white/10 border ${errors[f.name] ? 'border-red-400' : 'border-white/20'} text-sm text-white focus:outline-none backdrop-blur-md transition font-light`}
250
+ className={`h-[3.25rem] w-full rounded-xl border bg-white/[0.04] px-3.5 pt-4 text-sm text-white transition-colors focus:bg-white/[0.06] focus:outline-none ${errors[f.name] ? 'border-red-400/70' : 'border-white/10 hover:border-white/20'}`}
224
251
  />
225
252
  <span
226
253
  ref={el => {
227
254
  if (!borderRefs.current[f.name]) borderRefs.current[f.name] = [];
228
255
  borderRefs.current[f.name][1] = el;
229
256
  }}
230
- className="pointer-events-none absolute left-1/2 -translate-x-1/2 bottom-0 w-[80%] h-[2px] rounded-full opacity-0 scale-x-70 origin-center"
231
- style={{
232
- background: `linear-gradient(90deg, transparent 0%, ${borderGlowColor} 20%, transparent 100%)`,
233
- boxShadow: `0 0 8px 0 ${borderGlowShadow}`,
234
- }}
257
+ className="pointer-events-none absolute bottom-0 left-1/2 h-[1.5px] w-[80%] -translate-x-1/2 rounded-full opacity-0"
235
258
  />
236
259
  </div>
237
260
  ))}
238
261
 
239
- <div className="flex items-center gap-3 mt-2 select-none relative">
262
+ <div className="relative col-span-2 mt-1 flex select-none items-center gap-3">
240
263
  <button
241
264
  type="button"
265
+ role="checkbox"
242
266
  aria-checked={checked}
243
- tabIndex={0}
267
+ aria-label="I agree to the terms"
244
268
  onClick={handleCheckbox}
245
- className={`relative w-6 h-6 rounded-md border-2 border-white/30 bg-white/10 flex items-center justify-center focus:outline-none focus:ring-2 focus:ring-purple-400 transition`}
246
- style={{ minWidth: 24 }}
269
+ className="relative flex h-5 w-5 min-w-5 items-center justify-center rounded-md border border-white/25 bg-white/5 transition focus:outline-none focus-visible:ring-2"
270
+ style={{ borderColor: checked ? edgeColor : undefined, '--tw-ring-color': edgeColor }}
247
271
  >
248
- <svg
249
- ref={checkTick}
250
- width="18" height="18" viewBox="0 0 18 18"
251
- className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-purple-400"
252
- style={{ scale: checked ? 1 : 0, opacity: checked ? 1 : 0, transition: 'all 0.2s' }}
253
- >
254
- <polyline points="3,10 7,14 15,6" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
272
+ <svg ref={checkTick} width="14" height="14" viewBox="0 0 18 18" style={{ color: edgeColor }}>
273
+ <polyline points="3,10 7,14 15,6" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round" />
255
274
  </svg>
256
275
  </button>
257
- <span className="text-white/80 text-sm">I agree to the terms</span>
276
+ <span className="text-sm text-zinc-400">I agree to the <span className="text-zinc-200 underline decoration-white/20 underline-offset-2">terms</span></span>
258
277
  {checkboxError && (
259
- <div className="absolute -left-0 -top-10 flex flex-col items-center " style={{ zIndex: 999 }}>
260
- <div className="bg-red-500 text-white text-xs rounded px-3 py-1 shadow-lg font-medium">check this box</div>
261
- <div className="w-3 h-3 bg-red-500 rotate-135 -mt-1" style={{ clipPath: 'polygon(0 0, 100% 0, 100% 100%)' }}></div>
278
+ <div className="absolute -top-9 left-0 z-50 flex flex-col items-start">
279
+ <div className="rounded-md bg-red-500 px-2.5 py-1 text-xs font-medium text-white shadow-lg">Please accept the terms</div>
280
+ <div className="ml-1.5 -mt-1 h-2.5 w-2.5 rotate-45 bg-red-500" />
262
281
  </div>
263
282
  )}
264
283
  </div>
284
+
265
285
  {/* Animated Submit Button */}
266
286
  <button
267
287
  type="submit"
268
- className="mt-6 py-3 px-6 bg-gradient-to-r from-purple-700 via-purple-500 to-indigo-800 rounded-md hover:brightness-110 transition shadow-lg w-full font-semibold text-base flex items-center justify-center gap-2 relative overflow-hidden"
269
- style={{ minHeight: 48 }}
270
- onClick={handleBtnClick}
288
+ className="relative col-span-2 mt-3 flex min-h-12 w-full items-center justify-center overflow-hidden rounded-xl text-sm font-semibold text-white shadow-lg transition hover:brightness-110 active:scale-[0.99]"
289
+ style={{ background: `linear-gradient(110deg, ${GlowColor}, ${edgeColor})`, boxShadow: `0 10px 30px -12px ${edgeColor}` }}
271
290
  disabled={btnState !== 'default'}
272
291
  >
273
292
  {/* Bouncing Balls */}
274
- <span className={`absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 flex gap-1 ${btnState === 'loading' ? 'opacity-100' : 'opacity-0'}`} style={{ transition: 'opacity 0.2s' }}>
275
- <span ref={ballsRef[0]} className="w-2.5 h-2.5 rounded-full bg-white/80 inline-block" />
276
- <span ref={ballsRef[1]} className="w-2.5 h-2.5 rounded-full bg-white/80 inline-block" />
277
- <span ref={ballsRef[2]} className="w-2.5 h-2.5 rounded-full bg-white/80 inline-block" />
293
+ <span className={`absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 gap-1 transition-opacity duration-200 ${btnState === 'loading' ? 'opacity-100' : 'opacity-0'}`}>
294
+ <span ref={ballsRef[0]} className="inline-block h-2 w-2 rounded-full bg-white/90" />
295
+ <span ref={ballsRef[1]} className="inline-block h-2 w-2 rounded-full bg-white/90" />
296
+ <span ref={ballsRef[2]} className="inline-block h-2 w-2 rounded-full bg-white/90" />
278
297
  </span>
279
298
  {/* Checkmark */}
280
- <span
281
- className={`absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-2xl text-green-400 ${btnState === 'success' ? 'opacity-100' : 'opacity-0'}`}
282
- style={{ transition: 'opacity 0.2s' }}
283
- >
284
- <svg width="24" height="24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M5 13l4 4L19 7" /></svg>
299
+ <span className={`absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 transition-opacity duration-200 ${btnState === 'success' ? 'opacity-100' : 'opacity-0'}`}>
300
+ <svg width="22" height="22" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M5 13l4 4L19 7" /></svg>
285
301
  </span>
286
302
  {/* Default text */}
287
- <span className={`transition-opacity duration-200 ${btnState === 'default' ? 'opacity-100' : 'opacity-0'}`}>Send Message</span>
303
+ <span className={`flex items-center gap-2 transition-opacity duration-200 ${btnState === 'default' ? 'opacity-100' : 'opacity-0'}`}>
304
+ Send Message
305
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6" /></svg>
306
+ </span>
288
307
  </button>
289
308
  </form>
290
309
  </div>
291
310
  </div>
292
311
  </div>
293
-
294
312
  );
295
- }
313
+ };
296
314
 
297
315
  export default EdgeGlowForm;
@@ -20,17 +20,21 @@ const TwitterIcon = () => (
20
20
  );
21
21
 
22
22
 
23
+ const ACCENT = "#B0DC3C";
24
+ const stop = (e) => e.stopPropagation();
25
+ const socialBtn = "flex h-10 w-10 items-center justify-center rounded-xl border border-white/10 bg-white/[0.04] text-white/70 transition-colors hover:border-[#B0DC3C]/50 hover:text-[#B0DC3C]";
26
+
23
27
  const FlipProfile = ({
24
28
  name = "Iron Man",
25
29
  role = "AI Engineer",
26
30
  dob = "5th March, 1999",
27
- avatar = "/assets/ironman.png",
31
+ avatar = "https://ik.imagekit.io/ny6yinyut/apexui/assets/ironman.png?tr=f-auto,q-80,w-480",
28
32
  github = "#",
29
33
  linkedin = "#",
30
34
  twitter = "#",
31
35
  resumeLink = "/Iron-Man-Resume.pdf",
32
36
  hireLink = "#",
33
- bgColor = "#0F172B"
37
+ bgColor = "#0F172B"
34
38
  }) => {
35
39
  const [isFlipped, setIsFlipped] = useState(false);
36
40
 
@@ -44,19 +48,28 @@ const FlipProfile = ({
44
48
  hidden: { opacity: 0 },
45
49
  visible: {
46
50
  opacity: 1,
47
- transition: { staggerChildren: 0.1, delayChildren: 0.3 }
51
+ transition: { staggerChildren: 0.08, delayChildren: 0.3 }
48
52
  }
49
53
  };
50
54
 
51
55
  const itemVariants = {
52
- hidden: { opacity: 0, y: 20 },
56
+ hidden: { opacity: 0, y: 16 },
53
57
  visible: { opacity: 1, y: 0 }
54
58
  };
55
59
 
60
+ // Shared face styles: accent glow at the top and a faint grid
61
+ const faceStyle = {
62
+ backgroundColor: bgColor,
63
+ backgroundImage: `radial-gradient(120% 60% at 50% 0%, ${ACCENT}26, transparent 60%), linear-gradient(rgba(255,255,255,0.035) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.035) 1px, transparent 1px)`,
64
+ backgroundSize: "auto, 22px 22px, 22px 22px",
65
+ backfaceVisibility: "hidden",
66
+ WebkitBackfaceVisibility: "hidden",
67
+ };
68
+
56
69
  return (
57
- <div className="w-full flex items-center justify-center p-4 min-h-[450px]" style={{ perspective: "1200px" }}>
70
+ <div className="w-full flex items-center justify-center p-4" style={{ perspective: "1200px" }}>
58
71
  <motion.div
59
- className="relative w-full max-w-sm h-[420px] cursor-pointer"
72
+ className="relative w-[300px] max-w-full h-[420px] cursor-pointer"
60
73
  style={{ transformStyle: "preserve-3d" }}
61
74
  variants={cardVariants}
62
75
  animate={isFlipped ? "flipped" : "initial"}
@@ -64,62 +77,81 @@ const FlipProfile = ({
64
77
  onClick={() => setIsFlipped(!isFlipped)}
65
78
  >
66
79
  {/* --- FRONT OF THE CARD --- */}
67
- <motion.div
68
- className="absolute w-full h-full rounded-3xl overflow-hidden shadow-2xl border border-[#B0DC3C] backdrop-blur-md flex flex-col items-center justify-center p-6 text-center text-white"
69
- style={{
70
- background: bgColor,
71
- backfaceVisibility: "hidden"
72
- }}
80
+ <div
81
+ className="absolute inset-0 rounded-[1.75rem] overflow-hidden border border-white/10 shadow-2xl shadow-black/50 flex flex-col items-center p-6 text-center text-white"
82
+ style={faceStyle}
73
83
  >
74
- <div className="absolute inset-0 w-full h-full border-2 border-[#B0DC3C] rounded-3xl animate-pulse pointer-events-none opacity-30"></div>
75
- <img src={avatar} alt="Avatar" className="w-32 h-32 rounded-full border-4 border-[#B0DC3C] object-cover shadow-lg shadow-fuchsia-900/50 mb-4" />
76
- <h2 className="text-3xl font-bold bg-gradient-to-r from-gray-500 to-white bg-clip-text text-transparent">{name}</h2>
77
- <p className="text-lg font-medium text-green-200/90">{role}</p>
78
- <p className="mt-4 text-xs text-gray-100">Click to flip</p>
79
- </motion.div>
84
+ <div className="flex w-full items-center justify-between">
85
+ <span className="rounded-full border border-[#B0DC3C]/30 bg-[#B0DC3C]/10 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.16em] text-[#B0DC3C]">Profile</span>
86
+ <span className="flex h-8 w-8 items-center justify-center rounded-full border border-white/10 bg-white/5 text-white/60" aria-hidden="true">
87
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12a9 9 0 1 1-3-6.7L21 8" /><path d="M21 3v5h-5" /></svg>
88
+ </span>
89
+ </div>
90
+
91
+ {/* Avatar with a slowly spinning accent ring */}
92
+ <div className="relative mt-6 h-36 w-36">
93
+ <div className="absolute inset-0 rounded-full animate-[spin_6s_linear_infinite]" style={{ background: `conic-gradient(from 0deg, ${ACCENT}, transparent 35%, ${ACCENT}55 60%, transparent 80%, ${ACCENT})` }} />
94
+ <div className="absolute inset-[3px] rounded-full" style={{ backgroundColor: bgColor }} />
95
+ <img src={avatar} alt={name} className="absolute inset-[7px] h-[calc(100%-14px)] w-[calc(100%-14px)] rounded-full object-cover" />
96
+ </div>
97
+
98
+ <h2 className="mt-5 text-3xl font-bold tracking-tight">{name}</h2>
99
+ <p className="mt-1.5 rounded-full bg-white/5 px-3 py-1 text-sm font-medium text-[#B0DC3C]">{role}</p>
100
+
101
+ <p className="mt-auto flex items-center gap-1.5 text-xs text-white/50">
102
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M9 11V6a3 3 0 0 1 6 0v8" /><path d="M5 15a7 7 0 0 0 14 0v-1a2 2 0 0 0-4 0" /></svg>
103
+ Tap to flip
104
+ </p>
105
+ </div>
80
106
 
81
107
  {/* --- BACK OF THE CARD --- */}
82
- <motion.div
83
- className="absolute w-full h-full rounded-3xl overflow-hidden shadow-2xl border border-cyan-500/40 backdrop-blur-md flex flex-col items-center justify-center p-6 text-center text-white"
84
- style={{
85
- background: bgColor,
86
- backfaceVisibility: "hidden",
87
- transform: "rotateY(180deg)"
88
- }}
108
+ <div
109
+ className="absolute inset-0 rounded-[1.75rem] overflow-hidden border border-[#B0DC3C]/30 shadow-2xl shadow-black/50 p-6 text-white"
110
+ style={{ ...faceStyle, transform: "rotateY(180deg)" }}
89
111
  >
90
112
  <AnimatePresence>
91
113
  {isFlipped && (
92
114
  <motion.div
93
- className="flex flex-col items-center justify-center w-full h-full"
115
+ className="flex h-full w-full flex-col"
94
116
  variants={backContentVariants}
95
117
  initial="hidden"
96
118
  animate="visible"
97
119
  exit="hidden"
98
120
  >
99
- <motion.p variants={itemVariants} className="text-sm text-cyan-300">DOB: {dob}</motion.p>
100
- <motion.div variants={itemVariants} className="w-1/2 h-px bg-cyan-400/30 my-4" />
121
+ <motion.div variants={itemVariants} className="flex items-center gap-3">
122
+ <img src={avatar} alt="" className="h-12 w-12 rounded-full border-2 border-[#B0DC3C] object-cover" />
123
+ <div className="min-w-0 text-left">
124
+ <p className="truncate text-lg font-bold leading-tight">{name}</p>
125
+ <p className="truncate text-xs text-[#B0DC3C]">{role}</p>
126
+ </div>
127
+ </motion.div>
128
+
129
+ <motion.div variants={itemVariants} className="mt-5 rounded-2xl border border-white/10 bg-white/[0.04] p-4 text-left">
130
+ <p className="text-[10px] font-semibold uppercase tracking-[0.16em] text-white/40">Born</p>
131
+ <p className="mt-1 text-sm font-medium text-white/90">{dob}</p>
132
+ </motion.div>
101
133
 
102
- <motion.div variants={itemVariants} className="flex gap-5 items-center justify-center text-cyan-300">
103
- <a href={github} target="_blank" rel="noopener noreferrer" className="hover:text-white transition-colors"><GitHubIcon /></a>
104
- <a href={linkedin} target="_blank" rel="noopener noreferrer" className="hover:text-white transition-colors"><LinkedInIcon /></a>
105
- <a href={twitter} target="_blank" rel="noopener noreferrer" className="hover:text-white transition-colors"><TwitterIcon /></a>
134
+ <motion.div variants={itemVariants} className="mt-4 flex items-center gap-2.5">
135
+ <a href={github} target="_blank" rel="noopener noreferrer" onClick={stop} aria-label="GitHub" className={socialBtn}><GitHubIcon /></a>
136
+ <a href={linkedin} target="_blank" rel="noopener noreferrer" onClick={stop} aria-label="LinkedIn" className={socialBtn}><LinkedInIcon /></a>
137
+ <a href={twitter} target="_blank" rel="noopener noreferrer" onClick={stop} aria-label="X (Twitter)" className={socialBtn}><TwitterIcon /></a>
106
138
  </motion.div>
107
139
 
108
- <motion.div variants={itemVariants} className="mt-6 flex flex-col gap-3 w-full items-center">
109
- <motion.a whileTap={{ scale: 0.95 }} href={hireLink} className="w-full max-w-xs text-center px-6 py-2.5 bg-cyan-600/80 hover:bg-cyan-500 text-white rounded-full font-semibold shadow-lg shadow-cyan-900/40 transition-all">
140
+ <motion.div variants={itemVariants} className="mt-auto flex flex-col gap-2.5">
141
+ <motion.a whileTap={{ scale: 0.97 }} href={hireLink} onClick={stop} className="w-full rounded-xl bg-[#B0DC3C] py-2.5 text-center text-sm font-bold text-slate-950 transition hover:brightness-110">
110
142
  Hire Me
111
143
  </motion.a>
112
- <motion.a whileTap={{ scale: 0.95 }} href={resumeLink} download className="w-full max-w-xs text-center px-6 py-2.5 bg-white/10 hover:bg-white/20 text-white rounded-full font-semibold backdrop-blur-md transition-all">
144
+ <motion.a whileTap={{ scale: 0.97 }} href={resumeLink} download onClick={stop} className="w-full rounded-xl border border-white/15 bg-white/5 py-2.5 text-center text-sm font-semibold text-white transition hover:bg-white/10">
113
145
  Download CV
114
146
  </motion.a>
115
147
  </motion.div>
116
148
  </motion.div>
117
149
  )}
118
150
  </AnimatePresence>
119
- </motion.div>
151
+ </div>
120
152
  </motion.div>
121
153
  </div>
122
154
  );
123
155
  };
124
156
 
125
- export default FlipProfile;
157
+ export default FlipProfile;
@@ -5,7 +5,7 @@ function cn(...classes) {
5
5
  }
6
6
  import React, { useRef } from "react";
7
7
  import { motion, useMotionValue, useSpring, useMotionTemplate } from "framer-motion";
8
- import bgHexa from '/assets/bg-hexa.jpg'
8
+ const bgHexa = 'https://ik.imagekit.io/ny6yinyut/apexui/assets/bg-hexa.jpg?tr=f-auto,q-80';
9
9
  export default function GlareCardDemo() {
10
10
  return (
11
11
  <GlareCard className="flex flex-col items-center justify-center bg-gradient-to-br from-gray-900 via-slate-800 to-[#181825] p-8 border border-slate-800 shadow-2xl relative overflow-hidden group group-hover:scale-100 transition-transform duration-300 ease-in-out">
@@ -78,7 +78,7 @@ export function GlareCard({
78
78
  return (
79
79
  <motion.div
80
80
  style={style}
81
- className="relative isolate [contain:layout_style] [perspective:600px] transition-transform duration-[var(--duration)] ease-[var(--easing)] delay-[var(--delay)] will-change-transform w-[320px] [aspect-ratio:17/21]"
81
+ className="relative isolate [contain:layout_style] [perspective:600px] transition-transform duration-[var(--duration)] ease-[var(--easing)] delay-[var(--delay)] will-change-transform w-full max-w-[320px] [aspect-ratio:17/21]"
82
82
  ref={refElement}
83
83
  onPointerMove={(event) => {
84
84
  const rotateFactor = 0.4;