diff --git a/apps/web/src/components/sections/hero.tsx b/apps/web/src/components/sections/hero.tsx index 61bf38b3f5..97815208e9 100644 --- a/apps/web/src/components/sections/hero.tsx +++ b/apps/web/src/components/sections/hero.tsx @@ -1,7 +1,7 @@ -import Image from "next/image"; import { CtaButton } from "@/components/ui/cta-button"; import Announcement from "../hero/Announcement"; import Demo from "../hero/Demo"; +import SparklesText from "../ui/sparkles-text"; export default function Hero() { return ( @@ -11,9 +11,30 @@ export default function Hero() {

Hypercharge Notetaking

-

- Hypnote is a smart notepad that upgrades your notes by automatically - transcribing and analyzing the conversation +

+ + HYPRNOTE + {" "} + is a smart notepad 🗒️ +
+ + that combines notes with + + + + voice recordings + + + +
+ + to create{" "} + +

diff --git a/apps/web/src/components/ui/header-button.tsx b/apps/web/src/components/ui/header-button.tsx index 2687d638ec..28eb6838d0 100644 --- a/apps/web/src/components/ui/header-button.tsx +++ b/apps/web/src/components/ui/header-button.tsx @@ -44,14 +44,12 @@ export function HeaderButton({ className }: HeaderButtonProps) { variant="outline" size="default" className={cn( - "inline-flex items-center justify-center gap-2 transition-all duration-200 rounded-xl relative", + "inline-flex items-center justify-center gap-2 transition-all duration-200 rounded-xl border border-gray-300 hover:border-gray-400", { - "bg-gradient-to-br from-[#f97316] to-[#6366f1] text-white border-transparent before:opacity-100": + "bg-gradient-to-br from-[#fbbf24] to-[#2563eb] text-white": isScrolled, - "border border-gray-300 before:opacity-0": !isScrolled, }, - "hover:bg-gradient-to-br hover:from-[#f97316] hover:to-[#6366f1] hover:text-white hover:border-transparent hover:before:opacity-100", - "before:content-[''] before:absolute before:inset-[1px] before:rounded-[10px] before:border before:border-white/30 before:transition-opacity before:duration-200", + "hover:bg-gradient-to-br hover:from-[#fbbf24] hover:to-[#2563eb] hover:text-white", className, )} > diff --git a/apps/web/src/components/ui/sparkles-text.tsx b/apps/web/src/components/ui/sparkles-text.tsx new file mode 100644 index 0000000000..8d3e8a4a89 --- /dev/null +++ b/apps/web/src/components/ui/sparkles-text.tsx @@ -0,0 +1,152 @@ +"use client"; + +import { CSSProperties, ReactElement, useEffect, useState } from "react"; +import { motion } from "framer-motion"; + +import { cn } 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: '#9E7AFF', second: '#FE8BBB'}" + * @type string + * @description + * The colors of the sparkles + * */ + colors?: { + first: string; + second: string; + }; +} + +const SparklesText: React.FC = ({ + text, + colors = { first: "#9E7AFF", second: "#FE8BBB" }, + 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; diff --git a/apps/web/src/styles/pushable-button.css b/apps/web/src/styles/pushable-button.css index 03a340dc06..9991709f76 100644 --- a/apps/web/src/styles/pushable-button.css +++ b/apps/web/src/styles/pushable-button.css @@ -1,5 +1,5 @@ .pushable { - background: linear-gradient(135deg, #7c2d12, #312e81); + background: linear-gradient(135deg, #f59e0b, #1e3a8a); border: none; border-radius: 12px; padding: 0; @@ -16,7 +16,7 @@ padding: 12px 42px; border-radius: 12px; font-size: 1.25rem; - background: linear-gradient(135deg, #f97316, #6366f1); + background: linear-gradient(135deg, #fbbf24, #2563eb); color: white; transform: translateY(-6px); transition: transform 50ms; @@ -28,7 +28,7 @@ position: absolute; inset: 1px; border-radius: 11px; - border: 1px solid rgba(255, 255, 255, 0.3); + border: 1px solid rgba(255, 255, 255, 0.4); pointer-events: none; }