This is a Next.js project bootstrapped with create-next-app.
First, run the development server:
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun devOpen http://localhost:3000 with your browser to see the result.
You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.
This project uses next/font to automatically optimize and load Inter, a custom Google Font.
To learn more about Next.js, take a look at the following resources:
- Next.js Documentation - learn about Next.js features and API.
- Learn Next.js - an interactive Next.js tutorial.
You can check out the Next.js GitHub repository - your feedback and contributions are welcome!
The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.
Check out our Next.js deployment documentation for more details.
- in your terminal, run
npx create-next-app@latestas it says in https://nextjs.org/ - run
npm run dev - delete
favicon.icoin theappfolder - clear the styles in
app\globals.css - set the metadata in
app\layout.tsx - in
app\page.tsx, delete everything with thereturnof this page, and instead set some basic markup & Tailwind CSS classes - install
Tailwind CSS IntelliSense&ES7+ - customize your Tailwing CSS config by reffering your Figma design https://resource.jsmastery.pro/minimal-portfolio
- in
tailwind.config.ts, add your first custom color by extending your actual theme - go back to
app\page.tsx& refer to that customized color
Build a top title, a primary title, a subtitle & the call to action button to show your work
- in the root of your directory, create a new folder called
components - within this folder, create a new file called
Hero.tsx - in this file, type
rafceto quickly create aHome()component function (feature fromES7+ React/Redux/React-Native snippets) - in
app\page.tsx, output the<Hero />component imported fromcomponents\Hero.tsx - back to
components\Hero.tsx, set some classes to the<div> - inside that
<div>create another<div>acting as a wrapper for your first components coming from Aceternity to add the spotlight effects available in your Figma design in desktop version - here are examples on how to use a nice search feature to find exactly what you're looking for quickly:
- Aceternity:
- go to https://ui.aceternity.com/ & press
Ctrl + Kto open up a search no matter where on the page you are - search for
spotlight& pressEnter - you'll get redirected to https://ui.aceternity.com/components/spotlight
- NextJS:
- go to https://nextjs.org/docs & press
Ctlr + K - search for
server actions& pressEnter - there you are https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#convention
- then press
Ctrl + F& search foruse server
- so, back to Aceternity, look for
spotlightto reach out to https://ui.aceternity.com/components/spotlight- below "Install dependencies", copy
npm i framer-motion clsx tailwind-merge
- in your terminal, run
npm i framer-motion clsx tailwind-merge
- below "Add util file", copy the code for
utils/cn.ts
- in the root of your project, add a new
utilsfolder & add a newcn.tsfile & in there paste the code you copied before
- below "Copy the source code", copy the code for
components/ui/Spotlight.tsx
- inside of the
componentsfolder, create a newuifolder, inside of which you create a new file calledSpotlight.tsx& paste what you just copied
- below "Copy the highlighted
spotlightanimation intotailwind.config.jsfile", copy the code
- in
tailwind.config.js, paste the code you just copied to override the content
- press
Ctrl + K& search forAdd utilities, you'll see that you have to add thisflattenColorPaletteintailwind.config.jsby overriding the code in yourtailwind.config.js
- below "Install dependencies", copy
- since you will be continuing overriding some files, use the provided code in the open source GitHub repository
tailwind.config.ts
- go to https://github.com/adrianhajdin/portfolio?tab=readme-ov-file#snippets
- then copy the code below
tailwind.config.ts - override the content of your
tailwind.config.jsfile with the code you just copied
- do the same thing for
app\globals.css
- install all the dependencies required in the updated
tailwind.config.tsfile, so in your terminal, run:npm install mini-svg-data-urinpm install tailwindcss-animate
- use the
<Spotlight />component withincomponents\Hero.tsxinside the previously added<div> - pass some native Tailwind CSS classes to this
<Spotlight>component &fill="white" - duplicate this component 2 more times & change their styles
- right below the
<div>that contains this spotlight, create another<div>that will act as a UI grid- for that, you'll use a component called "Grid and Dot Backgrounds" from https://ui.aceternity.com/components/grid-and-dot-backgrounds
- click on
Codeto switch over the code & copy the 2<div>s with the<p>tag in between & paste it there - modify a couple of classes of this code
- use a theme provider which is a package called
next-themesavailable in https://www.npmjs.com/package/next-themes to switch the background to dark- in your terminal, run
npm i next-themes - google "next themes" & click on "Next.js - shadcn/ui" to go to https://ui.shadcn.com/docs/dark-mode/next & follow this setup
- like we did above, you have to "Install next-themes" by running
npm install next-themesin your terminal - Create a theme provider
- copy the provided code
- go to
app& create a new file calledprovider.tsx - in there, paste the code you just copied
- Wrap your root layout
- copy the
<ThemeProvider>layout - go to
app\layout.tsx& wrap your{children}with it & import{ ThemeProvider }from./provider - set the
defaultThemeto"dark"
- like we did above, you have to "Install next-themes" by running
- in your terminal, run
- go back to
components\Hero.tsx- add a new
<div>that will wrap your heading below the<div>containing your grid & give it some CSS classes - inside of it, add an inner
<div>with some CSS classes - and in it, render an
<h2>that would say "Dynamic Web Magic with Next.js" - make this
<h2>text appear over the grid by setting the grid to a position ofabsolute& less noticable by giving a background color ofdark:bg-grid-white/[0.05]
- add a new
- below this
<h2>, render your primary text & give it its animation- go back to Aceternity UI & search for
Text Generate Effect - you will be redirected to https://ui.aceternity.com/components/text-generate-effect
- Copy the source code for
components/ui/text-generate-effect.tsx - inside
components\ui, add a new file calledTextGenerateEffect.tsx& paste in there the code you just copied - go back to
components\Hero.tsx& use this<TextGenerateEffect />& pass to it 2 propsclassName&words
- go back to Aceternity UI & search for
- below this
<TextGenerateEffect />output a<p>tag to add the subtitle - go back to
components\ui\TextGenerateEffect.tsx, modify some of the content- make the
motion.spanCSS class dynamic to turn the "Experiences" word into purple - a bit down, replace
mt-4withmy-4 - remove the
text-2xlCSS class to make the text in thewordsbigger
- make the
- like in the Figma design, implement the "Show my Work" button
- go back to Aceternity & finc
Tailwind CSS buttons - you'll reach https://ui.aceternity.com/components/tailwindcss-buttons
- in there, copy the "Border Magic" button
- within the
uifolder, create a new component calledMagicButton.tsx& create a new React component with help of therafceshortcut - paste the code you just copied in there
- go to
components\Hero.tsx& render the<MagicButton />component in there - in
components\ui\MagicButton.tsx, make the button more dynamic with help of props to render some dynamic content & updated some of the CSS classes - go to
components\Hero.tsx& render some props to<MagicButton>titleicon- use React Icons https://react-icons.github.io/react-icons/ to render some icons by installing
react-iconshttps://www.npmjs.com/package/react-icons by runningnpm i react-iconsin your terminal - use it by setting some
FaLocationArrowimported fromreact-icons/fa6to theiconprop
- use React Icons https://react-icons.github.io/react-icons/ to render some icons by installing
positionset toright
- go back to Aceternity & finc
- add the navigation bar
- go to Aceternity & find "Floating Navbar"
- you'll be redirected to https://ui.aceternity.com/components/floating-navbar
- copy the source code for
components/ui/floating-navbar.tsx - within the
uifolder, create a new component calledFloatingNav.tsx - paste in there the code you just copied
- go to
app\page.tsx& output the<FloatingNav />component & pass to it thenavItemsprop like it says in the docs under "Props"
- in the
componentsfolder, add a newGrid.tsxcomponent- in there, use the
rafceshortcut - in
app\page.tsx, import that<Grid />component
- in there, use the
- use another Aceternity component called "Bento Grid"
- got to https://ui.aceternity.com/ & search for "Bento Grid"
- you'll get redirected to https://ui.aceternity.com/components/bento-grid
- copy the source code related to
components/ui/bento-grid.tsx - in the
uifolder, creater a new component calledBentoGrid.tsx - in there, paste the code you just copied
- in
components\Grid.tsx, import the 2<BentoGrid>&<BentoGridItem>components available incomponents\ui\BentoGrid.tsx
- inside
<BentoGrid>, render an array in which you add an object with atitle& adescription& anidfield - map this array & return in it the
<BentoGridItem>component - add to this
<BentoGridItem>the required couple of props according to the docs under "Props"
- to render the grid according to your design, modify the content of the
BentoGridItemcomponent incomponents\ui\BentoGrid.tsx
- modify some CSS classes
- accept the
idprop
- outsource the data in a different folder & component to render different grid items in a more optimized way
- within the root folder, create a new
datafolder & inside of it, create a newindex.tsfile - in there, declare the array of grid item by cutting it from
components\Grid.tsx& storing it in agridItemsconstant - back in
components\Grid.tsx, import thegridItemsconstant & map it like you did before
- within the root folder, create a new
- since your project will contain a lot of data, so to save you some time
- go to the
README.mdof the original project https://github.com/adrianhajdin/portfolio/blob/main/README.md - click on
Code to Copyto reach out to this page https://github.com/adrianhajdin/portfolio/blob/main/README.md#snippets - then go to
data/index.ts& copy the code & paste in yourdata\index.tsfile - then, under
Assets, click onhereto download thepublicfolder - delete your
publicfolder & replace it with the new downloaded one
- go to the
- following the step 2, customize the bento grid items & make them as nice as the Figma design
- in
components\Grid.tsx, add some more props to the<BentoGridItem> - in
components\ui\BentoGrid.tsx, accept those props nicely in theBentoGridItemcomponent so that you can put them to use - properly style this
BentoGridItemaccording to those props so that the cards look nice- add a new
styleattribute with somebackgroundcolor &backgroundColorgradient provided from https://github.com/adrianhajdin/portfolio/blob/main/README.md#snippets underLinear Gradient - below it, create a new
<div>& inside of it add- an inner
<div>with some CSS classes & an<img />in it - another
<div>for the secondary image - another
<div>only for the sixth item to render an animation calledBackground Gradient Animationfrom Aceternity UI- go to https://ui.aceternity.com/ & search for "Gradient Animation"
- you'll get redirected to https://ui.aceternity.com/components/background-gradient-animation
- copy the source code for
components/ui/background-gradient-animation.tsx - in the
uifolder, add a newGradientBg.tsxfile & paste the code you just copied in there - use this
<BackgroundGradientAnimation>component in this inner<div> - and between this component, render a self closing
<div>with some CSS classes - in
components\ui\GradientBg.tsx, properly import{cn}
- another
<div>with some CSS classes & anotherdivwith some CSS classes & inside of it some{description} - right below it, render your
{title}with some CSS classes
- an inner
- all of those grid items have to have some unique design, so add these special elements for each one of the cards
- start with this
three-globe, which would be another Aceternity component, for the second card- go to https://ui.aceternity.com/ & search for "GitHub Globe"
- you will be redirected to https://ui.aceternity.com/components/github-globe
- copy the source code for
components/ui/globe.tsx - in the
uifolder, create a newGlobe.tsxfile & paste in there the code you just copied - in your terminal, install all the required packages & files from this code
- add the
data/globe.jsonfile- go to https://ui.aceternity.com/components/github-globe, under
Copy the globe json& click onDownload the globe.json file from this URL - you'll be redirected to https://gist.github.com/manuarora700/4f03b7767a9431f2589c14c47377328a
- click on the little icon to "display the source blob"
- you'll be redirected to https://gist.github.com/manuarora700/4f03b7767a9431f2589c14c47377328a?short_path=7ed1be6
- from there, go to the "raw file" & copy the code
- in the
datafolder, create a newglobe.jsonfile & paste the code you just copied in there
- go to https://ui.aceternity.com/components/github-globe, under
- install Globe dependencies
- go to https://ui.aceternity.com/components/github-globe, under
Install Globe dependencies& copy the command - in your terminal, paste that command
- go to https://ui.aceternity.com/components/github-globe, under
- add the
- go to
components\ui\BentoGrid.tsx, below the<div>that wraps thedescription& thetitle- use
<GridGlobe>component importedfrom './GridGlobe'for the second grid item card - check the requiered props in the docs in the "Props" section https://ui.aceternity.com/components/github-globe
- at the top of this page, click on
Codeto switch over the code & copy the code - in the
uifolder, add a newGridGlobe.tsxfile which would be the representation of theGlobecomponent within the grid - in there, paste the code you just copied which contain the code for the
globeConfigprop we need & import theGlobefrom'./Globe' - go to
components\ui\GridGlobe.tsx, in theGridGlobe()function component to customize it as we want it by cleaning it - go back to
components\ui\BentoGrid.tsx, fix the styles of the container to make the globe not jump out of the card which matters a lot for all these elements of each one of the cards
- use
- focus on the fourth card, the
id 3, which would be the Tech Stack list- in
components\ui\BentoGrid.tsx, below where you rendered the second card, add a<div>with some CSS classes - inside of it, render the Tech text in another
<div>with some CSS classes - inside of it, create an array of left side items & map over it & give it a key & some CSS classes & render each item in a
<span> - below this left side maping, create another
<span>with some CSS classes for the empty list item with a background color - duplicate the
<div>containing this left list & paste it below it & change some of the tech & move the<span>for the empty list item above the mapped list
- in
- customize the card with the
id 6, which is the one with the gradient in which the user will be able to copy your email- below the content for the
id 3, add some dynamic content & an outer & inner<div>with some CSS classes - inside this inner
<div>, render a lottie animation- by installing the
react-lottiepackage & also installing its types by runningnpm i --save-dev @types/react-lottie - in this inner
<div>, output the<Lottie />component & give it someoptionsprop which contains an object ofloopproperty, which is going to loop only when we copy the email, so create acopiedstate because you need to have access to the state of copied & set this field tocopiedautoplaywhich also has acopiedvalueanimationDatawith a value ofanimationDatawhich would be another JSON object to add to yourdatafolder- so, in the
datafolder, create a newconfetti.jsonfile - go to https://github.com/adrianhajdin/portfolio/blob/main/data/confetti.json & copy the code
- paste it in the newly added file
- so, in the
rendererSettingsobject, which you can add to it a specialpreserveAspectRatiowith a value of'xMidYMid slice'
- by installing the
- make it a
'use client'component, because you used auseState() - below the Lottie animation, add a
<MagicButton>to trigger the animation- pass some props to it & a
handleClickprop which trigger ahandleCopyfunction - declare the
handleCopy()function
- pass some props to it & a
- make the button work when clicking & set the gradient as a background
- in
components\ui\MagicButton.tsx, add aonClickprop that points at thishandleClickfunction - back to
components\ui\GradientBg.tsx, replaceh-screen w-screen relativewithh-full w-full absolute
- in
- below the content for the
- start with this
- add a new
- in
This section on your list will be what your portfolio is all about which is displaying the recent projects you worked on using this very engaging card that folds back and allows you to visit the live website that you're seeing on the screen This is a very cool effect, so let's go ahead and implement it now
- create a new section called "Recent Projects"
- under
components, create a newRecentProjects.tsxfile - run
racfeto create aRecentProjectscomponent - in
app\page.tsx, output the<RecentProjects />component
- under
- in
data\index.ts, customize theprojectsarray to really make it your projects - customize
RecentProjects.tsx- set a
h1heading - render a list of your projects by adding
import { projects } from '@/data';& mapping theprojects - output another Aceternity UI component
3D Animated Pinwhich will pin on these project cards- go to https://ui.aceternity.com/ & search for "3D Pin"
- you'll get redirected to https://ui.aceternity.com/components/3d-pin
- under
Copy the source codeforcomponents/ui/3d-pin.tsx, copy the code below - then in
components/ui, add a new3d-pin.tsxfile & paste the code you just copied in there - go back to
components\RecentProjects.tsx& use this<PinContainer>component - go to
components\ui\3d-pin.tsxto customize this<PinContainer> - back to
components\RecentProjects.tsx, customize this<PinContainer>component by- passing some props to it
- adding a children inside of it for the
title, thedescription& thebottomof the cards
- set a
- implement the links of the floating navbar so that the user can scroll down to the projects section
- go back to the original home page
app\page.tsx- remove the array in the
<FloatingNav>component - use the constant
{navItems}comingfrom '@/data'
- remove the array in the
- go to
components\ui\FloatingNav.tsx- remove the
Loginbutton - modify some CSS classes to customize the styles of the navbar
- remove the
- in
components\RecentProjects.tsx, make theProjectsnavbar link point to the "Projects" section by addingid="projects"
- go back to the original home page
With this many features completed on your developer portfolio, it's important to ensure a smooth user experience, optimized performance and just in general showcasing that you're using all the best practices of developing applications.
- For that reason, let's use Sentry, an Enterprise level application Sentry monitoring software that allows you to fix your portfolio very quickly if it breaks.
- And specifically in this case, let's also enable your users to share when they experience something unexpected with the site. So, for that, you'll integrate a "Report a Bug" model that will allow them to provide you direct feedback.
So, let's get started with integrating Sentry
- go to https://sentry.io/welcome/
- create a new account with your GitHub account
- click
Install Sentry - choose
Next.jsas your framework - click
Configure SDK - copy the command & paste it in your terminal to install the Sentry wizard
- copy the provided
SENTRY_AUTH_TOKEN - in your project root directory, create a new
.env.localfile & paste the provided token in there
- copy the provided
- click
Connect to my central instanceorView Issuesto get redirected tohttps://<your-project>.sentry.io/issues/& see theIssues - in your project, a
sentry-example-pagefolder with apage.jsxfile are created- copy
sentry-example-page& paste it to your site URL, like this http://localhost:3000/sentry-example-page - click
Throw Error
- copy
- you should be able to see this error in your
Issuesdashboard in sentry.io - click on this
Errorto analyze it - you can use a lot features, like
Queries,Requests,Web Vitals, and especially in this case,User Feedback- click
User Feedback - click
Set Up Now - if you haven't install the sentry wizard, copy the command & back to your terminal, paste this command
- add the special integration called
Sentry.feedbackIntegrationin thesentry.client.config.jsfile within your code & set thecolorSchemetodark - go back to http://localhost:3000/ & refresh the page to see the
Report a Bugbutton
- click
- under
components, create a newClients.tsxfile & runrafce& add your customized content<h1>- cards provided from Aceternity UI
- go to https://ui.aceternity.com/ & search for
Infinite Moving Cards - you'll get redirected to https://ui.aceternity.com/components/infinite-moving-cards
- Copy the source code for
components/ui/infinite-moving-cards.tsx - in
components/ui, create a newInfiniteMovingCards.tsx - paste the code you just copied in there
- at the top of this file, fix the path for the
{ cn }import - in
components\Clients.tsx, output the<InfiniteMovingCards />component & set to it all the required props - go to
components\ui\InfiniteMovingCards.tsx& style those cards to your liking - go back to
components\Clients.tsx& add a div to wrap the companies
- go to https://ui.aceternity.com/ & search for
- go to
app\page.tsx& output<Clients />
- under
components, create a newExperience.tsxfile & in there- run
rafce - add your customized content
<h1>- cards with a
<Button>provided by Aceternity UI- go to https://ui.aceternity.com/ & search for
Moving Border - you'll get redirected to https://ui.aceternity.com/components/moving-border
- copy the source code for
components/ui/moving-border.tsx - in
components/ui, create a newMovingBorders.tsxfile - paste the code you just copied in there
- go back to
components\Experience.tsx& use the<Button>component imported from
- go to https://ui.aceternity.com/ & search for
- run
- go to
components\ui\MovingBorders.tsx& style theButton()component - go to
app\page.tsx& output<Experience />
- under
components, create a newApproach.tsxfile- in there, run
rafce - customize your content
- go to https://ui.aceternity.com/ & search for
Canvas Reveal Effect - you'll get redirected to https://ui.aceternity.com/components/canvas-reveal-effect
- copy the source code for
components/ui/canvas-reveal-effect.tsx - under
components/ui, create a newCanvasRevealEffect.tsxfile - in there, paste the code you just copied
- go back to https://ui.aceternity.com/components/canvas-reveal-effect & click on
Code& copy the code
- go to https://ui.aceternity.com/ & search for
- in there, run
- go to
components\Approach.tsx- paste the code you just copied
- replace
CanvasRevealEffectDemo()withApproach - update the path for the
{ CanvasRevealEffect }import - modify the data & the look & feel of these cards
- update the
AceternityIconfunction & return a Magic Button from Aceternity UI - update the
Cardfunction
- update the
- go to
app\page.tsx& output<Approach />
The next thing you can focus on is this minimalistic yet quite effective footer so let's do it next
- in
components, create a newFooter.tsxfile - in
app\page.tsx, output<Footer />
- in
app\page.tsx, removeoverflow-hiddenso that the page is not cut off when scrolling back up after clicking the nav buttons - instead add
overflow-clipto remove this extra horizontal scroll that appeared - in
components\Footer.tsx, remove the<div>containing the grid image to avoing extra space at the bottom of the page - in
components\ui\FloatingNav.tsx, fix the floating navbar for mobile view by removinghidden - in
components\Footer.tsx, add more space to the footer for mobile view & reduce some extra space for desktop view
- in
next.config.mjs, inside ofnextConfig, setoutputto'export'&typescript: {ignoreBuildErrors: true} - remove the
app/sentry-example-page& theapp/apifolders - in your terminal, run
npm run build - right click the
outfolder & clickReveal in File Explorer& copy all the files inout& paste it in your hosted website folder - go to your cPanel & go to your new URL