├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── app ├── SectionHero.tsx ├── SectionLetsConnect.tsx ├── SectionMyLatestProject.tsx ├── SectionQuote.tsx ├── SectionTechnologyStack.tsx ├── blog │ └── page.tsx ├── favicon.ico ├── globals.css ├── home.module.css ├── layout.tsx ├── page.tsx └── project │ ├── layout.tsx │ └── page.tsx ├── assets ├── fonts │ └── suarte │ │ └── Suarte Free.ttf └── images │ └── home │ ├── hero │ ├── avatar-smile.webp │ ├── dribble.webp │ ├── github.webp │ ├── instagram.webp │ ├── linkedin.webp │ ├── quadrilateral.webp │ ├── triangle.webp │ ├── twisted-torus.webp │ └── zig-zag.webp │ ├── letsConnect │ ├── avatar-big-smile.webp │ ├── dribble.webp │ ├── github.webp │ ├── gmail.webp │ ├── instagram.webp │ └── linkedin.webp │ ├── myLatestProject │ ├── figma.webp │ ├── projects │ │ └── portfolio-website.webp │ ├── rocket.webp │ └── suitcase.webp │ ├── quote │ ├── bulb.webp │ ├── heart.webp │ ├── paint-kit.webp │ └── tea-cup.webp │ └── technologyStack │ ├── expo.webp │ ├── express-js.webp │ ├── javascript.webp │ ├── laravel.webp │ ├── next-js.webp │ ├── planet-scale.webp │ ├── prisma.webp │ ├── react-js.webp │ ├── react-native.webp │ ├── tailwindcss.webp │ └── typescript.webp ├── components ├── Banner.tsx ├── BrandIcon.tsx ├── Footer.tsx └── Navbar.tsx ├── constant ├── assets.ts └── font.ts ├── next.config.js ├── package.json ├── postcss.config.js ├── public ├── next.svg └── vercel.svg ├── tailwind.config.js ├── tsconfig.json └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | 37 | .vercel 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Deri Kurniawan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deri Kurniawan's 3D Portfolio 2 | 3 | [![Deri-Kurniawan - 3D Portfolio](https://img.shields.io/static/v1?label=Deri-Kurniawan&message=3d-portfolio&color=blue&logo=github)](https://github.com/Deri-Kurniawan/3d-portfolio "Go to GitHub repo") [![stars - 3D Portfolio](https://img.shields.io/github/stars/Deri-Kurniawan/3d-portfolio?style=social)](https://github.com/Deri-Kurniawan/3d-portfolio) 4 | [![forks - 3D Portfolio](https://img.shields.io/github/forks/Deri-Kurniawan/3d-portfolio?style=social)](https://github.com/Deri-Kurniawan/3d-portfolio) [![License](https://img.shields.io/badge/License-MIT-blue)](#license) [![issues - 3D Portfolio](https://img.shields.io/github/issues/Deri-Kurniawan/3d-portfolio)](https://github.com/Deri-Kurniawan/3d-portfolio/issues) 5 | 6 | This portfolio is based on my designs in [Dribble - Deri Kurniawan](https://dribbble.com/shots/21642242-3D-Theme-Portfolio-Website?utm_source=Clipboard_Shot&utm_campaign=deri-kurniawan&utm_content=3D%20Theme%20Portfolio%20Website&utm_medium=Social_Share&utm_source=Clipboard_Shot&utm_campaign=deri-kurniawan&utm_content=3D%20Theme%20Portfolio%20Website&utm_medium=Social_Share). You can also find the figma design there. 7 | 8 | ## Assets 9 | Create your own 3d Character at [peeps.ui8.net](https://peeps.ui8.net/) 10 | 11 | ## License 12 | 13 | Released under [MIT](/LICENSE) by [@Deri-Kurniawan](https://github.com/Deri-Kurniawan). 14 | -------------------------------------------------------------------------------- /app/SectionHero.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { assets } from '@/constant/assets' 4 | import Image from 'next/image' 5 | import { MotionProps, motion } from 'framer-motion' 6 | import { useInView } from 'react-intersection-observer'; 7 | 8 | interface IAnimateImageProps extends MotionProps { 9 | className: string; 10 | src: string; 11 | width: number; 12 | height: number; 13 | alt: string; 14 | } 15 | 16 | const AnimatedImage = motion(Image); 17 | 18 | export default function SectionHero(): JSX.Element { 19 | const { ref, inView } = useInView({ 20 | threshold: 0.1, 21 | triggerOnce: true, 22 | }); 23 | 24 | const animatedImages: IAnimateImageProps[] = [ 25 | { 26 | className: 'w-[140px] h-auto lg:w-[180px] lg:h-[120px] absolute top-3 -left-16 z-[1]', 27 | src: assets.home.hero.zigZag, 28 | width: 180, 29 | height: 120, 30 | alt: '', 31 | initial: { opacity: 0, x: -100 }, 32 | animate: inView ? { opacity: 1, x: 0 } : {}, 33 | transition: { delay: 0.4, duration: 0.8 }, 34 | }, 35 | { 36 | className: 'w-[110px] h-auto lg:w-[150px] lg:h-[140px] absolute top-6 -right-12 z-[1]', 37 | src: assets.home.hero.twistedTorus, 38 | width: 150, 39 | height: 140, 40 | alt: '', 41 | initial: { opacity: 0, x: 100 }, 42 | animate: inView ? { opacity: 1, x: 0 } : {}, 43 | transition: { delay: 0.6, duration: 0.8 }, 44 | }, 45 | { 46 | className: 'w-[130px] h-auto lg:w-[170px] lg:h-[170px] absolute bottom-6 -left-14 z-[1]', 47 | src: assets.home.hero.quadrilateral, 48 | width: 170, 49 | height: 170, 50 | alt: '', 51 | initial: { opacity: 0, x: -100 }, 52 | animate: inView ? { opacity: 1, x: 0 } : {}, 53 | transition: { delay: 0.8, duration: 0.8 }, 54 | }, 55 | { 56 | className: 'w-[192px] h-auto lg:w-[242px] lg:h-[202px] absolute bottom-8 -right-24 z-[1]', 57 | src: assets.home.hero.triangle, 58 | width: 242, 59 | height: 202, 60 | alt: '', 61 | initial: { opacity: 0, x: 100 }, 62 | animate: inView ? { opacity: 1, x: 0 } : {}, 63 | transition: { delay: 1, duration: 0.8 }, 64 | }, 65 | ]; 66 | 67 | return ( 68 |
69 |
70 | {/* first */} 71 |
72 | 76 | Welcome to Deri's Portfolio 77 | 78 | 82 | Full Stack Web Developer 83 | 84 | 88 | I'm Deri Kurniawan. A passionate Full Stack Web Developer based in Sukabumi Regency, West Java, Indonesia. 89 | 90 |
91 | {/* second */} 92 |
93 |
94 |
95 | 98 | 110 | 111 | {animatedImages.map(({ className, src, width, height, alt, initial, animate, transition }, index) => ( 112 | 124 | ))} 125 |
126 |
127 |
128 |
129 |
130 | ) 131 | } 132 | -------------------------------------------------------------------------------- /app/SectionLetsConnect.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from 'react' 4 | import { useInView } from 'react-intersection-observer'; 5 | import { motion } from 'framer-motion'; 6 | import Image from 'next/image'; 7 | import { assets } from '@/constant/assets'; 8 | import styles from './home.module.css'; 9 | 10 | const AnimatedImage = motion(Image); 11 | 12 | export default function SectionLetsConnect() { 13 | const { ref, inView } = useInView({ 14 | threshold: 0.1, 15 | triggerOnce: true, 16 | }); 17 | 18 | const socialMediaLinks = [ 19 | { 20 | initial: { y: 50, opacity: 0 }, 21 | animate: inView ? { y: 0, opacity: 1 } : {}, 22 | transition: { duration: 0.5, delay: 0.4 }, 23 | whileHover: { scale: 1.1, transition: { duration: 0.2 } }, 24 | className: "hidden lg:block absolute hover:cursor-pointer top-14 left-14 xl:left-24 w-10 h-10 md:w-[168px] md:h-[168px] z-10", 25 | src: assets.home.letsConnect.linkedin, 26 | alt: "", 27 | width: 168, 28 | height: 168, 29 | tabIndex: 0, 30 | onClick: () => window.open('https://linkedin.com/in/deri-kurniawan', '_blank'), 31 | }, 32 | { 33 | initial: { y: 50, opacity: 0 }, 34 | animate: inView ? { y: 0, opacity: 1 } : {}, 35 | transition: { duration: 0.5, delay: 0.6 }, 36 | whileHover: { scale: 1.1, transition: { duration: 0.2 } }, 37 | className: "hidden lg:block absolute hover:cursor-pointer top-14 right-14 xl:right-24 w-10 h-10 md:w-[168px] md:h-[168px] z-10", 38 | src: assets.home.letsConnect.instagram, 39 | alt: "", 40 | width: 168, 41 | height: 168, 42 | tabIndex: 0, 43 | onClick: () => window.open('https://instagram.com/deri561', '_blank'), 44 | }, 45 | { 46 | initial: { y: -50, opacity: 0 }, 47 | animate: inView ? { y: 0, opacity: 1 } : {}, 48 | transition: { duration: 0.5, delay: 1 }, 49 | whileHover: { scale: 1.1, transition: { duration: 0.2 } }, 50 | className: "hidden lg:block absolute hover:cursor-pointer bottom-14 right-36 xl:right-44 md:right-24 w-10 h-10 md:w-[168px] md:h-[168px] z-10", 51 | src: assets.home.letsConnect.github, 52 | alt: "", 53 | width: 168, 54 | height: 168, 55 | tabIndex: 0, 56 | onClick: () => window.open('https://github.com/deri-kurniawan', '_blank') 57 | }, 58 | { 59 | initial: { y: -50, opacity: 0 }, 60 | animate: inView ? { y: 0, opacity: 1 } : {}, 61 | transition: { duration: 0.5, delay: 0.8 }, 62 | whileHover: { scale: 1.1, transition: { duration: 0.2 } }, 63 | className: "hidden lg:block absolute hover:cursor-pointer bottom-14 left-36 xl:left-44 md:left-24 w-10 h-10 md:w-[168px] md:h-[168px] z-10", 64 | src: assets.home.letsConnect.dribble, 65 | alt: "", 66 | width: 168, 67 | height: 168, 68 | tabIndex: 0, 69 | onClick: () => window.open('https://dribbble.com/deri-kurniawan', '_blank') 70 | }, 71 | { 72 | initial: { y: 100, opacity: 0 }, 73 | animate: inView ? { y: 0, opacity: 1 } : {}, 74 | transition: { duration: 0.5, delay: 0 }, 75 | whileHover: { scale: 1.1, transition: { duration: 0.2 } }, 76 | className: "hidden lg:block absolute hover:cursor-pointer -bottom-64 w-10 h-10 md:w-[310px] md:h-[310px] z-10", 77 | src: assets.home.letsConnect.gmail, 78 | alt: "", 79 | width: 310, 80 | height: 310, 81 | tabIndex: 0, 82 | onClick: () => window.open('mailto:deri.netuchi@gmail.com', "_self") 83 | } 84 | 85 | ] 86 | 87 | return ( 88 |
89 |
90 | Let's Connect 91 | Do you have any questions or a project in mind? Let's connect! I am here to help and excited to hear from you. You can also take a look at my work. 92 |
93 |
94 |
95 |
96 | 97 |
98 | 109 | {socialMediaLinks.map((socialMediaLink, index) => ( 110 | 111 | ))} 112 |
113 | window.open('https://linkedin.com/in/deri-kurniawan', '_blank')} /> 114 | window.open('https://dribbble.com/deri-kurniawan', '_blank')} /> 115 | window.open('mailto:deri.netuchi@gmail.com', "_self")} /> 116 | window.open('https://instagram.com/deri561', '_blank')} /> 117 | window.open('https://github.com/deri-kurniawan', '_blank')} /> 118 |
119 |
120 |
121 |
122 | ) 123 | } 124 | -------------------------------------------------------------------------------- /app/SectionMyLatestProject.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useEffect, useState } from 'react'; 4 | import { assets } from '@/constant/assets'; 5 | import { useInView } from 'react-intersection-observer'; 6 | import { motion } from 'framer-motion'; 7 | import Image from 'next/image'; 8 | import Link from 'next/link'; 9 | import { useRouter } from 'next/navigation'; 10 | import { BsGithub } from 'react-icons/bs'; 11 | import { IoMdOpen } from 'react-icons/io'; 12 | import { BsInfoCircle } from 'react-icons/bs'; 13 | import { FiFigma } from 'react-icons/fi'; 14 | import styles from "./home.module.css"; 15 | 16 | const tabs = [ 17 | { 18 | name: 'Project', 19 | image: assets.home.myLatestProject.suitcase, 20 | data: [ 21 | { 22 | slug: 'transform-portfolio-design-to-web-app-1', 23 | title: 'Transform Portfolio Design to Web App', 24 | image: assets.home.myLatestProject.projects.portfolioWebsite, 25 | repositoryUrl: "https://github.com/deri-kurniawan/portfolio", 26 | demoUrl: "https://portfolio.deri.my.id", 27 | }, 28 | { 29 | slug: 'transform-portfolio-design-to-web-app-2', 30 | title: 'Portfolio 2', 31 | image: assets.home.myLatestProject.projects.portfolioWebsite, 32 | repositoryUrl: "https://github.com/deri-kurniawan/portfolio", 33 | demoUrl: "https://portfolio.deri.my.id", 34 | }, 35 | { 36 | slug: 'transform-portfolio-design-to-web-app-3', 37 | title: 'Portfolio 3', 38 | image: assets.home.myLatestProject.projects.portfolioWebsite, 39 | repositoryUrl: "https://github.com/deri-kurniawan/portfolio", 40 | demoUrl: "https://portfolio.deri.my.id", 41 | }, 42 | { 43 | slug: 'transform-portfolio-design-to-web-app-4', 44 | title: 'Portfolio 4', 45 | image: assets.home.myLatestProject.projects.portfolioWebsite, 46 | repositoryUrl: "https://github.com/deri-kurniawan/portfolio", 47 | demoUrl: "https://portfolio.deri.my.id", 48 | }, 49 | { 50 | slug: 'transform-portfolio-design-to-web-app-5', 51 | title: 'Portfolio 5', 52 | image: assets.home.myLatestProject.projects.portfolioWebsite, 53 | repositoryUrl: "https://github.com/deri-kurniawan/portfolio", 54 | demoUrl: "https://portfolio.deri.my.id", 55 | }, 56 | { 57 | slug: 'transform-portfolio-design-to-web-app-6', 58 | title: 'Portfolio 6', 59 | image: assets.home.myLatestProject.projects.portfolioWebsite, 60 | repositoryUrl: "https://github.com/deri-kurniawan/portfolio", 61 | demoUrl: "https://portfolio.deri.my.id", 62 | }, 63 | ] 64 | }, 65 | { 66 | name: 'Design', 67 | image: assets.home.myLatestProject.figma, 68 | data: [ 69 | { 70 | slug: 'portfolio-web-design', 71 | title: 'Portfolio Web Design', 72 | image: assets.home.myLatestProject.projects.portfolioWebsite, 73 | repositoryUrl: "https://www.figma.com/file/TYBBBbA5cvBN4QU70hNxvr/DK-PORTFOLIO?type=design&node-id=49%3A26&t=3Bwr9eEa8OLH9C0R-1", 74 | demoUrl: "https://www.figma.com/proto/TYBBBbA5cvBN4QU70hNxvr/DK-PORTFOLIO?page-id=0%3A1&type=design&node-id=49-26&viewport=-226%2C241%2C0.42&scaling=min-zoom", 75 | }, 76 | ], 77 | }, 78 | ]; 79 | 80 | tabs.push({ 81 | name: 'More', 82 | image: assets.home.myLatestProject.rocket, 83 | data: [] 84 | }); 85 | 86 | export default function SectionMyLatestProject() { 87 | const [activeTab, setActiveTab] = useState(0); 88 | 89 | const { ref, inView } = useInView({ 90 | threshold: 0.1, 91 | triggerOnce: true, 92 | }); 93 | 94 | const router = useRouter(); 95 | 96 | useEffect(() => { 97 | const urlParams = new URLSearchParams(window.location.search); 98 | const tab = urlParams.get('tab'); 99 | if (tab && parseInt(tab) < tabs.length - 1) { 100 | setActiveTab(parseInt(tab)); 101 | } 102 | }, [activeTab]) 103 | 104 | return ( 105 |
106 |
107 | My Latest Project 108 | Take a look at something I've worked on, such as a case study, real project, and more 109 |
110 |
111 |
112 |
113 | {tabs.map((tab, index) => ( 114 | { 121 | if (index === tabs.length - 1) { 122 | router.push('/project'); 123 | return; 124 | } 125 | setActiveTab(index); 126 | window.history.pushState({}, '', `?tab=${index}`); 127 | }} 128 | whileHover={{ scale: 1.05 }} 129 | whileTap={{ scale: 0.95 }} 130 | > 131 | 138 |
139 |

{tab.name}

140 |
141 |
142 | 143 | ))} 144 |
145 |
146 |
147 |
148 | {tabs.map((tab, tabIndex) => 149 | tab.data.map((item, dataIndex) => 150 | activeTab === tabIndex && ( 151 | 160 |
161 | 167 | 175 | 176 |
177 |
178 |
179 |

{item.title}

180 |
181 | {item.repositoryUrl && ( 182 | 195 | {tabs[activeTab].name.toLowerCase() === "project" ? ( 196 | 197 | ) : ( 198 | 199 | )} 200 | 201 | )} 202 | {item.demoUrl && ( 203 | 216 | 217 | 218 | )} 219 | 220 | 221 | 222 |
223 |
224 |
225 |
226 | ) 227 | ) 228 | )} 229 |
230 |
231 |
232 |
233 |
234 |
235 | ) 236 | } 237 | -------------------------------------------------------------------------------- /app/SectionQuote.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from 'react' 4 | import { motion } from "framer-motion"; 5 | import { useInView } from 'react-intersection-observer'; 6 | import Image from 'next/image'; 7 | import { assets } from '@/constant/assets'; 8 | import { suarte } from '@/constant/font'; 9 | import styles from "./home.module.css"; 10 | 11 | const AnimatedImage = motion(Image); 12 | 13 | export default function SectionQuote() { 14 | const { ref, inView } = useInView({ 15 | threshold: 0.1, 16 | triggerOnce: true, 17 | }); 18 | 19 | const animatedFloatingImages = [ 20 | { 21 | className: "absolute -z-10 -top-20 left-10 md:left-36 lg:left-48 lg:-top-24 w-[70px] h-[70px] lg:w-[100px] lg:h-[100px]", 22 | src: assets.home.quote.teaCup, 23 | width: 100, 24 | height: 100, 25 | alt: '', 26 | initial: { y: 50, x: -50, opacity: 0 }, 27 | animate: inView ? { y: 0, x: 0, opacity: 1 } : {}, 28 | transition: { duration: 0.5, delay: 0.2 }, 29 | }, 30 | { 31 | className: "absolute -z-10 -top-20 right-10 md:right-36 lg:right-48 lg:-top-24 w-[70px] h-[70px] lg:w-[100px] lg:h-[100px]", 32 | src: assets.home.quote.bulb, 33 | width: 100, 34 | height: 100, 35 | alt: '', 36 | initial: { y: 50, x: 50, opacity: 0 }, 37 | animate: inView ? { y: 0, x: 0, opacity: 1 } : {}, 38 | transition: { duration: 0.5, delay: 0.4 }, 39 | }, 40 | { 41 | className: "absolute -z-10 -bottom-40 md:-bottom-20 left-8 md:left-32 lg:-bottom-24 xl:left-72 w-[70px] h-[70px] lg:w-[100px] lg:h-[100px]", 42 | src: assets.home.quote.paintKit, 43 | width: 100, 44 | height: 100, 45 | alt: '', 46 | initial: { y: 50, x: -50, opacity: 0 }, 47 | animate: inView ? { y: 0, x: 0, opacity: 1 } : {}, 48 | transition: { duration: 0.5, delay: 0.6 }, 49 | }, 50 | { 51 | className: "absolute -z-10 -bottom-36 md:-bottom-20 right-8 md:right-28 xl:right-72 w-[70px] h-[70px] lg:w-[100px] lg:h-[100px]", 52 | src: assets.home.quote.heart, 53 | width: 100, 54 | height: 100, 55 | alt: '', 56 | initial: { y: 50, x: 50, opacity: 0 }, 57 | animate: inView ? { y: 0, x: 0, opacity: 1 } : {}, 58 | transition: { duration: 0.5, delay: 0.8 }, 59 | } 60 | ]; 61 | 62 | return ( 63 |
64 |
65 | 66 | This portfolio was made with heart and soul, pouring passion and creativity into every detail to bring it to life. It's not just a portfolio, it's a labor of love. 67 | 68 | 69 | {animatedFloatingImages.map((item, index) => ( 70 | 71 | ))} 72 |
73 | 74 | Deri kurniawan 75 | 76 |
77 | ) 78 | } 79 | -------------------------------------------------------------------------------- /app/SectionTechnologyStack.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { assets } from '@/constant/assets' 4 | import Image from 'next/image' 5 | import React from 'react' 6 | import { motion } from "framer-motion"; 7 | import { useInView } from 'react-intersection-observer'; 8 | import Link from 'next/link'; 9 | import styles from "./home.module.css"; 10 | 11 | const technologyStack = [ 12 | { 13 | name: 'Next JS', 14 | image: assets.home.technologyStack.nextJs, 15 | officialSite: 'https://nextjs.org/', 16 | }, 17 | { 18 | name: 'Laravel', 19 | image: assets.home.technologyStack.laravel, 20 | officialSite: 'https://laravel.com/', 21 | }, 22 | { 23 | name: 'Expo', 24 | image: assets.home.technologyStack.expo, 25 | officialSite: 'https://expo.dev/', 26 | }, 27 | { 28 | name: 'Prisma', 29 | image: assets.home.technologyStack.prisma, 30 | officialSite: 'https://www.prisma.io/', 31 | }, 32 | { 33 | name: "Express JS", 34 | image: assets.home.technologyStack.expressJs, 35 | officialSite: 'https://expressjs.com/', 36 | }, 37 | { 38 | name: "Planet Scale", 39 | image: assets.home.technologyStack.planetScale, 40 | officialSite: 'https://planetscale.com/', 41 | }, 42 | { 43 | name: "Javascript", 44 | image: assets.home.technologyStack.javascript, 45 | officialSite: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript', 46 | }, 47 | { 48 | name: "React JS", 49 | image: assets.home.technologyStack.reactJs, 50 | officialSite: 'https://reactjs.org/', 51 | }, 52 | { 53 | name: "Tailwind CSS", 54 | image: assets.home.technologyStack.tailwindCss, 55 | officialSite: 'https://tailwindcss.com/', 56 | }, 57 | { 58 | name: "React Native", 59 | image: assets.home.technologyStack.reactNative, 60 | officialSite: 'https://reactnative.dev/', 61 | }, 62 | { 63 | name: "Typescript", 64 | image: assets.home.technologyStack.typescript, 65 | officialSite: 'https://www.typescriptlang.org/', 66 | } 67 | ] 68 | 69 | export default function SectionTechnologyStack() { 70 | const { ref, inView } = useInView({ 71 | threshold: 0.1, 72 | triggerOnce: true, 73 | }); 74 | 75 | return ( 76 |
77 |
78 | Technology Stack 79 | I are concerned about security and performance for my client. That's why I always keep updating and use best technologies in a product 80 |
81 |
82 |
83 | {technologyStack.map((item, index) => ( 84 |
85 | 93 | {item.name} 100 | 112 |
113 |

114 | {item.name} 115 |

116 |
117 | 118 |
119 |
120 | ))} 121 |
122 |
123 |
124 | ) 125 | } 126 | -------------------------------------------------------------------------------- /app/blog/page.tsx: -------------------------------------------------------------------------------- 1 | export default function Blog() { 2 | return ( 3 |
4 |
5 |

Blog

6 |

Under Development

7 |
8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Deri-Kurniawan/3d-portfolio/3c74b8f47e152eac3adf6e798518486b6a502886/app/favicon.ico -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | html { 7 | @apply font-poppins; 8 | } 9 | 10 | body > div { 11 | @apply overflow-x-hidden; 12 | } 13 | 14 | /* remove highlight */ 15 | * { 16 | -webkit-tap-highlight-color: transparent; 17 | } 18 | } 19 | 20 | @layer utilities { 21 | .safe-layout { 22 | max-width: 1440px !important; 23 | margin: 0 auto !important; 24 | } 25 | 26 | .safe-x-padding { 27 | @apply px-[20px] md:px-[50px] lg:px-[120px]; 28 | } 29 | 30 | .gradient-text { 31 | @apply text-transparent bg-gradient-to-r from-primary to-secondary bg-clip-text; 32 | } 33 | 34 | .gradient-bg { 35 | @apply bg-gradient-to-r from-primary to-secondary; 36 | } 37 | 38 | .gradient-btn { 39 | @apply bg-gradient-to-r from-primary to-secondary; 40 | position: relative; 41 | color: #fff; 42 | border: none; 43 | overflow: hidden; 44 | z-index: 1; 45 | transition: all 0.3s ease-in-out; 46 | box-shadow: 0 6px 10px rgba(0, 0, 0, 0.1); 47 | } 48 | } 49 | 50 | /* Start of gradient button */ 51 | .gradient-btn:hover { 52 | transform: scale(1.05); 53 | color: #fff; 54 | box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); 55 | } 56 | .gradient-btn:active { 57 | transform: scale(0.9); 58 | } 59 | .gradient-btn::before { 60 | @apply bg-gradient-to-l from-secondary to-primary rounded-lg absolute -z-[1] top-0 -left-full w-full h-full transition-all duration-500 ease-in-out; 61 | content: ""; 62 | } 63 | .gradient-btn:hover::before { 64 | left: 0; 65 | } 66 | /* End of gradient button */ 67 | 68 | /* Start of Mobile & Tablet Hamburger */ 69 | .hamburger svg { 70 | @apply w-[40px]; 71 | transition: transform 600ms cubic-bezier(0.4, 0, 0.2, 1); 72 | } 73 | .hamburger svg > path.line { 74 | @apply stroke-secondary fill-none; 75 | stroke-linecap: round; 76 | stroke-linejoin: round; 77 | stroke-width: 3; 78 | transition: stroke-dasharray 600ms cubic-bezier(0.4, 0, 0.2, 1), 79 | stroke-dashoffset 600ms cubic-bezier(0.4, 0, 0.2, 1); 80 | } 81 | .hamburger svg > path.line-top-bottom { 82 | stroke-dasharray: 12 63; 83 | } 84 | .hamburger input:checked + svg { 85 | @apply -rotate-[45deg]; 86 | } 87 | .hamburger input:checked + svg .line-top-bottom { 88 | stroke-dasharray: 20 300; 89 | stroke-dashoffset: -32.42; 90 | } 91 | /* End of Mobile & Tablet Hamburger */ 92 | -------------------------------------------------------------------------------- /app/home.module.css: -------------------------------------------------------------------------------- 1 | /* Components */ 2 | .__gradientText { 3 | @apply text-transparent bg-gradient-to-r from-primary to-secondary bg-clip-text; 4 | } 5 | /* End of components */ 6 | 7 | .sectionTitle { 8 | @apply mb-6 text-4xl font-extrabold md:text-5xl lg:text-6xl font-montserrat __gradientText; 9 | } 10 | 11 | .sectionDescription { 12 | @apply text-base font-medium md:text-xl lg:text-2xl text-accent; 13 | } 14 | 15 | .creatorQuotes { 16 | @apply font-medium text-base md:text-xl leading-[38px] lg:text-2xl text-accent max-w-[933px] mx-auto text-justify; 17 | } 18 | 19 | .creatorQuotesName { 20 | @apply font-medium text-6xl lg:text-7xl text-accent text-center mt-[20px]; 21 | } 22 | 23 | .sectionDistance { 24 | @apply my-[172px]; 25 | } 26 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import { montserrat, poppins } from '@/constant/font' 2 | import './globals.css' 3 | import Navbar from '../components/Navbar' 4 | 5 | export const metadata = { 6 | title: "Home - Portfolio", 7 | description: 'Deri Kurniawan Portfolio', 8 | } 9 | 10 | export default function RootLayout({ 11 | children, 12 | }: { 13 | children: React.ReactNode 14 | }) { 15 | return ( 16 | 17 | 18 | 19 | {children} 20 | 21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import Footer from "../components/Footer"; 2 | import SectionHero from "./SectionHero"; 3 | import SectionLetsConnect from "./SectionLetsConnect"; 4 | import SectionMyLatestProject from "./SectionMyLatestProject"; 5 | import SectionQuote from "./SectionQuote"; 6 | import SectionTechnologyStack from "./SectionTechnologyStack"; 7 | 8 | export default function Home() { 9 | return ( 10 |
11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /app/project/layout.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Footer from '@components/Footer' 3 | 4 | export default function ProjectLayout({ 5 | children 6 | }: { 7 | children: React.ReactNode 8 | }) { 9 | return ( 10 | <> 11 | {children} 12 |