Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions apps/web/src/components/sections/hero.tsx
Original file line number Diff line number Diff line change
@@ -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 (
Expand All @@ -11,9 +11,30 @@ export default function Hero() {

<h1 className="text-5xl font-bold mb-6">Hypercharge Notetaking</h1>

<p className="text-2xl text-muted-foreground max-w-2xl mx-auto mb-8">
Hypnote is a smart notepad that upgrades your notes by automatically
transcribing and analyzing the conversation
<p className="text-2xl max-w-2xl mx-auto mb-8 text-gray-800 leading-relaxed">
<strong className="text-black font-bold font-racing-sans">
HYPRNOTE
</strong>{" "}
is a smart notepad 🗒️
<br className="hidden sm:block" />
<span className="inline-flex mt-2 items-center">
that combines notes with
<span className="inline-flex ml-2 justify-center items-center gap-2 bg-red-50/80 rounded-full px-3 py-1">
<span className="size-2 rounded-full bg-red-500 animate-pulse"></span>
<span className="font-medium text-gray-900 text-xl">
voice recordings
</span>
</span>
</span>
<br className="hidden sm:block" />
<span className="inline-block mt-2">
to create{" "}
<SparklesText
text="powerful summaries"
className="text-2xl inline font-medium"
colors={{ first: "#FFD700", second: "#1E90FF" }}
/>
</span>
</p>

<CtaButton size="xl" />
Expand Down
8 changes: 3 additions & 5 deletions apps/web/src/components/ui/header-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)}
>
Expand Down
152 changes: 152 additions & 0 deletions apps/web/src/components/ui/sparkles-text.tsx
Original file line number Diff line number Diff line change
@@ -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 <div />
* @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<SparklesTextProps> = ({
text,
colors = { first: "#9E7AFF", second: "#FE8BBB" },
className,
sparklesCount = 10,
...props
}) => {
const [sparkles, setSparkles] = useState<Sparkle[]>([]);

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 (
<div
className={cn("text-6xl font-bold", className)}
{...props}
style={
{
"--sparkles-first-color": `${colors.first}`,
"--sparkles-second-color": `${colors.second}`,
} as CSSProperties
}
>
<span className="relative inline-block">
{sparkles.map((sparkle) => (
<Sparkle key={sparkle.id} {...sparkle} />
))}
<strong>{text}</strong>
</span>
</div>
);
};

const Sparkle: React.FC<Sparkle> = ({ id, x, y, color, delay, scale }) => {
return (
<motion.svg
key={id}
className="pointer-events-none absolute z-20"
initial={{ opacity: 0, left: x, top: y }}
animate={{
opacity: [0, 0.5, 0],
scale: [0, scale, 0],
rotate: [75, 120, 150],
}}
transition={{ duration: 0.8, repeat: Infinity, delay }}
width="21"
height="21"
viewBox="0 0 21 21"
>
<path
d="M9.82531 0.843845C10.0553 0.215178 10.9446 0.215178 11.1746 0.843845L11.8618 2.72026C12.4006 4.19229 12.3916 6.39157 13.5 7.5C14.6084 8.60843 16.8077 8.59935 18.2797 9.13822L20.1561 9.82534C20.7858 10.0553 20.7858 10.9447 20.1561 11.1747L18.2797 11.8618C16.8077 12.4007 14.6084 12.3916 13.5 13.5C12.3916 14.6084 12.4006 16.8077 11.8618 18.2798L11.1746 20.1562C10.9446 20.7858 10.0553 20.7858 9.82531 20.1562L9.13819 18.2798C8.59932 16.8077 8.60843 14.6084 7.5 13.5C6.39157 12.3916 4.19225 12.4007 2.72023 11.8618L0.843814 11.1747C0.215148 10.9447 0.215148 10.0553 0.843814 9.82534L2.72023 9.13822C4.19225 8.59935 6.39157 8.60843 7.5 7.5C8.60843 6.39157 8.59932 4.19229 9.13819 2.72026L9.82531 0.843845Z"
fill={color}
/>
</motion.svg>
);
};

export default SparklesText;
6 changes: 3 additions & 3 deletions apps/web/src/styles/pushable-button.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.pushable {
background: linear-gradient(135deg, #7c2d12, #312e81);
background: linear-gradient(135deg, #f59e0b, #1e3a8a);
border: none;
border-radius: 12px;
padding: 0;
Expand All @@ -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;
Expand All @@ -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;
}

Expand Down