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 dev
Open 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@latest
as it says in https://nextjs.org/ - run
npm run dev
- delete
favicon.ico
in theapp
folder - clear the styles in
app\globals.css
- set the metadata in
app\layout.tsx
- in
app\page.tsx
, delete everything with thereturn
of 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
rafce
to 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 + K
to 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
spotlight
to 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
utils
folder & add a newcn.ts
file & in there paste the code you copied before
- below "Copy the source code", copy the code for
components/ui/Spotlight.tsx
- inside of the
components
folder, create a newui
folder, inside of which you create a new file calledSpotlight.tsx
& paste what you just copied
- below "Copy the highlighted
spotlight
animation intotailwind.config.js
file", 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 thisflattenColorPalette
intailwind.config.js
by 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.js
file with the code you just copied
- do the same thing for
app\globals.css
- install all the dependencies required in the updated
tailwind.config.ts
file, so in your terminal, run:npm install mini-svg-data-uri
npm install tailwindcss-animate
- use the
<Spotlight />
component withincomponents\Hero.tsx
inside 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
Code
to 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-themes
available 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-themes
in 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
defaultTheme
to"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.span
CSS class dynamic to turn the "Experiences" word into purple - a bit down, replace
mt-4
withmy-4
- remove the
text-2xl
CSS class to make the text in thewords
bigger
- 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
ui
folder, create a new component calledMagicButton.tsx
& create a new React component with help of therafce
shortcut - 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>
title
icon
- use React Icons https://react-icons.github.io/react-icons/ to render some icons by installing
react-icons
https://www.npmjs.com/package/react-icons by runningnpm i react-icons
in your terminal - use it by setting some
FaLocationArrow
imported fromreact-icons/fa6
to theicon
prop
- use React Icons https://react-icons.github.io/react-icons/ to render some icons by installing
position
set 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
ui
folder, 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 thenavItems
prop like it says in the docs under "Props"
- in the
components
folder, add a newGrid.tsx
component- in there, use the
rafce
shortcut - 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
ui
folder, 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
& anid
field - 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
BentoGridItem
component incomponents\ui\BentoGrid.tsx
- modify some CSS classes
- accept the
id
prop
- 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
data
folder & inside of it, create a newindex.ts
file - in there, declare the array of grid item by cutting it from
components\Grid.tsx
& storing it in agridItems
constant - back in
components\Grid.tsx
, import thegridItems
constant & 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.md
of the original project https://github.com/adrianhajdin/portfolio/blob/main/README.md - click on
Code to Copy
to 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.ts
file - then, under
Assets
, click onhere
to download thepublic
folder - delete your
public
folder & 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 theBentoGridItem
component so that you can put them to use - properly style this
BentoGridItem
according to those props so that the cards look nice- add a new
style
attribute with somebackground
color &backgroundColor
gradient 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 Animation
from 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
ui
folder, add a newGradientBg.tsx
file & 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 & anotherdiv
with 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
ui
folder, create a newGlobe.tsx
file & paste in there the code you just copied - in your terminal, install all the required packages & files from this code
- add the
data/globe.json
file- 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
data
folder, create a newglobe.json
file & 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
Code
to switch over the code & copy the code - in the
ui
folder, add a newGridGlobe.tsx
file which would be the representation of theGlobe
component within the grid - in there, paste the code you just copied which contain the code for the
globeConfig
prop we need & import theGlobe
from'./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-lottie
package & also installing its types by runningnpm i --save-dev @types/react-lottie
- in this inner
<div>
, output the<Lottie />
component & give it someoptions
prop which contains an object ofloop
property, which is going to loop only when we copy the email, so create acopied
state because you need to have access to the state of copied & set this field tocopied
autoplay
which also has acopied
valueanimationData
with a value ofanimationData
which would be another JSON object to add to yourdata
folder- so, in the
data
folder, create a newconfetti.json
file - 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
rendererSettings
object, which you can add to it a specialpreserveAspectRatio
with 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
handleClick
prop which trigger ahandleCopy
function - 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 aonClick
prop that points at thishandleClick
function - back to
components\ui\GradientBg.tsx
, replaceh-screen w-screen relative
withh-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.tsx
file - run
racfe
to create aRecentProjects
component - in
app\page.tsx
, output the<RecentProjects />
component
- under
- in
data\index.ts
, customize theprojects
array to really make it your projects - customize
RecentProjects.tsx
- set a
h1
heading - render a list of your projects by adding
import { projects } from '@/data';
& mapping theprojects
- output another Aceternity UI component
3D Animated Pin
which 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 code
forcomponents/ui/3d-pin.tsx
, copy the code below - then in
components/ui
, add a new3d-pin.tsx
file & paste the code you just copied in there - go back to
components\RecentProjects.tsx
& use this<PinContainer>
component - go to
components\ui\3d-pin.tsx
to 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
& thebottom
of 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
Login
button - modify some CSS classes to customize the styles of the navbar
- remove the
- in
components\RecentProjects.tsx
, make theProjects
navbar 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.js
as 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.local
file & paste the provided token in there
- copy the provided
- click
Connect to my central instance
orView Issues
to get redirected tohttps://<your-project>.sentry.io/issues/
& see theIssues
- in your project, a
sentry-example-page
folder with apage.jsx
file 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
Issues
dashboard in sentry.io - click on this
Error
to 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.feedbackIntegration
in thesentry.client.config.js
file within your code & set thecolorScheme
todark
- go back to http://localhost:3000/ & refresh the page to see the
Report a Bug
button
- click
- under
components
, create a newClients.tsx
file & 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.tsx
file & 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.tsx
file - 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.tsx
file- 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.tsx
file - 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
AceternityIcon
function & return a Magic Button from Aceternity UI - update the
Card
function
- 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.tsx
file - in
app\page.tsx
, output<Footer />
- in
app\page.tsx
, removeoverflow-hidden
so that the page is not cut off when scrolling back up after clicking the nav buttons - instead add
overflow-clip
to 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
, setoutput
to'export'
&typescript: {ignoreBuildErrors: true}
- remove the
app/sentry-example-page
& theapp/api
folders - in your terminal, run
npm run build
- right click the
out
folder & 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