diff --git a/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_assets/indra_photo_600.jpg b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_assets/indra_photo_600.jpg new file mode 100644 index 0000000..d703a3a Binary files /dev/null and b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_assets/indra_photo_600.jpg differ diff --git a/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/CardHover.tsx b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/CardHover.tsx new file mode 100644 index 0000000..c20b5bc --- /dev/null +++ b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/CardHover.tsx @@ -0,0 +1,63 @@ +import { type IndraIconSkill } from "~~/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_data/indra-skills"; + +type CardProps = { + Icon: IndraIconSkill; + name: string; + description: string; + time: string; +}; + +const CardContent = ({ Icon, description, name, time }: CardProps) => { + return ( +
+
+ +

{name}

+
+

{description}

+
+ {time} +
+
+ ); +}; + +export const CardHoverEffect1 = (props: CardProps) => { + return ( +
+ + +
+ ); +}; + +export const CardHoverEffect2 = (props: CardProps) => { + return ( +
+ + +
+ ); +}; + +export const CardHoverEffect3 = (props: CardProps) => { + return ( +
+ + + + +
+ ); +}; + +export const CardHoverEffect4 = (props: CardProps) => { + return ( +
+ + + + +
+ ); +}; diff --git a/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraAboutMeSection.tsx b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraAboutMeSection.tsx new file mode 100644 index 0000000..33fae0e --- /dev/null +++ b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraAboutMeSection.tsx @@ -0,0 +1,23 @@ +import React from "react"; +import Image from "next/image"; +import indraPhoto from "../_assets/indra_photo_600.jpg"; + +const IndraAboutMeSection: React.FC = () => { + return ( +
+
+
+ Indra +
+
+

About Me

+

{`I'm a front-end engineer 🧑‍💻 with full-stack prowess 💪, loving the craft of building useful and delightful products.`}

+

{`My expertise spans React ecosystem across the stack, with a keen interest in Web3 technologies.`}

+

{`I'm excited about the Ethereum ecosystem and exploring the transformative potential of blockchain technology.`}

+
+
+
+ ); +}; + +export default IndraAboutMeSection; diff --git a/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSkillsSection.tsx b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSkillsSection.tsx new file mode 100644 index 0000000..12ecebc --- /dev/null +++ b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSkillsSection.tsx @@ -0,0 +1,54 @@ +import { + CardHoverEffect1, + CardHoverEffect2, + CardHoverEffect3, + CardHoverEffect4, +} from "~~/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/CardHover"; +import { indraSkills } from "~~/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_data/indra-skills"; + +const IndraSkillsSection = (): React.ReactElement => { + return ( +
+

Skills

+
+ +
+
+ ); +}; + +export default IndraSkillsSection; diff --git a/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSocialsSection.tsx b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSocialsSection.tsx new file mode 100644 index 0000000..37de1fd --- /dev/null +++ b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSocialsSection.tsx @@ -0,0 +1,46 @@ +import Link from "next/link"; +import { + IndraIconSocials, + indraSocials, +} from "~~/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_data/indra-socials"; + +type HoverRevealButtonProps = { + Icon: IndraIconSocials; + label: string; +}; + +const HoverRevealButton = ({ Icon, label }: HoverRevealButtonProps) => { + return ( +
+ + + {label} + +
+ ); +}; + +const IndraSocialsSection = () => { + return ( +
+

Socials

+ +
+ ); +}; + +export default IndraSocialsSection; diff --git a/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSparkleName.tsx b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSparkleName.tsx new file mode 100644 index 0000000..728b9e0 --- /dev/null +++ b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSparkleName.tsx @@ -0,0 +1,107 @@ +"use client"; + +import React, { CSSProperties, useEffect, useState } from "react"; + +interface Sparkle { + id: string; + x: string; + y: string; + color: string; + delay: number; + scale: number; + lifespan: number; +} + +interface SparklesTextProps { + className?: string; + text: string; + sparklesCount?: number; + colors?: { + first: string; + second: string; + }; +} + +const SparklesText: React.FC = ({ + text, + colors = { first: "#9E7AFF", second: "#FE8BBB" }, + className = "", + sparklesCount = 10, +}) => { + const [sparkles, setSparkles] = useState([]); + + useEffect(() => { + const generateStar = (): Sparkle => ({ + id: `${Math.random()}-${Date.now()}`, + x: `${Math.random() * 100}%`, + y: `${Math.random() * 100}%`, + color: Math.random() > 0.5 ? colors.first : colors.second, + delay: Math.random() * 2, + scale: Math.random() * 1 + 0.3, + lifespan: Math.random() * 10 + 5, + }); + + const initializeStars = () => { + setSparkles(Array.from({ length: sparklesCount }, generateStar)); + }; + + const updateStars = () => { + setSparkles(currentSparkles => + currentSparkles.map(star => (star.lifespan <= 0 ? generateStar() : { ...star, lifespan: star.lifespan - 0.1 })), + ); + }; + + initializeStars(); + const interval = setInterval(updateStars, 100); + + return () => clearInterval(interval); + }, [colors.first, colors.second, sparklesCount]); + + return ( +
+ {sparkles.map(sparkle => ( + + ))} + {text} +
+ ); +}; + +const Sparkle: React.FC = ({ id, x, y, color, delay, scale }) => { + return ( + + + + ); +}; + +const IndraSparkleName: React.FC = () => { + return ( + <> + + + ); +}; + +export default IndraSparkleName; diff --git a/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_data/indra-skills.tsx b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_data/indra-skills.tsx new file mode 100644 index 0000000..82c0472 --- /dev/null +++ b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_data/indra-skills.tsx @@ -0,0 +1,177 @@ +import { AiOutlineApi } from "react-icons/ai"; +import { BsGearWideConnected } from "react-icons/bs"; +import { + SiChakraui, + SiCypress, + SiDocker, + SiElectron, + SiGit, + SiGraphql, + SiJavascript, + SiJest, + SiNextdotjs, + SiNodedotjs, + SiRadixui, + SiReact, + SiReacthookform, + SiReactquery, + SiRedux, + SiSocketdotio, + SiStorybook, + SiSwagger, + SiTailwindcss, + SiTestinglibrary, + SiTypescript, +} from "react-icons/si"; +import { TbBrandReactNative } from "react-icons/tb"; + +const currentYear = new Date().getFullYear(); + +export const indraSkills = [ + { + description: "A JavaScript library for building user interfaces", + icon: SiReact, + name: "React", + time: `${currentYear - 2019}+ years`, + }, + { + description: "The React Framework for Production", + icon: SiNextdotjs, + name: "Next.js", + time: `${currentYear - 2019}+ years`, + }, + { + description: "Typed superset of JavaScript that compiles to plain JavaScript", + icon: SiTypescript, + name: "TypeScript", + time: `${currentYear - 2019}+ years`, + }, + { + description: "High-level, interpreted programming language", + icon: SiJavascript, + name: "JavaScript", + time: `${currentYear - 2017}+ years`, + }, + { + description: "JavaScript runtime built on Chrome's V8 JavaScript engine", + icon: SiNodedotjs, + name: "Node.js", + time: `${currentYear - 2017}+ years`, + }, + { + description: "Framework for building native apps using React", + icon: TbBrandReactNative, + name: "React Native", + time: `${currentYear - 2019}+ years`, + }, + { + description: "A library for managing server state in React applications", + icon: SiReactquery, + name: "React Query", + time: `${currentYear - 2020}+ years`, + }, + { + description: "A library for building forms in React applications", + icon: SiReacthookform, + name: "React Hook Form", + time: `${currentYear - 2020}+ years`, + }, + { + description: "Swagger is a framework for building RESTful web services", + icon: SiSwagger, + name: "Swagger", + time: `${currentYear - 2020}+ years`, + }, + { + description: "Query language for APIs", + icon: SiGraphql, + name: "GraphQL", + time: `${currentYear - 2022}+ years`, + }, + { + description: "Architectural style for designing networked applications", + icon: AiOutlineApi, + name: "REST APIs", + time: `${currentYear - 2018}+ years`, + }, + { + description: "Predictable state container for JavaScript apps", + icon: SiRedux, + name: "Redux", + time: `${currentYear - 2019}+ years`, + }, + { + description: "Utility-first CSS framework", + icon: SiTailwindcss, + name: "Tailwind CSS", + time: `${currentYear - 2020}+ years`, + }, + { + description: "Simple, modular and accessible component library for React", + icon: SiChakraui, + name: "Chakra UI", + time: `${currentYear - 2022}+ years`, + }, + { + description: "Unstyled, accessible components for building high‑quality design systems", + icon: SiRadixui, + name: "Radix UI", + time: `${currentYear - 2022}+ years`, + }, + { + description: "Protocol for real time data exchange", + icon: SiSocketdotio, + name: "Web Sockets", + time: `${currentYear - 2020}+ years`, + }, + { + description: "Tool for developing UI components in isolation", + icon: SiStorybook, + name: "Storybook", + time: `${currentYear - 2020}+ years`, + }, + { + description: "JavaScript testing framework", + icon: SiJest, + name: "Jest", + time: `${currentYear - 2020}+ years`, + }, + { + description: "React Testing Library (RTL) - react testing utilities that encourage good testing practices", + icon: SiTestinglibrary, + name: "RTL", + time: `${currentYear - 2020}+ years`, + }, + { + description: "End-to-end testing framework", + icon: SiCypress, + name: "Cypress", + time: `${currentYear - 2020}+ years`, + }, + { + description: "Tool for developing, shipping, and running applications", + icon: SiDocker, + name: "Docker", + time: `${currentYear - 2021}+ years`, + }, + { + description: "Continuous Integration and Continuous Deployment", + icon: BsGearWideConnected, + name: "CI/CD", + time: `${currentYear - 2019}+ years`, + }, + { + description: "Distributed version control system", + icon: SiGit, + name: "Git", + time: `${currentYear - 2015}+ years`, + }, + { + description: "Framework for building cross-platform desktop apps with web technologies", + icon: SiElectron, + name: "Electron", + time: `${currentYear - 2019}+ years`, + }, +] as const; + +export type IndraIconSkill = (typeof indraSkills)[number]["icon"]; diff --git a/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_data/indra-socials.tsx b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_data/indra-socials.tsx new file mode 100644 index 0000000..b8b2270 --- /dev/null +++ b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_data/indra-socials.tsx @@ -0,0 +1,52 @@ +import { SiGithub, SiLinkedin, SiTwitter, SiYoutube } from "react-icons/si"; +import { SlGlobe } from "react-icons/sl"; +import { BuidlGuidlLogo } from "~~/components/assets/BuidlGuidlLogo"; + +export const indraSocials = [ + { + icon: SlGlobe, + name: "Website", + label: "Website", + url: "https://dub.sh/indra-web", + username: "indralukmana.com", + }, + { + icon: SiGithub, + label: "GitHub", + name: "GitHub", + url: "https://dub.sh/indra-github", + username: "indralukmana", + }, + { + icon: SiLinkedin, + label: "LinkedIn", + name: "LinkedIn", + url: "https://dub.sh/indra-linkedin", + username: "in/indralukmana", + }, + { + icon: SiTwitter, + label: "Twitter", + name: "Twitter", + url: "https://dub.sh/indra-twitter", + username: "@indluk", + }, + { + icon: SiYoutube, + label: "Youtube", + username: "@indluk", + name: "Youtube", + url: "https://dub.sh/indra-youtube", + }, + { + name: "BuidlGuidl", + url: "https://app.buidlguidl.com/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3", + label: "BuidlGuidl", + icon: BuidlGuidlLogo, + username: "0x8...3C3", + }, +] as const; + +export type IndraIconSocials = (typeof indraSocials)[number]["icon"]; + +export const indraEthAddress = "0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3"; diff --git a/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/page.tsx b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/page.tsx new file mode 100644 index 0000000..0c28e35 --- /dev/null +++ b/packages/nextjs/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/page.tsx @@ -0,0 +1,28 @@ +import type { NextPage } from "next"; +import IndraAboutMeSection from "~~/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraAboutMeSection"; +import IndraSkillsSection from "~~/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSkillsSection"; +import IndraSocialsSection from "~~/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSocialsSection"; +import IndraSparkleName from "~~/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_components/IndraSparkleName"; +import { indraEthAddress } from "~~/app/builders/0x80Ad2861Ab5D4EeA61330A4bd7d6969357C463C3/_data/indra-socials"; +import { Address } from "~~/components/scaffold-eth"; + +const BuilderPage: NextPage = () => { + return ( +
+
+

+ +

+
+
+ + + + + + +
+ ); +}; + +export default BuilderPage; diff --git a/packages/nextjs/tailwind.config.js b/packages/nextjs/tailwind.config.js index 9099dc5..dc29874 100644 --- a/packages/nextjs/tailwind.config.js +++ b/packages/nextjs/tailwind.config.js @@ -81,6 +81,13 @@ module.exports = { }, animation: { "pulse-fast": "pulse 1s cubic-bezier(0.4, 0, 0.6, 1) infinite", + sparkle: "sparkle 1.5s ease-in-out infinite", + }, + keyframes: { + sparkle: { + "0%, 100%": { opacity: 0, transform: "scale(0) rotate(0deg)" }, + "50%": { opacity: 1, transform: "scale(1) rotate(180deg)" }, + }, }, }, },