diff --git a/package-lock.json b/package-lock.json index d6b84ba..8638a8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@radix-ui/react-slot": "^1.1.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "framer-motion": "^11.15.0", "lucide-react": "^0.469.0", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -2651,6 +2652,33 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.15.0.tgz", + "integrity": "sha512-MLk8IvZntxOMg7lDBLw2qgTHHv664bYoYmnFTmE0Gm/FW67aOJk0WM3ctMcG+Xhcv+vh5uyyXwxvxhSeJzSe+w==", + "license": "MIT", + "dependencies": { + "motion-dom": "^11.14.3", + "motion-utils": "^11.14.3", + "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/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3136,6 +3164,18 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/motion-dom": { + "version": "11.14.3", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.14.3.tgz", + "integrity": "sha512-lW+D2wBy5vxLJi6aCP0xyxTxlTfiu+b+zcpVbGVFUxotwThqhdpPRSmX8xztAgtZMPMeU0WGVn/k1w4I+TbPqA==", + "license": "MIT" + }, + "node_modules/motion-utils": { + "version": "11.14.3", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.14.3.tgz", + "integrity": "sha512-Xg+8xnqIJTpr0L/cidfTTBFkvRw26ZtGGuIhA94J9PQ2p4mEa06Xx7QVYZH0BP+EpMSaDlu+q0I0mmvwADPsaQ==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4146,7 +4186,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, "license": "0BSD" }, "node_modules/turbo-stream": { diff --git a/package.json b/package.json index d50f25b..b09f898 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@radix-ui/react-slot": "^1.1.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "framer-motion": "^11.15.0", "lucide-react": "^0.469.0", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/public/svg/services-bg.svg b/public/svg/services-bg.svg new file mode 100644 index 0000000..79fceaa --- /dev/null +++ b/public/svg/services-bg.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index e69de29..40af6dd 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -0,0 +1,2 @@ +export * from "./services/NipIcon"; +export * from "./services/RelayIcon"; diff --git a/src/assets/icons/services/NipIcon.tsx b/src/assets/icons/services/NipIcon.tsx new file mode 100644 index 0000000..8a8dd19 --- /dev/null +++ b/src/assets/icons/services/NipIcon.tsx @@ -0,0 +1,32 @@ +import { IconProps } from "@/@types/iconProps"; + +export const NipIcon = ({ ...props }: IconProps) => { + return ( + + + + + + + + + + ); +}; diff --git a/src/assets/icons/services/RelayIcon.tsx b/src/assets/icons/services/RelayIcon.tsx new file mode 100644 index 0000000..f4d2d94 --- /dev/null +++ b/src/assets/icons/services/RelayIcon.tsx @@ -0,0 +1,34 @@ +import { IconProps } from "@/@types/iconProps"; + +export const RelayIcon = ({ ...props }: IconProps) => { + return ( + + + + + + + + + + ); +}; diff --git a/src/components/AnimateWrapper.tsx b/src/components/AnimateWrapper.tsx new file mode 100644 index 0000000..b7d7633 --- /dev/null +++ b/src/components/AnimateWrapper.tsx @@ -0,0 +1,48 @@ +import { + AnimatePresence, + AnimationProps, + motion, + TargetAndTransition, + VariantLabels, +} from "framer-motion"; +import React from "react"; +type AnimateWrapperType = { + duration?: number; + whileInView?: VariantLabels | TargetAndTransition; + transition?: AnimationProps; + delay?: number; + once?: boolean; + children?: React.ReactNode; +} & AnimationProps; + +export default function AnimateWrapper({ + exit, + whileInView, + initial, + duration, + children, + transition, + delay, + once, +}: AnimateWrapperType) { + return ( + <> + + + {children} + + + > + ); +} diff --git a/src/components/pages/Home/HeroSection.tsx b/src/components/pages/Home/HeroSection.tsx index 2999b87..50175fe 100644 --- a/src/components/pages/Home/HeroSection.tsx +++ b/src/components/pages/Home/HeroSection.tsx @@ -1,7 +1,7 @@ const HeroSection = () => { return ( - + Stay Immortal! diff --git a/src/components/pages/Home/Services/ServicesCard.tsx b/src/components/pages/Home/Services/ServicesCard.tsx new file mode 100644 index 0000000..ec51151 --- /dev/null +++ b/src/components/pages/Home/Services/ServicesCard.tsx @@ -0,0 +1,32 @@ +import GradientIconBox from "@/components/ui/GradientIconBox"; +import { ServicesCardProps } from "./data"; + +const ServicesCard = ({ + title, + description, + icon, + isItPublished, +}: ServicesCardProps) => { + return ( + + + {icon} + + {!isItPublished && ( + + Coming Soon + + )} + + {title} + + + + {description} + + + + ); +}; + +export default ServicesCard; diff --git a/src/components/pages/Home/Services/data.tsx b/src/components/pages/Home/Services/data.tsx new file mode 100644 index 0000000..27633cf --- /dev/null +++ b/src/components/pages/Home/Services/data.tsx @@ -0,0 +1,24 @@ +import { TitleDescriptionT } from "@/@types/global"; +import { NipIcon, RelayIcon } from "@/assets/icons"; +import { ReactNode } from "react"; + +export type ServicesCardProps = { + icon: ReactNode; + isItPublished?: boolean; +} & TitleDescriptionT; + +export const servicesData: ServicesCardProps[] = [ + { + title: "NIP-05 Service", + description: + "Let your friends to find you by your name on chaotic nostr ecosystem easily. Pay once keep it forever.", + icon: , + isItPublished: true, + }, + { + title: "Relay Services", + description: + "Let your friends to find you by your name on chaotic nostr ecosystem easily. Pay once keep it forever.", + icon: , + }, +]; diff --git a/src/components/pages/Home/Services/index.tsx b/src/components/pages/Home/Services/index.tsx new file mode 100644 index 0000000..5bcdc32 --- /dev/null +++ b/src/components/pages/Home/Services/index.tsx @@ -0,0 +1,21 @@ +import SectionTitle from "@/components/ui/SectionTitle"; +import { servicesData } from "./data"; +import ServicesCard from "./ServicesCard"; +import AnimateWrapper from "@/components/AnimateWrapper"; + +const ServicesSection = () => { + return ( + + Our Services + + + {servicesData.map((service, key) => ( + + ))} + + + + ); +}; + +export default ServicesSection; diff --git a/src/components/pages/Home/index.tsx b/src/components/pages/Home/index.tsx index 1221d35..1809530 100644 --- a/src/components/pages/Home/index.tsx +++ b/src/components/pages/Home/index.tsx @@ -1,9 +1,11 @@ import HeroSection from "./HeroSection"; +import ServicesSection from "./Services"; export const HomePage = () => { return ( <> + > ); }; diff --git a/src/components/ui/GradientIconBox.tsx b/src/components/ui/GradientIconBox.tsx new file mode 100644 index 0000000..d5c11dc --- /dev/null +++ b/src/components/ui/GradientIconBox.tsx @@ -0,0 +1,13 @@ +import { ReactNode } from "react"; + +const GradientIconBox = ({ children }: { children: ReactNode }) => { + return ( + + + {children} + + + ); +}; + +export default GradientIconBox; diff --git a/src/components/ui/SectionTitle.tsx b/src/components/ui/SectionTitle.tsx new file mode 100644 index 0000000..b621677 --- /dev/null +++ b/src/components/ui/SectionTitle.tsx @@ -0,0 +1,30 @@ +import { cn } from "@/lib/utils"; +import { ReactNode, forwardRef } from "react"; +import AnimateWrapper from "../AnimateWrapper"; + +type SectionTitleProps = { + children: ReactNode; + className?: string; +}; + +const SectionTitle = forwardRef( + ({ className, children, ...props }: SectionTitleProps) => { + return ( + + + {children} + + + ); + }, +); + +SectionTitle.displayName = "SectionTitle"; + +export default SectionTitle; diff --git a/src/styles/index.css b/src/styles/index.css index e43b59d..374bef6 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -48,4 +48,7 @@ @apply bg-clip-text text-transparent bg-gradient-to-r from-[#ACCDF2] via-[#D4E9F7] to-[#ACCDF2]; text-shadow: 0px 0px 22.76px #a0c5f7a8; } + .purple-gradient-text { + @apply bg-clip-text text-transparent bg-gradient-to-r from-[#F869B6] to-[#D34CD9]; + } }
+ {title} +
+ {description} +