Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 23 additions & 20 deletions .github/workflows/integrate.yml
Original file line number Diff line number Diff line change
@@ -1,38 +1,41 @@
name: Build and Deploy

on: [push]

jobs:
build-and-deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./

steps:
- name: Checkout 🛎️
uses: actions/checkout@v2 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Cache 💾
uses: actions/cache@v2
- name: Cache Next.js
uses: actions/cache@v4
with:
path: ${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-nextjs-v3-${{ hashFiles('**/package-lock.json') }}
path: .next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}

- name: Install and Build 🔧
uses: actions/setup-node@v1
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '16'
- run: npm install
- run: npm run build
node-version: 20

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build
env:
CI: false
CI: false

- name: Deploy 🚀
- name: Deploy to GitHub Pages
if: github.ref == 'refs/heads/main'
uses: JamesIves/github-pages-deploy-action@3.6.2
uses: JamesIves/github-pages-deploy-action@v4
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages # The branch the action should deploy to.
FOLDER: out # The folder the action should deploy.
CLEAN: true # Automatically remove deleted files from the deploy branch
branch: gh-pages
folder: out
clean: true
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
lts/hydrogen
lts/krypton
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# My Portfolio
# Portfolio

Hey!
Personal portfolio built with Next.js 16, React 19, TypeScript, and Material UI v7.

This is my portfolio website made with [React.js](https://reactjs.org/), [Next.js](https://nextjs.org/) and [Material-UI](https://material-ui.com/).
Fully static and optimized for GitHub Pages.
Focused on clean UI architecture, accessibility, and maintainable code.
81 changes: 81 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from "react";
import type { Metadata } from "next";
import profileData from "@/features/profile/data/profileData";
import Providers from "@shared/ui/Providers";
import "@styles/globals.scss";

export const metadata: Metadata = {
metadataBase: new URL(profileData.meta.url),
title: profileData.meta.title,
description: profileData.about,
keywords: profileData.meta.tags.join(", "),
robots: "index, follow, noimageindex",
openGraph: {
title: profileData.meta.title,
description: profileData.about,
url: profileData.meta.url,
siteName: profileData.meta.title,
images: [
{
url: profileData.avatar,
width: 1200,
height: 630,
alt: profileData.name,
},
],
type: "profile",
},
};

interface RootLayoutProps {
children: React.ReactNode;
}

export default function RootLayout({ children }: RootLayoutProps) {
return (
<html lang="en">
<head>
{/* Favicons */}
<link
rel="apple-touch-icon"
sizes="180x180"
href="./favicons/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="./favicons/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="./favicons/favicon-16x16.png"
/>
<link rel="manifest" href="./favicons/site.webmanifest" />
<link
rel="mask-icon"
href="./favicons/safari-pinned-tab.svg"
color="#5bbad5"
/>
<meta name="msapplication-TileColor" content="#5c5236" />
<meta name="theme-color" content="#212121" />

<link rel="preconnect" href="https://fonts.googleapis.com" />

<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap" rel="stylesheet"></link>

<link
rel="stylesheet"
href="https://fonts.googleapis.com/icon?family=Material+Icons"
/>
</head>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}

86 changes: 86 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"use client";

import { Container, Typography, useMediaQuery, useTheme } from "@mui/material";
import AppBottomNavigation from "@shared/ui/AppBottomNavigation";
import Copyright from "@shared/ui/Copyright";
import Margin from "@shared/ui/Margin";
import BlogSection from "@features/blogs/BlogSection";
import DomainSection from "@features/skills/DomainSection";
import ProfileSection from "@features/profile/ProfileSection";
import ProjectSection from "@features/projects/ProjectSection";
import { fetchMediumFeed } from "@features/blogs/utils/fetchMediumFeed";
import { useEffect, useState } from "react";

interface MediumFeedResponse {
items: Array<{
title: string;
description: string;
thumbnail?: string;
categories: string[];
link: string;
}>;
}

/**
* HomePage is the main landing page of the portfolio website, assembling
* all sections such as About, Skills, Projects, and Blogs.
*
* Fetches blog data from Medium and passes it to BlogSection.
* Responsive design: adapts navigation and layout for different devices.
*
* @returns JSX.Element Main page component
* @remarks This is the root container for the homepage structure.
*/
export default function HomePage() {
const theme = useTheme();
const isMediumOrDown = useMediaQuery(theme.breakpoints.down("md"));
const [blogsData, setBlogsData] = useState<MediumFeedResponse | null>(null);

useEffect(() => {
fetchMediumFeed().then(setBlogsData);
}, []);

return (
<div className="App">
<div id="about">
<ProfileSection />
</div>
<Container>
<Margin count={2} />

<div id="skills">
<Typography variant="h4">Skills</Typography>
<Margin />
<DomainSection />
</div>

<Margin count={2} />

<div id="projects" className="page-section">
<Typography variant="h4">Projects</Typography>
<Margin />
<ProjectSection />
</div>

<Margin count={2} />

<div id="blogs" className="page-section">
<Typography variant="h4">Blogs</Typography>
<Margin />
{blogsData && <BlogSection blogsData={blogsData} />}
</div>

<Margin count={2} />
</Container>
<Copyright />

{isMediumOrDown && (
<>
<Margin count={4} />
<AppBottomNavigation />
</>
)}
</div>
);
}

65 changes: 0 additions & 65 deletions components/AppBottomNavigation.js

This file was deleted.

25 changes: 0 additions & 25 deletions components/Copyright.js

This file was deleted.

54 changes: 0 additions & 54 deletions components/DomainListItem.js

This file was deleted.

Loading