Merge version_2_1776677260726 into main #1
@@ -8,8 +8,17 @@ import MetricsSimpleCards from '@/components/sections/metrics/MetricsSimpleCards
|
||||
import NavbarCentered from '@/components/ui/NavbarCentered';
|
||||
import TestimonialRatingCards from '@/components/sections/testimonial/TestimonialRatingCards';
|
||||
import { Droplets, Flame, Wrench } from "lucide-react";
|
||||
import { useEffect } from "react";
|
||||
import { applyRippleEffect } from "@/hooks/useButtonClick";
|
||||
|
||||
export default function App() {
|
||||
useEffect(() => {
|
||||
const buttons = document.querySelectorAll("button");
|
||||
buttons.forEach((button) => {
|
||||
applyRippleEffect(button);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="nav" data-section="nav">
|
||||
|
||||
14
src/components/cards/GlassCard.tsx
Normal file
14
src/components/cards/GlassCard.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
type GlassCardProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const GlassCard = ({ className }: GlassCardProps) => {
|
||||
return (
|
||||
<div className={`glass-card ${className || ''}`}>
|
||||
Active Now
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GlassCard;
|
||||
@@ -4,6 +4,7 @@ import TextAnimation from "@/components/ui/TextAnimation";
|
||||
import ImageOrVideo from "@/components/ui/ImageOrVideo";
|
||||
import GridOrCarousel from "@/components/ui/GridOrCarousel";
|
||||
import { cls } from "@/lib/utils";
|
||||
import GlassCard from "@/components/cards/GlassCard";
|
||||
|
||||
type Testimonial = {
|
||||
name: string;
|
||||
@@ -56,7 +57,7 @@ const TestimonialRatingCards = ({
|
||||
</div>
|
||||
|
||||
<GridOrCarousel carouselThreshold={3}>
|
||||
{testimonials.map((testimonial) => (
|
||||
{testimonials.map((testimonial, index) => (
|
||||
<div key={testimonial.name} className="flex flex-col justify-between gap-5 h-full p-5 rounded card">
|
||||
<div className="flex flex-col items-start gap-5">
|
||||
<div className="flex gap-1">
|
||||
@@ -73,8 +74,9 @@ const TestimonialRatingCards = ({
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="size-10 overflow-hidden rounded-full">
|
||||
<div className="relative size-10 overflow-hidden rounded-full">
|
||||
<ImageOrVideo imageSrc={testimonial.imageSrc} videoSrc={testimonial.videoSrc} />
|
||||
{index === 0 && <GlassCard className="absolute bottom-0 left-1/2 -translate-x-1/2 translate-y-1/4" />}
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-base font-medium leading-tight">{testimonial.name}</span>
|
||||
|
||||
@@ -49,3 +49,30 @@ export const useButtonClick = (href?: string, onClick?: () => void) => {
|
||||
|
||||
return handleClick;
|
||||
};
|
||||
|
||||
export const applyRippleEffect = (element: HTMLElement) => {
|
||||
element.addEventListener("mousedown", (e: MouseEvent) => {
|
||||
const target = e.currentTarget as HTMLElement;
|
||||
const ripple = document.createElement("span");
|
||||
const rect = target.getBoundingClientRect();
|
||||
const size = Math.max(rect.width, rect.height);
|
||||
const x = e.clientX - rect.left - size / 2;
|
||||
const y = e.clientY - rect.top - size / 2;
|
||||
|
||||
ripple.style.width = ripple.style.height = `${size}px`;
|
||||
ripple.style.left = `${x}px`;
|
||||
ripple.style.top = `${y}px`;
|
||||
ripple.classList.add("ripple");
|
||||
|
||||
const existingRipple = target.querySelector(".ripple");
|
||||
if (existingRipple) {
|
||||
existingRipple.remove();
|
||||
}
|
||||
|
||||
target.appendChild(ripple);
|
||||
|
||||
ripple.addEventListener("animationend", () => {
|
||||
ripple.remove();
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -152,6 +152,26 @@ h6 {
|
||||
font-family: '${inter.variable} ${openSans.variable}', sans-serif;
|
||||
}
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
button::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 0;
|
||||
left: -75%;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0) 100%);
|
||||
transform: skewX(-25deg);
|
||||
}
|
||||
|
||||
button:hover::before {
|
||||
animation: shine 1s;
|
||||
}
|
||||
|
||||
/* WEBILD_CARD_STYLE */
|
||||
/* @cards/gradient-radial */
|
||||
.card {
|
||||
@@ -161,10 +181,16 @@ h6 {
|
||||
/* WEBILD_PRIMARY_BUTTON */
|
||||
/* @primaryButtons/shadow */
|
||||
.primary-button {
|
||||
background: var(--color-primary-cta);
|
||||
background-image: linear-gradient(to right, var(--color-primary-cta) 0%, var(--color-accent) 50%, var(--color-primary-cta) 100%);
|
||||
background-size: 200% auto;
|
||||
transition: background-position 0.5s ease;
|
||||
box-shadow: 2.10837px 3.16256px 9.48767px color-mix(in srgb, var(--color-primary-cta) 40%, transparent);
|
||||
}
|
||||
|
||||
.primary-button:hover {
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
/* WEBILD_SECONDARY_BUTTON */
|
||||
/* @secondaryButtons/glass */
|
||||
.secondary-button {
|
||||
@@ -173,3 +199,8 @@ h6 {
|
||||
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
border: 1px solid var(--color-secondary-cta);
|
||||
}
|
||||
|
||||
.primary-button:active,
|
||||
.secondary-button:active {
|
||||
animation: button-pulse 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
@@ -128,6 +128,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes button-pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation classes */
|
||||
|
||||
.animate-pulsate {
|
||||
@@ -169,3 +181,25 @@
|
||||
.animate-progress {
|
||||
animation: progress linear forwards;
|
||||
}
|
||||
|
||||
@keyframes ripple {
|
||||
to {
|
||||
transform: scale(4);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ripple {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
transform: scale(0);
|
||||
animation: ripple 600ms linear;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes shine {
|
||||
100% {
|
||||
left: 125%;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user