├── .prettierignore ├── .eslintignore ├── public ├── bg.gif ├── favicon.ico ├── background.gif ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── profile-picture.jpeg ├── resume │ └── resume-en.pdf ├── projectMedia │ └── loaner.png ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── site.webmanifest ├── browserconfig.xml ├── robots.txt └── hero-graphic.svg ├── .prettierrc ├── next-env.d.ts ├── next.config.js ├── components ├── ui │ └── ShortCenteredDivider.tsx ├── AnimatedLink.tsx ├── layout │ ├── Footer.tsx │ ├── NavigationDrawer.tsx │ └── Navbar.tsx ├── styles │ └── theme.ts ├── home │ ├── constants │ │ ├── skillIcons.tsx │ │ └── socialIcons.tsx │ ├── HeroSection.tsx │ ├── AboutSection.tsx │ ├── ContactSection.tsx │ └── PortfolioSection.tsx ├── RecentPostCard.tsx └── Link.tsx ├── .gitignore ├── tsconfig.json ├── utils ├── createEmotionCache.ts └── getDataUrlWithShimmerEffect.ts ├── README.md ├── .eslintrc.json ├── package.json ├── pages ├── _app.tsx ├── index.tsx └── _document.tsx └── locales └── en.json /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .next 3 | out 4 | package-lock.json -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | pages/_document.tsx 3 | components/Link.tsx -------------------------------------------------------------------------------- /public/bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hash-debug/Portfolio/master/public/bg.gif -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": false, 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hash-debug/Portfolio/master/public/favicon.ico -------------------------------------------------------------------------------- /public/background.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hash-debug/Portfolio/master/public/background.gif -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hash-debug/Portfolio/master/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hash-debug/Portfolio/master/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hash-debug/Portfolio/master/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/profile-picture.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hash-debug/Portfolio/master/public/profile-picture.jpeg -------------------------------------------------------------------------------- /public/resume/resume-en.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hash-debug/Portfolio/master/public/resume/resume-en.pdf -------------------------------------------------------------------------------- /public/projectMedia/loaner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hash-debug/Portfolio/master/public/projectMedia/loaner.png -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hash-debug/Portfolio/master/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hash-debug/Portfolio/master/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"Hrithika","short_name":"HR","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #ffffff 7 | 8 | 9 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: true, 5 | i18n: { 6 | locales: ['en', 'es'], 7 | defaultLocale: 'en', 8 | }, 9 | images: { 10 | domains: ['res.cloudinary.com'], 11 | }, 12 | }; 13 | 14 | module.exports = nextConfig; 15 | -------------------------------------------------------------------------------- /components/ui/ShortCenteredDivider.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/material/styles'; 2 | import { Divider } from '@mui/material'; 3 | 4 | const ShortCenteredDivider = styled(Divider)(({ theme }) => ({ 5 | height: '4px', 6 | width: '60px', 7 | backgroundColor: theme.palette.primary.main, 8 | margin: 'auto', 9 | })); 10 | 11 | export default ShortCenteredDivider; 12 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | This favicon was generated using the following font: 2 | 3 | - Font Title: Lusitana 4 | - Font Author: Copyright (c) 2011 by Ana Paula Megda (www.anamegda.com|anapbm@gmail.com), with Reserved Font Name Lusitana. 5 | - Font Source: http://fonts.gstatic.com/s/lusitana/v13/CSR84z9ShvucWzsMKxhaRuMiSct_.ttf 6 | - Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL)) 7 | -------------------------------------------------------------------------------- /.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 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "jsxImportSource": "@emotion/react", 17 | "incremental": true 18 | }, 19 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /components/AnimatedLink.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/material/styles'; 2 | 3 | import Link from './Link'; 4 | 5 | const AnimatedLink = styled(Link)(() => ({ 6 | padding: '12px 15px', 7 | textDecoration: 'none', 8 | position: 'relative', 9 | '&::before': { 10 | content: '""', 11 | position: 'absolute', 12 | width: 0, 13 | height: '2px', 14 | bottom: 0, 15 | left: 0, 16 | backgroundColor: '#f50057', 17 | visibility: 'hidden', 18 | transition: 'all 0.3s ease-in-out', 19 | }, 20 | '&:hover::before': { 21 | visibility: 'visible', 22 | width: '100%', 23 | }, 24 | })); 25 | 26 | export default AnimatedLink; 27 | -------------------------------------------------------------------------------- /utils/createEmotionCache.ts: -------------------------------------------------------------------------------- 1 | import createCache from '@emotion/cache'; 2 | 3 | const isBrowser = typeof document !== 'undefined'; 4 | 5 | // On the client side, Create a meta tag at the top of the and set it as insertionPoint. 6 | // This assures that MUI styles are loaded first. 7 | // It allows developers to easily override MUI styles with other styling solutions, like CSS modules. 8 | export default function createEmotionCache() { 9 | let insertionPoint; 10 | 11 | if (isBrowser) { 12 | const emotionInsertionPoint = document.querySelector( 13 | 'meta[name="emotion-insertion-point"]' 14 | ); 15 | insertionPoint = emotionInsertionPoint ?? undefined; 16 | } 17 | 18 | return createCache({ key: 'mui-style', insertionPoint }); 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## View project 2 | 3 | [Live Demo](https://hrithikasportfolio.netlify.app) 4 | 5 | ## About the project 6 | 7 | A personal portfolio website that showcases my feature projects, technical skill stack, contact information and more about me. 8 | 9 | ## Core dependencies 10 | 11 | - [React](https://reactjs.org/) - A Javascript library for building user interfaces. 12 | - [NextJS](https://nextjs.org/) - A React framework with hybrid static & server rendering, TypeScript support, smart bundling, route pre-fetching, and more. 13 | - [Material UI](https://material-ui.com/) - A React component-based design system. 14 | - [Yup](https://www.npmjs.com/package/yup) - A JavaScript schema builder for value parsing and validation. 15 | - [React Icons](https://www.npmjs.com/package/react-icons) - Include popular icons in your React projects. 16 | -------------------------------------------------------------------------------- /utils/getDataUrlWithShimmerEffect.ts: -------------------------------------------------------------------------------- 1 | const shimmer = (w: number, h: number) => ` 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | `; 14 | 15 | const toBase64 = (str: string) => 16 | typeof window === 'undefined' 17 | ? Buffer.from(str).toString('base64') 18 | : window.btoa(str); 19 | 20 | export default function getDataUrlWithShimmerEffect(w: number, h: number) { 21 | return `data:image/svg+xml;base64,${toBase64(shimmer(w, h))}`; 22 | } 23 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "prettier"], 3 | "rules": { 4 | "react/react-in-jsx-scope": 0, 5 | "react/jsx-filename-extension": [ 6 | 1, 7 | { "extensions": [".js", ".jsx", "ts", "tsx"] } 8 | ], 9 | "react/jsx-props-no-spreading": [1, { "custom": "ignore" }], 10 | "react/display-name": 1, 11 | "react/prop-types": 0, 12 | "jsx-a11y/anchor-is-valid": 0, 13 | "no-use-before-define": "off", 14 | "import/extensions": [ 15 | "error", 16 | "ignorePackages", 17 | { 18 | "js": "never", 19 | "jsx": "never", 20 | "ts": "never", 21 | "tsx": "never" 22 | } 23 | ], 24 | "import/order": ["warn", { "newlines-between": "always" }], 25 | "react/jsx-sort-props": [ 26 | "warn", 27 | { 28 | "callbacksLast": true, 29 | "shorthandFirst": true, 30 | "noSortAlphabetically": false, 31 | "reservedFirst": true 32 | } 33 | ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /components/layout/Footer.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Fab, Typography } from '@mui/material/'; 2 | import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; 3 | 4 | import { NextLinkComposed } from '../Link'; 5 | 6 | export default function Footer() { 7 | return ( 8 | theme.palette.grey[900] }} 11 | > 12 | 13 | 22 | 23 | 24 | 25 | 26 | Made with ❤️ by Hrithika {new Date().getFullYear()} 27 | 28 | 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /components/styles/theme.ts: -------------------------------------------------------------------------------- 1 | import { Roboto } from '@next/font/google'; 2 | import { createTheme, responsiveFontSizes } from '@mui/material'; 3 | import { cyan, pink } from '@mui/material/colors'; 4 | 5 | export const roboto = Roboto({ 6 | weight: ['300', '400', '500', '700'], 7 | subsets: ['latin'], 8 | display: 'swap', 9 | fallback: ['Helvetica', 'Arial', 'sans-serif'], 10 | }); 11 | 12 | // Create a theme instance. 13 | const theme = responsiveFontSizes( 14 | createTheme({ 15 | palette: { 16 | mode: 'dark', 17 | primary: pink, 18 | secondary: pink, 19 | error: { 20 | main: '#ff6358', 21 | }, 22 | }, 23 | typography: { 24 | fontFamily: roboto.style.fontFamily, 25 | }, 26 | breakpoints: { 27 | values: { 28 | xs: 0, 29 | sm: 600, 30 | md: 960, 31 | lg: 1280, 32 | xl: 1920, 33 | }, 34 | }, 35 | components: { 36 | MuiCssBaseline: { 37 | styleOverrides: ` 38 | html { 39 | scroll-behavior: smooth; 40 | } 41 | `, 42 | }, 43 | }, 44 | }) 45 | ); 46 | 47 | export default theme; 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-portfolio", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "type-check": "tsc --pretty --noEmit", 10 | "lint": "next lint", 11 | "format": "prettier --write \"./**/*.{js,jsx,ts,tsx}\"" 12 | }, 13 | "dependencies": { 14 | "@emotion/cache": "^11.10.5", 15 | "@emotion/react": "^11.10.5", 16 | "@emotion/server": "^11.10.0", 17 | "@emotion/styled": "^11.10.5", 18 | "@mui/icons-material": "^5.10.9", 19 | "@mui/material": "^5.10.13", 20 | "@next/font": "^13.0.2", 21 | "@sendgrid/mail": "^7.4.6", 22 | "clsx": "^1.2.1", 23 | "formik": "^2.2.9", 24 | "next": "^13.0.2", 25 | "react": "^18.2.0", 26 | "react-dom": "^18.2.0", 27 | "react-icons": "^4.6.0", 28 | "yup": "^0.32.11" 29 | }, 30 | "devDependencies": { 31 | "@types/node": "^18.11.9", 32 | "@types/react": "^18.0.25", 33 | "@types/react-dom": "18.0.8", 34 | "eslint": "8.27.0", 35 | "eslint-config-next": "13.0.2", 36 | "eslint-config-prettier": "^8.5.0", 37 | "prettier": "^2.7.1", 38 | "typescript": "^4.8.4" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from 'next/app'; 2 | import Head from 'next/head'; 3 | import { CacheProvider, EmotionCache } from '@emotion/react'; 4 | import { ThemeProvider } from '@mui/material/styles'; 5 | import CssBaseline from '@mui/material/CssBaseline'; 6 | 7 | import createEmotionCache from '../utils/createEmotionCache'; 8 | import theme from '../components/styles/theme'; 9 | import Navbar from '../components/layout/Navbar'; 10 | import Footer from '../components/layout/Footer'; 11 | 12 | // Client-side cache, shared for the whole session of the user in the browser. 13 | const clientSideEmotionCache = createEmotionCache(); 14 | 15 | interface MyAppProps extends AppProps { 16 | // eslint-disable-next-line react/require-default-props 17 | emotionCache?: EmotionCache; 18 | } 19 | 20 | export default function MyApp(props: MyAppProps) { 21 | const { Component, emotionCache = clientSideEmotionCache, pageProps } = props; 22 | 23 | return ( 24 | 25 | 26 | Hrithika R Portfolio 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |