From 658ee9f1bcf422e716d9a75c84710bb0ccc9d084 Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Sun, 11 Aug 2024 21:12:23 +0200 Subject: [PATCH] refactor: Improve responsiveness of Features component layout --- src/components/features.tsx | 3 + src/components/ui/sparkles-text.tsx | 152 ++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 src/components/ui/sparkles-text.tsx diff --git a/src/components/features.tsx b/src/components/features.tsx index 25a8bb4..3063aea 100644 --- a/src/components/features.tsx +++ b/src/components/features.tsx @@ -17,6 +17,7 @@ import { import { CheckIcon, XIcon } from "lucide-react"; import { QuestionMarkIcon } from "@radix-ui/react-icons"; import ShineBorder from "./ui/shine-border"; +import SparklesText from "./ui/sparkles-text"; function Checkmark() { return @@ -34,6 +35,8 @@ export default function Features() { return (
{/**/} +

What does Zen offer ?

+

Zen Browser is packed with features that will change the way you browse the web. Here are
some of the features that Zen offers.

diff --git a/src/components/ui/sparkles-text.tsx b/src/components/ui/sparkles-text.tsx new file mode 100644 index 0000000..2290115 --- /dev/null +++ b/src/components/ui/sparkles-text.tsx @@ -0,0 +1,152 @@ +'use client' + +import { motion } from 'framer-motion' +import type { CSSProperties, ReactElement } from 'react' +import { useEffect, useState } from 'react' +import { ny } from '@/lib/utils' + +interface Sparkle { + id: string + x: string + y: string + color: string + delay: number + scale: number + lifespan: number +} + +interface SparklesTextProps { + /** + * @default
+ * @type ReactElement + * @description + * The component to be rendered as the text + */ + as?: ReactElement + + /** + * @default "" + * @type string + * @description + * The className of the text + */ + className?: string + + /** + * @required + * @type string + * @description + * The text to be displayed + */ + text: string + + /** + * @default 10 + * @type number + * @description + * The count of sparkles + */ + sparklesCount?: number + + /** + * @default "{first: '#A07CFE', second: '#FE8FB5'}" + * @type string + * @description + * The colors of the sparkles + */ + colors?: { + first: string + second: string + } +} + +const SparklesText: React.FC = ({ + text, + colors = { first: '#A07CFE', second: '#FE8FB5' }, + className, + sparklesCount = 10, + ...props +}) => { + const [sparkles, setSparkles] = useState([]) + + useEffect(() => { + const generateStar = (): Sparkle => { + const starX = `${Math.random() * 100}%` + const starY = `${Math.random() * 100}%` + const color = Math.random() > 0.5 ? colors.first : colors.second + const delay = Math.random() * 2 + const scale = Math.random() * 1 + 0.3 + const lifespan = Math.random() * 10 + 5 + const id = `${starX}-${starY}-${Date.now()}` + return { id, x: starX, y: starY, color, delay, scale, lifespan } + } + + const initializeStars = () => { + const newSparkles = Array.from({ length: sparklesCount }, generateStar) + setSparkles(newSparkles) + } + + const updateStars = () => { + setSparkles(currentSparkles => + currentSparkles.map((star) => { + if (star.lifespan <= 0) + return generateStar() + else return { ...star, lifespan: star.lifespan - 0.1 } + }), + ) + } + + initializeStars() + const interval = setInterval(updateStars, 100) + + return () => clearInterval(interval) + }, [colors.first, colors.second]) + + return ( +
+ + {sparkles.map(sparkle => ( + + ))} + + {text} + + +
+ ) +} + +const Sparkle: React.FC = ({ id, x, y, color, delay, scale }) => { + return ( + + + + ) +} + +export default SparklesText