├── src ├── assets │ ├── tech │ │ ├── py.png │ │ ├── aws.png │ │ ├── css.png │ │ ├── figma.png │ │ ├── git.png │ │ ├── html.png │ │ ├── java.png │ │ ├── neo.png │ │ ├── node.webp │ │ ├── raspi.png │ │ ├── eslint.png │ │ ├── github.png │ │ ├── reactjs.png │ │ ├── javascript.png │ │ ├── postgresql.png │ │ └── vite.svg │ ├── logo │ │ └── icon.png │ ├── portfolio.png │ ├── avatar │ │ └── avatar.jpg │ ├── projects │ │ ├── memory.jpg │ │ ├── skyspa.jpg │ │ ├── foremen.jpg │ │ ├── sybaris.jpg │ │ └── calculator.jpg │ ├── menu.svg │ ├── close.svg │ └── index.js ├── Components │ ├── MarqueeCards.jsx │ ├── Loader.jsx │ ├── Particles │ │ ├── HeroParticles.jsx │ │ ├── ParticlesComponent.jsx │ │ └── particlesOptions.js │ ├── PreloadMedia.jsx │ ├── elements │ │ ├── ToggleButton.jsx │ │ ├── Arrow.jsx │ │ ├── HeroScroller.jsx │ │ ├── BgQuote.jsx │ │ └── ImageSlider.jsx │ ├── SocialLinks.jsx │ ├── SectionTitle.jsx │ ├── HeroText.jsx │ ├── SkillsCards.jsx │ ├── nav │ │ └── NavBar.jsx │ ├── ContactForm.jsx │ └── ProjectCards.jsx ├── App │ ├── App.jsx │ ├── index.jsx │ └── index.css ├── Pages │ ├── Projects.jsx │ ├── Hero.jsx │ ├── Skills.jsx │ ├── Contact.jsx │ └── About.jsx ├── styles.js └── Constants │ └── constants.js ├── public ├── Fonts │ ├── Feogra │ │ └── Feogra.ttf │ ├── Mario │ │ └── Brugty.ttf │ └── Morganite │ │ ├── License.pdf │ │ ├── Morganite-Black.ttf │ │ ├── Morganite-Bold.ttf │ │ ├── Morganite-Book.ttf │ │ ├── Morganite-Light.ttf │ │ ├── Morganite-Thin.ttf │ │ ├── Morganite-Medium.ttf │ │ ├── Morganite-SemiBold.ttf │ │ ├── Morganite-BoldItalic.ttf │ │ ├── Morganite-BookItalic.ttf │ │ ├── Morganite-ExtraBold.ttf │ │ ├── Morganite-ExtraLight.ttf │ │ ├── Morganite-ThinItalic.ttf │ │ ├── Morganite-BlackItalic.ttf │ │ ├── Morganite-LightItalic.ttf │ │ ├── Morganite-MediumItalic.ttf │ │ ├── Morganite-ExtraBoldItalic.ttf │ │ ├── Morganite-SemiBoldItalic.ttf │ │ ├── Morganite-ExtraLightItalic.ttf │ │ └── morganiteFont.css └── cv │ └── SaraEcheverriasCV2024.pdf ├── postcss.config.js ├── vite.config.js ├── .gitignore ├── .eslintrc.cjs ├── tailwind.config.js ├── index.html ├── README.md └── package.json /src/assets/tech/py.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/py.png -------------------------------------------------------------------------------- /src/assets/logo/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/logo/icon.png -------------------------------------------------------------------------------- /src/assets/portfolio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/portfolio.png -------------------------------------------------------------------------------- /src/assets/tech/aws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/aws.png -------------------------------------------------------------------------------- /src/assets/tech/css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/css.png -------------------------------------------------------------------------------- /src/assets/tech/figma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/figma.png -------------------------------------------------------------------------------- /src/assets/tech/git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/git.png -------------------------------------------------------------------------------- /src/assets/tech/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/html.png -------------------------------------------------------------------------------- /src/assets/tech/java.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/java.png -------------------------------------------------------------------------------- /src/assets/tech/neo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/neo.png -------------------------------------------------------------------------------- /src/assets/tech/node.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/node.webp -------------------------------------------------------------------------------- /src/assets/tech/raspi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/raspi.png -------------------------------------------------------------------------------- /src/assets/tech/eslint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/eslint.png -------------------------------------------------------------------------------- /src/assets/tech/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/github.png -------------------------------------------------------------------------------- /src/assets/tech/reactjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/reactjs.png -------------------------------------------------------------------------------- /public/Fonts/Feogra/Feogra.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Feogra/Feogra.ttf -------------------------------------------------------------------------------- /public/Fonts/Mario/Brugty.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Mario/Brugty.ttf -------------------------------------------------------------------------------- /src/assets/avatar/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/avatar/avatar.jpg -------------------------------------------------------------------------------- /src/assets/projects/memory.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/projects/memory.jpg -------------------------------------------------------------------------------- /src/assets/projects/skyspa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/projects/skyspa.jpg -------------------------------------------------------------------------------- /src/assets/tech/javascript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/javascript.png -------------------------------------------------------------------------------- /src/assets/tech/postgresql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/tech/postgresql.png -------------------------------------------------------------------------------- /src/assets/projects/foremen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/projects/foremen.jpg -------------------------------------------------------------------------------- /src/assets/projects/sybaris.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/projects/sybaris.jpg -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /public/Fonts/Morganite/License.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/License.pdf -------------------------------------------------------------------------------- /public/cv/SaraEcheverriasCV2024.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/cv/SaraEcheverriasCV2024.pdf -------------------------------------------------------------------------------- /src/assets/projects/calculator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/src/assets/projects/calculator.jpg -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-Black.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-Bold.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-Book.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-Book.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-Light.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-Thin.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-Medium.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-SemiBold.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-BoldItalic.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-BookItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-BookItalic.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-ExtraBold.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-ExtraLight.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-ThinItalic.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-BlackItalic.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-LightItalic.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-MediumItalic.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /public/Fonts/Morganite/Morganite-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketopeak/whoami/HEAD/public/Fonts/Morganite/Morganite-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | import dotenv from 'dotenv'; 4 | 5 | dotenv.config(); 6 | 7 | export default defineConfig({ 8 | plugins: [react()], 9 | server: { 10 | host: true, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | .env 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | }, 6 | extends: [ 7 | 'plugin:react/recommended', 8 | 'airbnb', 9 | ], 10 | overrides: [ 11 | ], 12 | parserOptions: { 13 | ecmaVersion: 'latest', 14 | sourceType: 'module', 15 | }, 16 | plugins: [ 17 | 'react', 18 | ], 19 | rules: { 20 | "import/prefer-default-export": "off", 21 | "semi": "off", 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/Components/MarqueeCards.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: MarqueeCards.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import Marquee from "react-fast-marquee"; 11 | 12 | const MarqueeCards = ({children, direction}) => { 13 | 14 | return ( 15 | 21 | {children} 22 | 23 | ); 24 | }; 25 | 26 | export default MarqueeCards; 27 | -------------------------------------------------------------------------------- /src/Components/Loader.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: Loader.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import React from "react"; 11 | 12 | const Loader = () => { 13 | return ( 14 |
15 | 19 | M 20 | 21 |
22 |
23 | ); 24 | }; 25 | 26 | export default Loader; 27 | -------------------------------------------------------------------------------- /src/App/App.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: App.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 02/06/2023 8 | */ 9 | 10 | import NavBar from "../Components/nav/NavBar"; 11 | import Hero from "../Pages/Hero"; 12 | import Projects from "../Pages/Projects"; 13 | import About from "../Pages/About"; 14 | import Skills from "../Pages/Skills"; 15 | import Contact from "../Pages/Contact"; 16 | 17 | function App() { 18 | return ( 19 | <> 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | } 29 | 30 | export default App; -------------------------------------------------------------------------------- /src/Components/Particles/HeroParticles.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: HeroParticles.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import ParticlesComponent from "./ParticlesComponent"; 11 | import { heroOptions } from "./particlesOptions"; 12 | 13 | const HeroParticles = () => { 14 | return ( 15 |
16 | 21 |
22 | ); 23 | }; 24 | 25 | export default HeroParticles; 26 | -------------------------------------------------------------------------------- /src/Pages/Projects.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: Projects.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 20/04/2024 8 | */ 9 | 10 | import Works from "../Components/ProjectCards"; 11 | import SectionTitle from "../Components/SectionTitle"; 12 | 13 | const Projects = () => { 14 | return ( 15 |
16 |
17 |
18 | 19 |
20 | 21 |
22 |
23 | ); 24 | }; 25 | 26 | export default Projects; -------------------------------------------------------------------------------- /src/Components/PreloadMedia.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: PreloadMedia.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import {useState} from 'react' 11 | import Loader from './Loader'; 12 | 13 | const PreloadMedia = ({images, children}) => { 14 | const [loaded, setLoaded] = useState(false); 15 | 16 | const onLoad = () => { 17 | setLoaded(true); 18 | } 19 | 20 | const imageElements = images.map((imageSrc) => { 21 | const img = new Image(); 22 | img.src = imageSrc; 23 | img.onload = onLoad; 24 | return img; 25 | }); 26 | 27 | return loaded ? children : 28 | } 29 | 30 | export default PreloadMedia; -------------------------------------------------------------------------------- /src/Components/elements/ToggleButton.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: ToggleButton.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 02/06/2023 8 | */ 9 | 10 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 11 | import { icons } from "../../Constants/constants"; 12 | 13 | const ToggleButton = ({isActive, handleClick}) => { 14 | return ( 15 |
16 | 17 |
18 | ); 19 | }; 20 | 21 | export default ToggleButton; 22 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | import tailwindcss from 'tailwindcss'; 2 | import autoprefixer from 'autoprefixer'; 3 | 4 | /** @type {import('tailwindcss').Config} */ 5 | export default { 6 | content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], 7 | theme: { 8 | extend: { 9 | dropShadow: { 10 | green: '0 0 10rem #29c26f', 11 | }, 12 | }, 13 | colors: { 14 | primary: { 15 | 200: '#ffffff', // almost white 16 | 400: '#B64D80', // dark pink 17 | 500: '#CD6899', // light pink 18 | 600: '#99235C', // wine 19 | }, 20 | grayscale: { 21 | 25: '#E4E2DD', // beige 22 | 50: '#CD6899', 23 | 100: '#efefef', 24 | 200: '#FDFDFF', 25 | 950: '#16161b', 26 | }, 27 | }, 28 | }, 29 | plugins: [tailwindcss, autoprefixer], 30 | }; 31 | -------------------------------------------------------------------------------- /src/styles.js: -------------------------------------------------------------------------------- 1 | /* Copyright (C), 2023-2024, Mikael Laine (mikael) 2 | @author Mikael Laine 3 | FileName: styles.js 4 | @version: I 5 | Creation: 02/06/2023 6 | Last modification: 03/06/2023 */ 7 | 8 | const styles = { 9 | paddingX: 'sm:px-16 px-6', 10 | paddingY: 'sm:py-16 py-6', 11 | padding: 'sm:px-16 px-6 sm:py-16 py-10', 12 | 13 | heroHeadText: 14 | 'font-black text-white lg:text-[80px] sm:text-[60px] xs:text-[50px] text-[40px] lg:leading-[98px] mt-2', 15 | heroSubText: 16 | 'text-[#dfd9ff] font-medium lg:text-[30px] sm:text-[26px] xs:text-[20px] text-[16px] lg:leading-[40px]', 17 | 18 | sectionHeadText: 19 | 'text-white font-black md:text-[60px] sm:text-[50px] xs:text-[40px] text-[30px]', 20 | sectionSubText: 21 | 'sm:text-[18px] text-[14px] text-secondary uppercase tracking-wider', 22 | }; 23 | 24 | export { styles }; 25 | -------------------------------------------------------------------------------- /src/App/index.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: index.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 02/06/2023 8 | */ 9 | 10 | 11 | import React from "react"; 12 | import ReactDOM from "react-dom/client"; 13 | import { BrowserRouter } from "react-router-dom"; 14 | import PreloadMedia from "../Components/PreloadMedia"; 15 | import { media } from "../Constants/constants"; 16 | import App from "./App"; 17 | import "./index.css"; 18 | import "font-awesome/css/font-awesome.min.css"; 19 | import "../../public/Fonts/Morganite/morganiteFont.css"; 20 | 21 | ReactDOM.createRoot(document.getElementById("root")).render( 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | -------------------------------------------------------------------------------- /src/Components/elements/Arrow.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: Arrow.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 02/06/2023 8 | */ 9 | 10 | const Arrow = () => { 11 | return ( 12 | 13 | 14 | 23 | 24 | 25 | 26 | 31 | 32 | ); 33 | }; 34 | 35 | export default Arrow; 36 | -------------------------------------------------------------------------------- /src/Pages/Hero.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: Hero.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import { m, LazyMotion, domAnimation } from "framer-motion"; 11 | import HeroText from "../Components/HeroText"; 12 | import HeroParticles from "../Components/Particles/HeroParticles"; 13 | import HeroScroller from "../Components/elements/HeroScroller"; 14 | 15 | const Hero = () => { 16 | return ( 17 |
18 | 19 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | ); 30 | }; 31 | 32 | export default Hero; 33 | -------------------------------------------------------------------------------- /src/assets/menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Mike - Personal portfolio 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Components/Particles/ParticlesComponent.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: ParticlesComponent.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 02/06/2023 8 | */ 9 | 10 | import { useCallback } from "react"; 11 | import Particles from "react-particles"; 12 | import { loadFull } from "tsparticles"; 13 | 14 | const ParticlesComponent = (props) => { 15 | const { particlesOptions, className, id } = props; 16 | 17 | let isInitialized = false; 18 | 19 | const particlesInit = useCallback(async (engine) => { 20 | if(!isInitialized) { 21 | await loadFull(engine); 22 | isInitialized = true; 23 | } 24 | 25 | }, []); 26 | 27 | const particlesLoaded = useCallback(async (container) => { 28 | await container 29 | }, []); 30 | 31 | return ( 32 | 39 | ); 40 | }; 41 | 42 | export default ParticlesComponent; 43 | -------------------------------------------------------------------------------- /src/Components/elements/HeroScroller.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: HeroScroller.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 02/06/2023 8 | */ 9 | 10 | import { m } from "framer-motion"; 11 | 12 | const HeroScroller = () => { 13 | return ( 14 | 36 | ); 37 | }; 38 | 39 | export default HeroScroller; 40 | -------------------------------------------------------------------------------- /src/Components/elements/BgQuote.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: BgQuote.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 02/06/2023 8 | */ 9 | 10 | import { m, LazyMotion, domAnimation } from "framer-motion"; 11 | import Arrow from "./Arrow"; 12 | 13 | const BgQuote = (props) => { 14 | const { text } = props; 15 | 16 | return ( 17 | 18 | 24 |

28 | {text} 29 |

30 |
31 | 32 |
33 |
34 |
35 | ); 36 | }; 37 | 38 | export default BgQuote; 39 | -------------------------------------------------------------------------------- /src/assets/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/Components/SocialLinks.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: SocialLinks.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 11 | import { icons } from "../Constants/constants"; 12 | 13 | const SocialLinks = () => { 14 | return ( 15 | 35 | ); 36 | }; 37 | 38 | export default SocialLinks; 39 | -------------------------------------------------------------------------------- /src/Pages/Skills.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: Skills.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import MarqueeCards from "../Components/MarqueeCards"; 11 | import SectionTitle from "../Components/SectionTitle"; 12 | import SkillsCards from "../Components/SkillsCards"; 13 | 14 | const Skills = () => { 15 | return ( 16 |
17 |
18 |
19 | 20 |
21 |
22 |
23 |
24 | 25 | 26 | 27 |
28 |
29 |
30 | 31 | 32 | 33 |
34 |
35 |
36 |
37 | ); 38 | }; 39 | 40 | export default Skills; 41 | -------------------------------------------------------------------------------- /src/Components/SectionTitle.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: SectionTitle.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import { m, LazyMotion, domAnimation } from "framer-motion"; 11 | 12 | const SectionTitle = (props) => { 13 | const { title, subtitle } = props; 14 | 15 | return ( 16 | 17 | 23 | 32 | {subtitle} 33 | 34 |

38 | {title.split("").map((char, index) => { 39 | if(char === " ") { 40 | return " "; 41 | } 42 | return {char} 43 | })} 44 |

45 |
46 |
47 | ); 48 | }; 49 | 50 | export default SectionTitle; 51 | -------------------------------------------------------------------------------- /src/assets/tech/vite.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Components/elements/ImageSlider.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: ImageSlider.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 02/06/2023 8 | */ 9 | 10 | import { useEffect, useState, useRef } from "react"; 11 | import { m, LazyMotion, domAnimation } from "framer-motion"; 12 | 13 | const ImageSlider = ({ images }) => { 14 | const [index, setIndex] = useState(0); 15 | const [isInViewport, setIsInViewport] = useState(false); 16 | const imageRef = useRef(null); 17 | 18 | useEffect(() => { 19 | const interval = setInterval(() => { 20 | if (isInViewport) { 21 | setIndex((i) => (i + 1) % images.length); 22 | } 23 | }, 3000); 24 | 25 | return () => clearInterval(interval); 26 | }, [images, isInViewport]); 27 | 28 | useEffect(() => { 29 | const observer = new IntersectionObserver( 30 | ([entry]) => setIsInViewport(entry.isIntersecting), 31 | { threshold: 0 } 32 | ); 33 | 34 | if (imageRef.current) { 35 | observer.observe(imageRef.current); 36 | } 37 | 38 | return () => observer.disconnect(); 39 | }, []); 40 | 41 | return ( 42 | 43 | 56 | 57 | ); 58 | }; 59 | 60 | export default ImageSlider; 61 | -------------------------------------------------------------------------------- /src/Pages/Contact.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: Contact.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import { m, LazyMotion, domAnimation } from "framer-motion"; 11 | import SectionTitle from "../Components/SectionTitle"; 12 | import ContactForm from "../Components/ContactForm"; 13 | import SocialLinks from "../Components/SocialLinks"; 14 | 15 | const Contact = () => { 16 | return ( 17 |
21 |
22 |
23 | 24 |
25 |
26 | 27 | 33 |
34 | 35 |
36 |
37 |
38 |
39 |
40 | 41 |
42 | 43 | Made by Mikael Laine (miketopeak) 44 | 45 |
46 |
47 |
48 | ); 49 | }; 50 | 51 | export default Contact; 52 | -------------------------------------------------------------------------------- /src/assets/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: index.js 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | // Logo 11 | import mikeIcon from './logo/icon.png'; 12 | 13 | // Technologies 14 | import htmlIcon from './tech/html.png'; 15 | import cssIcon from './tech/css.png'; 16 | import jsIcon from './tech/javascript.png'; 17 | import reactIcon from './tech/reactjs.png'; 18 | import awsIcon from './tech/aws.png'; 19 | import javaIcon from './tech/java.png'; 20 | import gitIcon from './tech/git.png'; 21 | import githubIcon from './tech/github.png'; 22 | import figmaIcon from './tech/figma.png'; 23 | import psqlIcon from './tech/postgresql.png'; 24 | import eslintIcon from './tech/eslint.png'; 25 | import viteIcon from './tech/vite.svg'; 26 | import pyIcon from './tech/py.png'; 27 | import nodeIcon from './tech/node.webp'; 28 | import neoIcon from './tech/neo.png'; 29 | import raspIcon from './tech/raspi.png'; 30 | import close from './close.svg'; 31 | import menu from './menu.svg'; 32 | 33 | // Projects 34 | import memoryGame from './projects/memory.jpg'; 35 | import sybaris from './projects/sybaris.jpg' 36 | import foremen from './projects/foremen.jpg'; 37 | import calculator from './projects/calculator.jpg'; 38 | import skyspa from './projects/skyspa.jpg' 39 | 40 | // Avatar 41 | import avatar from './avatar/avatar.jpg'; 42 | 43 | export { 44 | menu, 45 | close, 46 | htmlIcon, 47 | cssIcon, 48 | jsIcon, 49 | reactIcon, 50 | awsIcon, 51 | javaIcon, 52 | gitIcon, 53 | githubIcon, 54 | eslintIcon, 55 | figmaIcon, 56 | psqlIcon, 57 | nodeIcon, 58 | pyIcon, 59 | viteIcon, 60 | neoIcon, 61 | raspIcon, 62 | memoryGame, 63 | foremen, 64 | calculator, 65 | skyspa, 66 | sybaris, 67 | avatar, 68 | mikeIcon, 69 | }; 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Who's Mikael ? 2 | Welcome to my portfolio repository! This project showcases my skills using React, ESLint, Tailwind, and Vite. It includes a brief introduction about me, my projects, the technologies I've worked with, and my experience. You'll also find a contact form at the bottom and my social media links below it. Feel free to explore and connect with me! 3 | 4 |

5 |
6 | wb 7 |
8 |

9 |

10 | Features • 11 | Files • 12 | How To Use • 13 | Packages 14 |

15 |

16 | Try it out here 17 |

18 | 19 | ## Features 20 | 21 | * Vite 22 | ```bash 23 | # Install dependencies 24 | $ npm i 25 | # run the app 26 | $ npm run dev 27 | ``` 28 | 29 | ## Files 30 | 31 | - src: the file that implements de solution. 32 | - assets: resources that are used in an application. 33 | - components: reusable pieces of code that define the appearance and behavior of a part of the UI. 34 | - pages: the different areas of the portfolio. 35 | - constants: values that cannot be altered by the program during normal execution. 36 | 37 | 38 | ## How To Use 39 | 40 | To clone and run this application, you'll need [Git](https://git-scm.com), [Node.js](https://nodejs.org/en) and [Vite](https://vitejs.dev/) installed on your computer. From your command line: 41 | 42 | ```bash 43 | # Clone this repository 44 | $ git clone https://github.com/miketopeak/whoami 45 | 46 | # Install dependencies 47 | $ npm i 48 | 49 | # Run the app 50 | $ npm run dev 51 | ``` 52 | 53 | ## Packages 54 | 55 | This software uses the following open source packages: 56 | 57 | - [Vite](https://vitejs.dev/) 58 | - [React](https://reactjs.org/) 59 | - [Tailwind](https://tailwindcss.com/) 60 | -------------------------------------------------------------------------------- /src/Components/HeroText.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: HeroText.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import { m, LazyMotion, domAnimation } from "framer-motion"; 11 | 12 | const HeroText = () => { 13 | const name = "Mikael ?"; 14 | 15 | return ( 16 |
20 | 21 | 28 | 33 | WHO'S{" "} 34 | 35 | 40 | {name.split("").map((char, index) => { 41 | if (char === " ") { 42 | return " "; 43 | } 44 | return ( 45 | 50 | {char} 51 | 52 | ); 53 | })} 54 | 55 | 56 | 57 |
58 | ); 59 | }; 60 | 61 | export default HeroText; 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vs-portfolio", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "vite": "^4.2.0", 13 | "@vitejs/plugin-react": "^3.1.0", 14 | "@types/react-dom": "^18.0.11", 15 | "@emailjs/browser": "^3.11.0", 16 | "@fortawesome/fontawesome-svg-core": "^6.4.0", 17 | "@fortawesome/free-brands-svg-icons": "^6.4.0", 18 | "@fortawesome/free-solid-svg-icons": "^6.4.0", 19 | "@fortawesome/react-fontawesome": "^0.2.0", 20 | "@motionone/utils": "^10.15.1", 21 | "@react-hook/window-size": "^3.1.1", 22 | "emailjs": "^4.0.2", 23 | "emailjs-com": "^3.2.0", 24 | "font-awesome": "^4.7.0", 25 | "framer-motion": "^10.11.2", 26 | "gsap": "^3.11.5", 27 | "localforage": "^1.10.0", 28 | "lodash-move": "^1.1.1", 29 | "match-sorter": "^6.3.1", 30 | "normalize-wheel": "^1.0.1", 31 | "pathseg": "^1.2.1", 32 | "react": "^18.2.0", 33 | "react-dom": "^18.2.0", 34 | "react-fast-marquee": "^1.3.5", 35 | "react-globe.gl": "^2.24.1", 36 | "react-intersection-observer": "^9.4.3", 37 | "react-particles": "^2.9.3", 38 | "react-responsive": "^9.0.2", 39 | "react-router-dom": "^6.10.0", 40 | "react-scroll": "^1.8.9", 41 | "react-simple-typewriter": "^5.0.1", 42 | "react-tilt": "^1.0.2", 43 | "react-tsparticles": "^2.9.3", 44 | "react-use": "^17.4.0", 45 | "sort-by": "^0.0.2", 46 | "tsparticles": "^2.9.3", 47 | "tailwindcss": "^3.3.1", 48 | "autoprefixer": "^10.4.14", 49 | "dotenv": "^16.0.3" 50 | }, 51 | "devDependencies": { 52 | "@types/react": "^18.0.28", 53 | "eslint": "^8.42.0", 54 | "eslint-config-airbnb": "^19.0.4", 55 | "eslint-plugin-import": "^2.27.5", 56 | "eslint-plugin-jsx-a11y": "^6.7.1", 57 | "eslint-plugin-react": "^7.32.2", 58 | "eslint-plugin-react-hooks": "^4.6.0", 59 | "postcss": "^8.4.21" 60 | }, 61 | "description": "", 62 | "main": "postcss.config.js", 63 | "keywords": [], 64 | "author": "", 65 | "license": "ISC" 66 | } 67 | -------------------------------------------------------------------------------- /src/Components/SkillsCards.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: SkillCards.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import { m, LazyMotion, domAnimation } from "framer-motion"; 11 | import { skills } from "../Constants/constants"; 12 | 13 | const SkillsCards = () => { 14 | return ( 15 |
16 | 17 | 18 | {skills.map((skill, index) => ( 19 | 34 |
35 | {skill.title} 40 | 47 | {skill.title} 48 | 49 | 57 | {skill.description} 58 | 59 |
60 |
61 | ))} 62 |
63 |
64 | ); 65 | }; 66 | 67 | export default SkillsCards; -------------------------------------------------------------------------------- /public/Fonts/Morganite/morganiteFont.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Morganite Black"; 3 | src: url(/Fonts/Morganite/Morganite-Black.ttf); 4 | } 5 | 6 | @font-face { 7 | font-family: "Morganite Black Italic"; 8 | src: url(/Fonts/Morganite/Morganite-BlackItalic.ttf); 9 | } 10 | 11 | @font-face { 12 | font-family: "Morganite Bold"; 13 | src: url(/Fonts/Morganite/Morganite-Bold.ttf); 14 | } 15 | 16 | @font-face { 17 | font-family: "Morganite Bold Italic"; 18 | src: url(/Fonts/Morganite/Morganite-BoldItalic.ttf); 19 | } 20 | 21 | @font-face { 22 | font-family: "Morganite Book"; 23 | src: url(/Fonts/Morganite/Morganite-Book.ttf); 24 | } 25 | 26 | @font-face { 27 | font-family: "Morganite Book Italic"; 28 | src: url(/Fonts/Morganite/Morganite-BookItalic.ttf); 29 | } 30 | 31 | @font-face { 32 | font-family: "Morganite Extra Bold"; 33 | src: url(/Fonts/Morganite/Morganite-ExtraBold.ttf); 34 | } 35 | 36 | @font-face { 37 | font-family: "Morganite Extra Bold Italic"; 38 | src: url(/Fonts/Morganite/Morganite-ExtraBoldItalic.ttf); 39 | } 40 | 41 | @font-face { 42 | font-family: "Morganite Extra Light"; 43 | src: url(/Fonts/Morganite/Morganite-ExtraLight.ttf); 44 | } 45 | 46 | @font-face { 47 | font-family: "Morganite Extra Light Italic"; 48 | src: url(/Fonts/Morganite/Morganite-ExtraLightItalic.ttf); 49 | } 50 | 51 | @font-face { 52 | font-family: "Morganite Light"; 53 | src: url(/Fonts/Morganite/Morganite-Light.ttf); 54 | } 55 | 56 | @font-face { 57 | font-family: "Morganite Light Italic"; 58 | src: url(/Fonts/Morganite/Morganite-LightItalic.ttf); 59 | } 60 | 61 | @font-face { 62 | font-family: "Morganite Extra Light Italic"; 63 | src: url(/Fonts/Morganite/Morganite-ExtraLightItalic.ttf); 64 | } 65 | 66 | @font-face { 67 | font-family: "Morganite Medium"; 68 | src: url(/Fonts/Morganite/Morganite-Medium.ttf); 69 | } 70 | 71 | @font-face { 72 | font-family: "Morganite Medium Italic"; 73 | src: url(/Fonts/Morganite/Morganite-MediumItalic.ttf); 74 | } 75 | 76 | @font-face { 77 | font-family: "Morganite Semi Bold"; 78 | src: url(/Fonts/Morganite/Morganite-SemiBold.ttf); 79 | } 80 | 81 | @font-face { 82 | font-family: "Morganite Semi Bold Italic"; 83 | src: url(/Fonts/Morganite/Morganite-SemiBoldItalic.ttf); 84 | } 85 | 86 | @font-face { 87 | font-family: "Morganite Thin"; 88 | src: url(/Fonts/Morganite/Morganite-Thin.ttf); 89 | } 90 | 91 | @font-face { 92 | font-family: "Morganite Thin Italic"; 93 | src: url(/Fonts/Morganite/Morganite-ThinItalic.ttf); 94 | } 95 | -------------------------------------------------------------------------------- /src/Pages/About.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: About.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import { m, LazyMotion, domAnimation } from "framer-motion"; 11 | import SectionTitle from "../Components/SectionTitle"; 12 | import { memoji } from "../Constants/constants"; 13 | import { introduction } from "../Constants/constants"; 14 | import ImageSlider from "../Components/elements/ImageSlider"; 15 | 16 | const About = () => { 17 | return ( 18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 | 26 | 38 | {introduction.text[0]} 39 | {introduction.text[1]} 40 | {introduction.text[2]} 41 | {introduction.text[3]} 42 | {introduction.text[4]} 43 | 44 | 45 | {introduction.text[5].split('here')[0]} 46 | here 47 | {introduction.text[5].split('here')[1]} 48 | 49 | 50 | 51 | 52 |
53 |
54 |
55 | 56 |
57 |
58 |
59 |
60 |
61 | ); 62 | }; 63 | 64 | export default About; 65 | -------------------------------------------------------------------------------- /src/Components/nav/NavBar.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: NavBar.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 02/06/2023 8 | */ 9 | 10 | import React, {useState } from "react"; 11 | import { Link } from "react-router-dom"; 12 | import {styles} from '../../styles.js'; 13 | import { navLinks } from "../../Constants/constants"; 14 | import { mikeIcon, menu, close } from "../../assets"; 15 | 16 | const Navbar = () => { 17 | const [active, setActive] = useState(""); 18 | const [toggle, setToggle] = useState(false); 19 | 20 | return ( 21 | 89 | ); 90 | }; 91 | 92 | export default Navbar; -------------------------------------------------------------------------------- /src/App/index.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: index.css 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 02/06/2023 8 | */ 9 | 10 | 11 | @tailwind base; 12 | @tailwind components; 13 | @tailwind utilities; 14 | 15 | @font-face { 16 | font-family: "Feogra-Demo"; 17 | src: url(/Fonts/Feogra/Feogra.ttf); 18 | } 19 | 20 | * { 21 | margin: 0; 22 | padding: 0; 23 | box-sizing: border-box; 24 | scroll-behavior: smooth; 25 | 26 | } 27 | 28 | body { 29 | background: url("https://uploads-ssl.webflow.com/62e3ee10882dc50bcae8d07a/631a5d4631d4c55a475f3e34_noise-50.png"); 30 | background-color: #000; 31 | position: relative; 32 | overflow-x: hidden; 33 | -webkit-overflow-x: hidden; 34 | } 35 | 36 | .overflow-hidden-web { 37 | overflow: hidden; 38 | -webkit-overflow: hidden; 39 | } 40 | 41 | .message::after { 42 | content: " "; 43 | width: 10px; 44 | height: 10px; 45 | background: transparent; 46 | position: absolute; 47 | bottom: -10px; 48 | right: 0; 49 | border-radius: 0 0 0 100%; 50 | } 51 | 52 | #repulse-div { 53 | -webkit-appearance: none; 54 | appearance: none; 55 | -webkit-filter: drop-shadow(0 0 5rem #292D44); 56 | filter: drop-shadow(0 0 5rem #292D44); 57 | } 58 | 59 | #repulse-div > h1 { 60 | -webkit-filter: drop-shadow(0 0 5rem #292D44); 61 | filter: drop-shadow(0 0 5rem #292D44); 62 | } 63 | 64 | #journey-scroll::-webkit-scrollbar { 65 | display: none; 66 | } 67 | 68 | #journey-scroll { 69 | -ms-overflow-style: none; 70 | scrollbar-width: none; 71 | } 72 | 73 | .arrowpath, 74 | polyline { 75 | fill: none; 76 | stroke: #1e90ff; 77 | stroke-width: 2; 78 | } 79 | 80 | .arrowpath { 81 | stroke-dasharray: 11, 5; 82 | } 83 | 84 | .noselect { 85 | -webkit-touch-callout: none; 86 | -webkit-user-select: none; 87 | -khtml-user-select: none; 88 | -moz-user-select: none; 89 | -ms-user-select: none; 90 | user-select: none; 91 | } 92 | 93 | .blob { 94 | animation: morph 3.6s linear infinite; 95 | background: transparent; 96 | border-collapse: separate; 97 | background-size: cover; 98 | background-position: center; 99 | outline: 1px #1e90ff; 100 | } 101 | 102 | @keyframes morph { 103 | 0%, 104 | 100% { 105 | border-radius: 40% 60% 70% 30% / 40% 40% 60% 50%; 106 | -webkit-border-radius: 40% 60% 70% 30% / 40% 40% 60% 50%; 107 | -moz-border-radius: 40% 60% 70% 30% / 40% 40% 60% 50%; 108 | } 109 | 34% { 110 | border-radius: 70% 30% 50% 50% / 30% 30% 70% 70%; 111 | -webkit-border-radius: 70% 30% 50% 50% / 30% 30% 70% 70%; 112 | -moz-border-radius: 70% 30% 50% 50% / 30% 30% 70% 70%; 113 | } 114 | 67% { 115 | border-radius: 100% 60% 60% 100% / 100% 100% 60% 60%; 116 | -webkit-border-radius: 100% 60% 60% 100% / 100% 100% 60% 60%; 117 | -moz-border-radius: 100% 60% 60% 100% / 100% 100% 60% 60%; 118 | } 119 | } 120 | 121 | .bounce { 122 | color: #1e90ff; 123 | transition: all 0.3s ease-out; 124 | } 125 | 126 | .bounce:hover { 127 | display: inline-block; 128 | animation: rubberband 0.8s ease-out; 129 | color: #fff; 130 | } 131 | 132 | @keyframes rubberband { 133 | 0% { 134 | transform: scaleX(1); 135 | } 136 | 40% { 137 | transform: scaleX(1.12) scaleY(0.75); 138 | } 139 | 55% { 140 | transform: scaleX(0.85) scaleY(1); 141 | } 142 | 65% { 143 | transform: scaleX(1.09) scaleY(0.85); 144 | } 145 | 75% { 146 | transform: scaleX(0.9) scaleY(1); 147 | } 148 | 90% { 149 | transform: scaleX(1.05) scaleY(0.95); 150 | } 151 | 100% { 152 | transform: scaleX(1) scaleY(1); 153 | } 154 | } 155 | 156 | @media only screen and (min-width: 600px) { 157 | .drop-shadow-div { 158 | -webkit-appearance: none; 159 | appearance: none; 160 | -webkit-filter: drop-shadow(0 0 1.5rem #00f7ff); 161 | filter: drop-shadow(0 0 1.5rem #00f7ff); 162 | } 163 | } 164 | 165 | .loader { 166 | width: 100px; 167 | height: 100px; 168 | border: 5px solid #1e90ff; 169 | border-radius: 50%; 170 | display: inline-block; 171 | position: relative; 172 | animation: rotation 1s linear infinite; 173 | } 174 | .loader::after { 175 | content: ''; 176 | position: absolute; 177 | left: 50%; 178 | top: 50%; 179 | transform: translate(-50%, -50%); 180 | width: 80px; 181 | height: 80px; 182 | border-radius: 50%; 183 | border: 5px solid; 184 | border-color: #1e90ff transparent; 185 | } 186 | 187 | @keyframes rotation { 188 | 0% { 189 | transform: rotate(0deg); 190 | } 191 | 100% { 192 | transform: rotate(360deg); 193 | } 194 | } -------------------------------------------------------------------------------- /src/Components/ContactForm.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: ContactForm.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 03/06/2023 8 | */ 9 | 10 | import { useRef, useState } from "react"; 11 | import { Typewriter } from "react-simple-typewriter"; 12 | import emailjs from "@emailjs/browser"; 13 | 14 | const ContactForm = () => { 15 | const [isSent, setIsSent] = useState(false); 16 | const form = useRef(); 17 | 18 | const sendEmail = (e) => { 19 | e.preventDefault(); 20 | 21 | emailjs 22 | .sendForm("whoisbl33h", "template1", e.target, "JjC_Nnt4rUsjIsRtz") 23 | .then( 24 | (result) => { 25 | document.getElementById("contact_form").reset(); 26 | setIsSent(true); 27 | alert("Thank you I will get back to you as soon as possible ! (:"); 28 | }, 29 | (error) => { 30 | console.error(error); 31 | setIsSent(false); 32 | } 33 | ); 34 | }; 35 | 36 | return ( 37 |
47 |
48 |

52 | 53 |   54 |

55 |
56 |
57 |
66 |
67 | 73 | 81 |
82 |
83 | 89 | 97 |
98 |
99 | 105 | 113 |
114 |
115 | 121 | 127 |
128 |
129 | 135 |
136 |
137 |
138 |
139 | ); 140 | }; 141 | 142 | export default ContactForm; 143 | -------------------------------------------------------------------------------- /src/Components/ProjectCards.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: ProjectCards.jsx 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 19/04/2024 8 | */ 9 | 10 | import { motion } from "framer-motion"; 11 | import { Tilt } from "react-tilt"; 12 | import { projects } from "../Constants/constants"; 13 | import { githubIcon } from "../assets"; 14 | 15 | export const staggerContainer = (staggerChildren, delayChildren) => { 16 | return { 17 | hidden: {}, 18 | show: { 19 | transition: { 20 | staggerChildren: staggerChildren, 21 | delayChildren: delayChildren || 0, 22 | }, 23 | }, 24 | }; 25 | }; 26 | 27 | export const textVariant = (delay) => { 28 | return { 29 | hidden: { 30 | y: -50, 31 | opacity: 0, 32 | }, 33 | show: { 34 | y: 0, 35 | opacity: 1, 36 | transition: { 37 | type: "spring", 38 | duration: 1.25, 39 | delay: delay, 40 | }, 41 | }, 42 | }; 43 | }; 44 | 45 | export const fadeIn = (direction, type, delay, duration) => { 46 | return { 47 | hidden: { 48 | x: direction === "left" ? 100 : direction === "right" ? -100 : 0, 49 | y: direction === "up" ? 100 : direction === "down" ? -100 : 0, 50 | opacity: 0, 51 | }, 52 | show: { 53 | x: 0, 54 | y: 0, 55 | opacity: 1, 56 | transition: { 57 | type: type, 58 | delay: delay, 59 | duration: duration, 60 | ease: "easeOut", 61 | }, 62 | }, 63 | }; 64 | }; 65 | 66 | export const zoomIn = (delay, duration) => { 67 | return { 68 | hidden: { 69 | scale: 0, 70 | opacity: 0, 71 | }, 72 | show: { 73 | scale: 1, 74 | opacity: 1, 75 | transition: { 76 | type: "tween", 77 | delay: delay, 78 | duration: duration, 79 | ease: "easeOut", 80 | }, 81 | }, 82 | }; 83 | }; 84 | 85 | export const slideIn = (direction, type, delay, duration) => { 86 | return { 87 | hidden: { 88 | x: direction === "left" ? "-100%" : direction === "right" ? "100%" : 0, 89 | y: direction === "up" ? "100%" : direction === "down" ? "100%" : 0, 90 | }, 91 | show: { 92 | x: 0, 93 | y: 0, 94 | transition: { 95 | type: type, 96 | delay: delay, 97 | duration: duration, 98 | ease: "easeOut", 99 | }, 100 | }, 101 | }; 102 | }; 103 | 104 | const ProjectCard = ({ 105 | index, 106 | name, 107 | description, 108 | image, 109 | source_code_link, 110 | demo_link, 111 | }) => { 112 | return ( 113 | 121 | 124 |
125 | {name} 130 | {/*
131 |
window.open(source_code_link, "_blank")} 133 | className="w-8 h-8 rounded-full flex justify-center items-center cursor-pointer" 134 | > 135 | github 140 |
141 |
*/} 142 |
143 | 144 |
145 |

{name}

146 |

147 | {description} 148 |

149 |
150 |
151 | 160 |
161 |
162 | ); 163 | }; 164 | 165 | const Works = () => { 166 | return ( 167 |
168 | {projects.map((project, index) => ( 169 | 170 | ))} 171 |
172 | ); 173 | }; 174 | 175 | export default Works; -------------------------------------------------------------------------------- /src/Components/Particles/particlesOptions.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: particleOptions.js 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 02/06/2023 8 | */ 9 | 10 | export const heroOptions = { 11 | autoPlay: true, 12 | 13 | fullScreen: { 14 | enable: false, 15 | zIndex: 0, 16 | }, 17 | 18 | detectRetina: true, 19 | fpsLimit: 120, 20 | 21 | interactivity: { 22 | detectsOn: '#hero', 23 | events: { 24 | onDiv: [ 25 | { 26 | selectors: '#repulse-div', 27 | enable: true, 28 | mode: 'bounce', 29 | type: 'circle', 30 | }, 31 | { 32 | selectors: '#repulse-div', 33 | enable: true, 34 | mode: 'repulse', 35 | type: 'circle', 36 | }, 37 | { 38 | selectors: '#repulse-span', 39 | enable: true, 40 | mode: 'repulse', 41 | type: 'circle', 42 | }, 43 | { 44 | selectors: '#repulse-span', 45 | enable: true, 46 | mode: 'bounce', 47 | type: 'circle', 48 | }, 49 | { 50 | selectors: '#togglebutton', 51 | enable: true, 52 | mode: 'repulse', 53 | type: 'circle', 54 | }, 55 | { 56 | selectors: '#togglebutton', 57 | enable: true, 58 | mode: 'bounce', 59 | type: 'circle', 60 | }, 61 | { 62 | selectors: '#scroller', 63 | enable: true, 64 | mode: 'repulse', 65 | type: 'circle', 66 | }, 67 | { 68 | selectors: '#scroller', 69 | enable: true, 70 | mode: 'bounce', 71 | type: 'circle', 72 | }, 73 | ], 74 | 75 | onHover: { 76 | enable: true, 77 | mode: 'bubble', 78 | parallax: { 79 | enable: true, 80 | force: 350, 81 | smooth: 20, 82 | }, 83 | }, 84 | resize: { 85 | delay: 0.5, 86 | enable: true, 87 | }, 88 | }, 89 | 90 | modes: { 91 | bounce: { 92 | distance: 100, 93 | }, 94 | bubble: { 95 | distance: 100, 96 | duration: 0.4, 97 | size: 40, 98 | color: { 99 | value: '#1e90ff', 100 | }, 101 | opacity: 8, 102 | mix: false, 103 | }, 104 | 105 | repulse: { 106 | distance: 200, 107 | factor: 200, 108 | speed: 1, 109 | maxSpeed: 50, 110 | }, 111 | }, 112 | }, 113 | 114 | particles: { 115 | collisions: { 116 | enable: true, 117 | mode: 'bounce', 118 | }, 119 | color: { 120 | value: '#1e90ff', 121 | }, 122 | move: { 123 | angle: { 124 | offset: 0, 125 | value: 90, 126 | }, 127 | center: { 128 | x: 50, 129 | y: 50, 130 | mode: 'percent', 131 | radius: 0, 132 | }, 133 | direction: ['top-left', 'bottom-left', 'bottom-right', 'top-right'], 134 | drift: 0, 135 | enable: true, 136 | random: false, 137 | size: false, 138 | speed: 0.8, 139 | outMode: 'bounce', 140 | }, 141 | number: { 142 | limit: 0, 143 | value: 30, 144 | }, 145 | 146 | opacity: { 147 | random: { 148 | enable: true, 149 | minimumValue: 0.4, 150 | maxValue: 0.6, 151 | }, 152 | value: 0.6, 153 | animation: { 154 | count: 0, 155 | enable: true, 156 | speed: 0.2, 157 | decay: 0, 158 | sync: true, 159 | destroy: 'none', 160 | startValue: 'random', 161 | }, 162 | }, 163 | 164 | shape: { 165 | type: 'character', 166 | character: [ 167 | { 168 | fill: true, 169 | font: 'Font Awesome 6 Brands', 170 | style: '', 171 | value: ['\uf3c6'], 172 | weight: '400', 173 | }, 174 | { 175 | fill: true, 176 | font: 'Font Awesome 6 Brands', 177 | style: '', 178 | value: ['\uf17c'], 179 | weight: '400', 180 | }, 181 | { 182 | fill: true, 183 | font: 'Font Awesome 6 Brands', 184 | style: '', 185 | value: ['\uf791'], 186 | weight: '400', 187 | }, 188 | ], 189 | }, 190 | 191 | size: { 192 | random: { 193 | enable: true, 194 | minimumValue: 25, 195 | maxValue: 35, 196 | }, 197 | animation: { 198 | count: 0, 199 | enable: true, 200 | speed: 0.2, 201 | decay: 0, 202 | sync: true, 203 | destroy: 'none', 204 | startValue: 'random', 205 | }, 206 | }, 207 | 208 | lineLinked: { 209 | blink: false, 210 | color: { 211 | value: '#ffffff', 212 | }, 213 | consent: true, 214 | distance: 100, 215 | enable: true, 216 | frequency: 10, 217 | opacity: 0.4, 218 | width: 1, 219 | }, 220 | }, 221 | pauseOnBlur: true, 222 | pauseOnOutsideViewport: true, 223 | smooth: true, 224 | }; 225 | -------------------------------------------------------------------------------- /src/Constants/constants.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C), 2023-2024, Mikael Laine (mikael) 3 | Author: Mikael Laine 4 | FileName: constants.js 5 | Version: I 6 | Creation: 02/06/2023 7 | Last modification: 18/12/2023 8 | */ 9 | 10 | import { library } from '@fortawesome/fontawesome-svg-core'; 11 | import { 12 | faX, 13 | faBars, 14 | faWindowRestore, 15 | faBagShopping, 16 | faDiceD6, 17 | faEnvelope, 18 | } from '@fortawesome/free-solid-svg-icons'; 19 | import { 20 | faReact, 21 | faGithub, 22 | faSkype, 23 | } from '@fortawesome/free-brands-svg-icons'; 24 | 25 | import { 26 | htmlIcon, 27 | cssIcon, 28 | jsIcon, 29 | reactIcon, 30 | awsIcon, 31 | javaIcon, 32 | gitIcon, 33 | githubIcon, 34 | psqlIcon, 35 | eslintIcon, 36 | pyIcon, 37 | viteIcon, 38 | nodeIcon, 39 | raspIcon, 40 | neoIcon, 41 | figmaIcon, 42 | memoryGame, 43 | foremen, 44 | calculator, 45 | skyspa, 46 | sybaris, 47 | avatar, 48 | } from '../assets'; 49 | 50 | library.add(faX, faBars, faWindowRestore, faBagShopping, faDiceD6); 51 | 52 | const media = { 53 | htmlIcon, 54 | cssIcon, 55 | jsIcon, 56 | reactIcon, 57 | awsIcon, 58 | javaIcon, 59 | gitIcon, 60 | githubIcon, 61 | psqlIcon, 62 | eslintIcon, 63 | pyIcon, 64 | viteIcon, 65 | nodeIcon, 66 | raspIcon, 67 | neoIcon, 68 | figmaIcon, 69 | avatar, 70 | }; 71 | 72 | const icons = { 73 | faBars, 74 | faX, 75 | faWindowRestore, 76 | faBagShopping, 77 | faDiceD6, 78 | faReact, 79 | faGithub, 80 | faSkype, 81 | faEnvelope, 82 | }; 83 | 84 | const introduction = { 85 | text: [ 86 | "I am Mikael, a seasoned Full-stack Developer.", 87 | 88 | "Seeking a position that utilizes abilities and skills in web development.", 89 | "Fast-paced, creative web developer with extensive knowledge in various front-end and back-end languages, responsive frameworks, databases, and best code practices.", 90 | "The aim is to become an exceptional Full- stack developer and make valuable contributions to the technology industry.", 91 | "Extremely flexible with communication and working hours.", 92 | "You can download my resume here." 93 | ], 94 | }; 95 | 96 | export const navLinks = [ 97 | { 98 | id: 'about', 99 | title: 'About', 100 | }, 101 | { 102 | id: 'projects', 103 | title: 'Projects', 104 | }, 105 | { 106 | id: 'skills', 107 | title: 'Skills', 108 | }, 109 | { 110 | id: 'contact', 111 | title: 'Contact', 112 | }, 113 | ]; 114 | 115 | const projects = [ 116 | { 117 | name: "Arasartara's Gallery", 118 | description: 'A memory game with an art theme implemented with React. Test your memory skills and enjoy beautiful artwork as you match pairs of cards in this engaging game.', 119 | image: memoryGame, 120 | source_code_link: 'https://github.com/bl33h/artMemoryGame', 121 | demo_link: 'https://arasarmemory.netlify.app/', 122 | }, 123 | { 124 | name: 'Connect 4', 125 | description: 'This project implements Connect Four in Python and Pygame, featuring a GUI and gameplay modes for player vs. AI and AI vs. AI. The AI uses the MiniMax algorithm, with optional alpha-beta pruning for improved performance.', 126 | image: "https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExbjRkaWp6MDJ1cXNrZmMzaTZ2aXVhcWtndWJpNHg0djRpYWdtYjF3ZSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/p49LPwL9yAoZInx28N/giphy.gif", 127 | source_code_link: 'https://github.com/bl33h/connectFour', 128 | demo_link: 'https://youtu.be/CBceC2BXJyE', 129 | }, 130 | { 131 | name: 'Sybaris Pull Suites', 132 | description: '--- The Best Romantic Getaway in the United States. A romantic paradise to ignite feelings, rekindle the romance and enjoy quality time together. --- Stack: WordPress, Elementor', 133 | image: sybaris, 134 | source_code_link: 'https://github.com/bl33h/pawsitive', 135 | demo_link: 'https://www.sybaris.com/', 136 | }, 137 | { 138 | name: 'Client-Server Chat', 139 | description: 'This is a chat application that facilitates communication between multiple clients through a centralized server. The application is designed using socket programming and handles multiple client connections concurrently using threads.', 140 | image: "https://i.pinimg.com/originals/0e/4a/c3/0e4ac37acbff81cd087aa19692a07a9d.gif", 141 | source_code_link: 'https://github.com/bl33h/clientServerChat', 142 | demo_link: 'https://youtu.be/Mk1BNqPz1n4', 143 | }, 144 | { 145 | name: 'Visit Our Lands', 146 | description: 'It is a recommendation system built with React and Supabase. This system focuses on providing tourist recommendations for various locations in Panama.', 147 | image: "https://res.cloudinary.com/worldpackers/image/upload/c_fill,f_auto,q_auto,w_1024/v1/guides/article_cover/uvd82gspopw8orvryulc", 148 | source_code_link: 'https://github.com/bl33h/visitOurLands', 149 | demo_link: 'https://visitourlands.netlify.app/', 150 | }, 151 | { 152 | name: 'Foremen Fiefdom', 153 | description: '--- At Foremen Fiefdom, they provide smartest of the investment chances in the real estate market and offer products promising highest returns. --- Stack: Nuxt.js, Bootstrap, Laravel', 154 | image: foremen, 155 | source_code_link: 'https://github.com/bl33h/exploringTheSpace', 156 | demo_link: 'https://www.foremenfiefdom.com/', 157 | }, 158 | { 159 | name: 'Basic Calculator', 160 | description: '--- A completely functional basic calculator website created with React. It allows you to perform mathematical calculations effortlessly. --- Stack: React.js', 161 | image: calculator, 162 | source_code_link: 'https://github.com/bl33h/disneyPlusReplica', 163 | demo_link: 'https://kimoto-calculator.netlify.app/', 164 | }, 165 | { 166 | name: '7 Sky Spa', 167 | description: '--- You can expect the most modern treatment devices, internationally recognized French cosmetic products and a dynamic and competent team. --- Stack: HTML, CSS, JavaScript, PHP', 168 | image: skyspa, 169 | source_code_link: 'https://github.com/bl33h/deepDiveOdysseyRaycasting', 170 | demo_link: 'https://7skyspa.co.uk/', 171 | } 172 | ]; 173 | 174 | const memoji = { 175 | image: [avatar], 176 | }; 177 | 178 | const skills = [ 179 | { 180 | id: 'html', 181 | title: 'HTML', 182 | icon: htmlIcon, 183 | description: 184 | 'I have a strong command of HTML for organizing web pages and generating meaningful content that can be accessed by all users.', 185 | }, 186 | { 187 | id: 'css', 188 | title: 'CSS', 189 | icon: cssIcon, 190 | description: 191 | 'I possess expertise in utilizing CSS to design web pages and craft visually captivating layouts that enhance the overall user experience.', 192 | }, 193 | { 194 | id: 'javascript', 195 | title: 'JavaScript', 196 | icon: jsIcon, 197 | description: 198 | 'I have substantial experience in employing JavaScript to introduce interactivity and functionality into web pages, resulting in dynamic user interfaces.', 199 | }, 200 | { 201 | id: 'react', 202 | title: 'React', 203 | icon: reactIcon, 204 | description: 205 | 'I am well-versed in React, proficient in creating reusable components and managing application state using hooks and context.', 206 | }, 207 | { 208 | id: 'java', 209 | title: 'Java', 210 | icon: javaIcon, 211 | description: 212 | 'I have extensive experience utilizing Java for object-oriented programming (OOP) and implementing data structures.', 213 | }, 214 | { 215 | id: 'aws', 216 | title: 'Amazon Web Services', 217 | icon: awsIcon, 218 | description: 219 | 'I am certified in AWS and proficient in working with EC2 and RDS instances, leveraging the power of cloud computing for scalable and reliable infrastructure.', 220 | }, 221 | { 222 | id: 'figma', 223 | title: 'Figma', 224 | icon: figmaIcon, 225 | description: 226 | 'In my Figma skills, I unleash creativity, designing captivating user interfaces and collaborating seamlessly with designers and developers.', 227 | }, 228 | { 229 | id: 'git', 230 | title: 'Git', 231 | icon: gitIcon, 232 | description: 233 | 'I am proficient in Git, managing code changes, collaborating with others, and resolving conflicts effectively.', 234 | }, 235 | { 236 | id: 'github', 237 | title: 'GitHub', 238 | icon: githubIcon, 239 | description: 240 | 'I am skilled in using GitHub for seamless project collaboration, code sharing, and issue tracking. Through GitHub, I efficiently create and manage repositories and effectively present my work to potential employers.', 241 | }, 242 | { 243 | id: 'psql', 244 | title: 'Postgresql', 245 | icon: psqlIcon, 246 | description: 247 | 'I have a strong command of PostgreSQL, encompassing a wide range of skills such as database normalization, triggers, front-end connectivity, and data analysis using software like Power BI.', 248 | }, 249 | { 250 | id: 'vite', 251 | title: 'Vite', 252 | icon: viteIcon, 253 | description: 254 | 'I have gained considerable experience working with Vite for approximately six months, leveraging its capabilities to build React websites and seamlessly deploy them on platforms like Netlify.', 255 | }, 256 | { 257 | id: 'py', 258 | title: 'Python', 259 | icon: pyIcon, 260 | description: 261 | 'With 3 years of Python experience, I am adept at coding functions and creating graphic interfaces using Tkinter.', 262 | }, 263 | { 264 | id: 'node', 265 | title: 'Node', 266 | icon: nodeIcon, 267 | description: 268 | 'When it comes to building web applications, I prefer using Node as my runtime environment over Yarn. I have expertise in leveraging Node.js to develop powerful and scalable web applications.', 269 | }, 270 | { 271 | id: 'neo', 272 | title: 'Neo4j', 273 | icon: neoIcon, 274 | description: 275 | 'I am knowledgeable in Neo4j, the graph database management system. I have expertise in utilizing GraphOS to build robust recommendation systems, leveraging the strength of graph-based data modeling.', 276 | }, 277 | { 278 | id: 'raspi', 279 | title: 'Raspberry Pi', 280 | icon: raspIcon, 281 | description: 282 | 'I have hands-on experience with Raspberry Pi, where I utilized a virtual Linux machine to execute programs written in assembly language. This allowed me to explore low-level computing and develop efficient code for the Raspberry Pi platform.', 283 | }, 284 | { 285 | id: 'eslint', 286 | title: 'Eslint', 287 | icon: eslintIcon, 288 | description: 289 | 'I utilize ESLint to identify and resolve code issues, as well as standardize the structure of my projects. With ESLint, I ensure code quality and consistency throughout my development process.', 290 | }, 291 | ]; 292 | 293 | const markerSvg = ` 294 | 295 | 296 | `; 297 | 298 | export { 299 | media, 300 | introduction, 301 | projects, 302 | memoji, 303 | skills, 304 | markerSvg, 305 | icons, 306 | }; 307 | --------------------------------------------------------------------------------