From d7b56dd1a45a1145317d7787c1aa6e6b7ce0c145 Mon Sep 17 00:00:00 2001 From: jaimin Date: Sun, 21 Sep 2025 13:48:37 +0530 Subject: [PATCH] hero section improved with modern look --- package-lock.json | 65 +++++++++++++++++++++++++++ package.json | 1 + src/components/home/hero.tsx | 16 +++---- src/components/ui/texts/gradient.tsx | 58 ++++++++++++++++++++++++ src/components/ui/texts/highlight.tsx | 65 +++++++++++++++++++++++++++ src/components/ui/texts/writing.tsx | 62 +++++++++++++++++++++++++ 6 files changed, 257 insertions(+), 10 deletions(-) create mode 100644 src/components/ui/texts/gradient.tsx create mode 100644 src/components/ui/texts/highlight.tsx create mode 100644 src/components/ui/texts/writing.tsx diff --git a/package-lock.json b/package-lock.json index e688a22..38c68e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "clsx": "^2.1.1", "geist": "^1.4.2", "lucide-react": "^0.513.0", + "motion": "^12.23.16", "next": "15.3.3", "next-sitemap": "^4.2.3", "next-themes": "^0.4.6", @@ -3713,6 +3714,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/framer-motion": { + "version": "12.23.16", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.16.tgz", + "integrity": "sha512-N81A8hiHqVsexOzI3wzkibyLURW1nEJsZaRuctPhG4AdbbciYu+bKJq9I2lQFzAO4Bx3h4swI6pBbF/Hu7f7BA==", + "dependencies": { + "motion-dom": "^12.23.12", + "motion-utils": "^12.23.6", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -4995,6 +5022,44 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/motion": { + "version": "12.23.16", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.23.16.tgz", + "integrity": "sha512-8vVuxZgcfGZm4kgSqFgGrhQ+6034y4UuEsqCX8s7UYeoQ+NO3R9LV5AyDlVr2Mb7xvS7ZM5s/XkTurWbWQ+UHA==", + "dependencies": { + "framer-motion": "^12.23.16", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/motion-dom": { + "version": "12.23.12", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.12.tgz", + "integrity": "sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==", + "dependencies": { + "motion-utils": "^12.23.6" + } + }, + "node_modules/motion-utils": { + "version": "12.23.6", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", + "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index 7bbe2e0..8527266 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "clsx": "^2.1.1", "geist": "^1.4.2", "lucide-react": "^0.513.0", + "motion": "^12.23.16", "next": "15.3.3", "next-sitemap": "^4.2.3", "next-themes": "^0.4.6", diff --git a/src/components/home/hero.tsx b/src/components/home/hero.tsx index 82fb23a..ac09009 100644 --- a/src/components/home/hero.tsx +++ b/src/components/home/hero.tsx @@ -4,6 +4,9 @@ import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { ArrowRight, Github, Copy, Eye, Code2, Zap } from "lucide-react"; import { APP_CONFIG } from "@/lib/constants"; +import { WritingText } from "../ui/texts/writing"; +import { HighlightText } from "../ui/texts/highlight"; +import { GradientText } from "../ui/texts/gradient"; interface HeroProps { activePattern?: string | null; @@ -59,18 +62,11 @@ export default function Hero({ theme }: HeroProps) { className={`font-medium transition-colors duration-300 ${isPatternDark ? "text-white" : "text-gray-900 dark:text-gray-50" }`} > - Craft Beautiful +

- - Patterns Backgrounds - +

@@ -81,7 +77,7 @@ export default function Hero({ theme }: HeroProps) { > Professional-grade background patterns and gradients. Easily copy the code and seamlessly integrate it into your projects. - Crafted with modern CSS and Tailwind +

{/* Feature highlights */} diff --git a/src/components/ui/texts/gradient.tsx b/src/components/ui/texts/gradient.tsx new file mode 100644 index 0000000..80a874c --- /dev/null +++ b/src/components/ui/texts/gradient.tsx @@ -0,0 +1,58 @@ +'use client'; + +import * as React from 'react'; +import { motion, type Transition } from 'motion/react'; + +import { cn } from '@/lib/utils'; + +type GradientTextProps = React.ComponentProps<'span'> & { + text: string; + gradient?: string; + neon?: boolean; + transition?: Transition; +}; + +function GradientText({ + text, + className, + gradient = 'linear-gradient(90deg, #3b82f6 0%, #a855f7 20%, #ec4899 50%, #a855f7 80%, #3b82f6 100%)', + neon = false, + transition = { duration: 50, repeat: Infinity, ease: 'linear' }, + ...props +}: GradientTextProps) { + const baseStyle: React.CSSProperties = { + backgroundImage: gradient, + }; + + return ( + + + {text} + + + {neon && ( + + {text} + + )} + + ); +} + +export { GradientText, type GradientTextProps }; \ No newline at end of file diff --git a/src/components/ui/texts/highlight.tsx b/src/components/ui/texts/highlight.tsx new file mode 100644 index 0000000..9ef8c84 --- /dev/null +++ b/src/components/ui/texts/highlight.tsx @@ -0,0 +1,65 @@ +'use client'; + +import * as React from 'react'; +import { + motion, + useInView, + type HTMLMotionProps, + type Transition, + type UseInViewOptions, +} from 'motion/react'; + +import { cn } from '@/lib/utils'; + +type HighlightTextProps = HTMLMotionProps<'span'> & { + text: string; + inView?: boolean; + inViewMargin?: UseInViewOptions['margin']; + inViewOnce?: boolean; + transition?: Transition; +}; + +function HighlightText({ + ref, + text, + className, + inView = false, + inViewMargin = '0px', + transition = { duration: 2, ease: 'easeInOut' }, + ...props +}: HighlightTextProps) { + const localRef = React.useRef(null); + React.useImperativeHandle(ref, () => localRef.current as HTMLSpanElement); + + const inViewResult = useInView(localRef, { + once: true, + margin: inViewMargin, + }); + const isInView = !inView || inViewResult; + + return ( + + {text} + + ); +} + +export { HighlightText, type HighlightTextProps }; \ No newline at end of file diff --git a/src/components/ui/texts/writing.tsx b/src/components/ui/texts/writing.tsx new file mode 100644 index 0000000..5265e88 --- /dev/null +++ b/src/components/ui/texts/writing.tsx @@ -0,0 +1,62 @@ +'use client'; + +import * as React from 'react'; +import { + motion, + useInView, + type Transition, + type UseInViewOptions, +} from 'motion/react'; + +type WritingTextProps = Omit, 'children'> & { + transition?: Transition; + inView?: boolean; + inViewMargin?: UseInViewOptions['margin']; + inViewOnce?: boolean; + spacing?: number | string; + text: string; +}; + +function WritingText({ + ref, + inView = false, + inViewMargin = '0px', + inViewOnce = true, + spacing = 5, + text, + transition = { type: 'spring', bounce: 0, duration: 2, delay: 0.3 }, + ...props +}: WritingTextProps) { + const localRef = React.useRef(null); + React.useImperativeHandle(ref, () => localRef.current as HTMLSpanElement); + + const inViewResult = useInView(localRef, { + once: inViewOnce, + margin: inViewMargin, + }); + const isInView = !inView || inViewResult; + + const words = React.useMemo(() => text.split(' '), [text]); + + return ( + + {words.map((word, index) => ( + + {word}{' '} + + ))} + + ); +} + +export { WritingText, type WritingTextProps }; \ No newline at end of file