import { Routes, Route, HashRouter } from "react-router-dom"; import { Suspense, lazy } from "react"; import Footer from "./components/Footer"; import Header from "./components/Header"; const Home = lazy(() => import("./pages/Home")); const PrivacyPolicies = lazy(() => import("./pages/PrivacyPolicies")); function App() { return (
} /> } />
); } export default App; import Image from "./Image"; import AboutMeImage from "../assets/about.png"; const About = () => { return (
About me image

About Me

I’m a developer with expertise in creating mobile apps for Android, iOS, and web platforms, focusing on solutions that work seamlessly across different devices. From building user-friendly mobile apps to crafting visually appealing websites, I take pride in delivering high-quality results that meet both functional and design expectations.

With a solid understanding of mobile and web development, I’m able to bring creative ideas to life in a way that’s practical and efficient. My goal is to ensure that every project I work on provides a smooth, engaging experience for users.

I approach each project with a focus on collaboration and delivering tailored solutions that align with the needs and goals of the people and businesses I work with.

); }; export default About; import Image from "../components/Image"; interface CardProps { icon: string; imgAlt: string; title: string; text: string; } const Card = (props: CardProps) => { return (
{props.imgAlt}

{props.title}

{props.text}

); }; export default Card; import { useEffect, useRef, useState } from "react"; import "../styles/main.scss"; import sourceCode from "../../source_code.txt"; interface WorkerUpdateMessage { type: "update"; position: number; } const CodeFlow = () => { const [content, setContent] = useState([]); const scrollRef = useRef(null); const workerRef = useRef(null); useEffect(() => { fetch(sourceCode) .then((response) => response.text()) .then((text) => { const extendedContent = text.split("\n"); setContent(extendedContent); }); return () => { if (workerRef.current) { workerRef.current.terminate(); } }; }, []); useEffect(() => { if (content.length === 0) return; const scrollElement = scrollRef.current; if (!scrollElement) return; workerRef.current = new Worker( new URL("../utils/codeFlowWorker.ts", import.meta.url) ); workerRef.current.postMessage({ type: "init", scrollHeight: scrollElement.scrollHeight, }); workerRef.current.postMessage({ type: "start" }); workerRef.current.onmessage = (event: MessageEvent) => { if (event.data.type === "update") { const { position } = event.data; scrollElement.style.transform = `translateY(${position}px)`; } }; return () => { if (workerRef.current) { workerRef.current.terminate(); // Cleanup the worker } }; }, [content]); return (
{content.map((line, index) => (

{line}

))}
); }; export default CodeFlow; import { UiButton } from "../components/UiButton"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faEnvelope } from "@fortawesome/free-solid-svg-icons"; import Link from "../components/Link"; import Image from "../components/Image"; import FacebookLogo from "../assets/logo_facebook.png"; import InstagramLogo from "../assets/logo_instagram.png"; import LinkedInLogo from "../assets/logo_linkedin.png"; import GithubLogo from "../assets/logo_github.png"; const Contact = () => { return (

Contact

If you have a project in mind that you would like to discuss, let's get in touch! Shoot me an e-mail:

} /> } destination="mailto:erman.ergoz@gmail.com" />

Or find me at:

} /> } /> } /> } /> } /> } /> } /> } />
); }; export default Contact; import "../styles/main.scss"; import { UiButton } from "../components/UiButton"; import Link from "../components/Link"; import Image from "../components/Image"; interface DesktopHeaderProps { onClick: (label: string) => () => void; navItems: string[]; logo: string; } const DesktopHeader = (props: DesktopHeaderProps) => { return (
} />
); }; export default DesktopHeader; import { UiButton } from "../components/UiButton"; import { useNavigate } from "react-router-dom"; import Logo from "../assets/logo.png"; import Link from "../components/Link"; import WcagBanner from "../assets/banner-wcag.png"; import GithubBanner from "../assets/logo-github-white.svg"; import Image from "../components/Image"; import { useLocation } from "react-router-dom"; const Footer = () => { const navigate = useNavigate(); const location = useLocation(); const isPolicyPage = location.pathname === "/privacy-policies"; const targetPath = isPolicyPage ? "/" : "/privacy-policies"; const buttonLabel = isPolicyPage ? "Home" : "Privacy Policies"; const handleButtonClick = (navigateTo: string) => () => { if (navigateTo == "/") { window.location.hash = ""; console.log("dfdsfsf") } switch (navigateTo) { default: { navigate(navigateTo); break; } } }; const getCurrentYear = (): number => new Date().getFullYear(); return (
Logo

© 2021 - {getCurrentYear()} Yusuf Erman ERGÖZ

} external={true} /> } />
); }; export default Footer; import "../styles/main.scss"; import Image from "../components/Image"; import Hand from "../assets/ic_greeting.svg"; const Greeting = () => { return (
Vawing hand

{"Hello! My name is Erman"}

{ "I am an application developer and an enthusiastic contributor to open-source projects, driven by a passion for creating exceptional applications." }

); }; export default Greeting; import "../styles/main.scss"; import Logo from "../assets/logo.png"; import DesktopHeader from "./DesktopHeader"; import MobileHeader from "./MobileHeader"; import { useEffect } from "react"; import { useLocation, useNavigate } from "react-router-dom"; const Header = () => { const navigate = useNavigate(); const location = useLocation(); const scrollToSection = (sectionId: string) => { const section = document.getElementById(sectionId); const headerOffset = 100; const elementPosition = section ? section.getBoundingClientRect().top : 0; const offsetPosition = elementPosition + window.scrollY - headerOffset; window.scrollTo({ top: offsetPosition, behavior: "smooth", }); }; const handleButtonClick = (buttonLabel: string = "") => { return () => { const sectionMap: { [key: string]: { path: string; sectionId: string } } = { "Home": { path: "/", sectionId: "home" }, "About Me": { path: "/#about", sectionId: "about" }, "What I Do": { path: "/#whatIDo", sectionId: "whatIDo" }, "Contact Me": { path: "/#contact", sectionId: "contact" }, }; const { path, sectionId } = sectionMap[buttonLabel] || {}; if (path && sectionId) { if (window.location.pathname === "/") { scrollToSection(sectionId); } else { navigate(path); } } }; }; useEffect(() => { if (location.hash) { const targetSection = location.hash.substring(1); scrollToSection(targetSection); } }, [location]); const navItems = ["Home", "About Me", "What I Do", "Contact Me"]; return ( <> ); }; export default Header; import { UiButton } from "./UiButton"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faChevronDown } from "@fortawesome/free-solid-svg-icons"; import Greeting from "../components/Greeting"; const HeroBanner = () => { const onMoreClicked = () => () => { const section = document.getElementById("about"); const headerOffset = 100; const elementPosition = section ? section.getBoundingClientRect().top : 0; const offsetPosition = elementPosition + window.scrollY - headerOffset; window.scrollTo({ top: offsetPosition, behavior: "smooth", }); }; return (
} variant={"inline"} onClick={onMoreClicked()} />
); }; export default HeroBanner; import "../styles/main.scss"; import { ImgHTMLAttributes } from "react"; interface ImageProps extends ImgHTMLAttributes { src: string; alt: string; } function Image({ src, alt, className = "", ...rest }: ImageProps) { return ( {alt} ); } export default Image; import { Link as RouterLink } from "react-router-dom"; import { AnchorHTMLAttributes, ReactNode } from "react"; interface LinkProps extends AnchorHTMLAttributes { destination: string; title?: string; children: ReactNode; external?: boolean; } function Link({ destination, title, children, external = false, ...rest }: LinkProps) { const isExternalLink = external || destination.startsWith("http"); const isHtmlFile = destination.endsWith(".html"); if (isExternalLink || isHtmlFile) { return ( {children} ); } return ( {children} ); } export default Link; import "../styles/main.scss"; import { UiButton } from "../components/UiButton"; import { Sling as Hamburger } from "hamburger-react"; import { useEffect, useRef, useState } from "react"; import Link from "../components/Link"; import Image from "../components/Image"; interface MobileHeaderProps { onClick: (label: string) => () => void; navItems: string[]; logo: string; } const MobileHeader = (props: MobileHeaderProps) => { const [isOpen, setOpen] = useState(false); const menuRef = useRef(null); const hamburgerRef = useRef(null); useEffect(() => { if (!isOpen && hamburgerRef.current) { hamburgerRef.current.focus(); } }, [isOpen]); useEffect(() => { if (!isOpen) return; const menuNode = menuRef.current; if (!menuNode) return; const focusableSelectors = [ "button:not([disabled])", "[href]", "input:not([disabled])", "select:not([disabled])", "textarea:not([disabled])", '[tabindex]:not([tabindex="-1"])', ].join(","); const focusableEls = menuNode.querySelectorAll(focusableSelectors); const firstEl = focusableEls[0]; const lastEl = focusableEls[focusableEls.length - 1]; firstEl?.focus(); function handleKeyDown(e: KeyboardEvent) { if (e.key === "Tab") { if (focusableEls.length === 0) return; if (e.shiftKey) { if (document.activeElement === firstEl) { e.preventDefault(); lastEl.focus(); } } else { if (document.activeElement === lastEl) { e.preventDefault(); firstEl.focus(); } } } else if (e.key === "Escape") { setOpen(false); } } menuNode.addEventListener("keydown", handleKeyDown); return () => { menuNode.removeEventListener("keydown", handleKeyDown); }; }, [isOpen]); const handleNavClick = (label: string) => { const clickAction = props.onClick(label); clickAction(); setOpen(false); }; return (
Logo
handleNavClick("Tr | En")} />
); }; export default MobileHeader; import "../styles/main.scss"; import { ButtonHTMLAttributes, ReactNode } from "react"; interface UiButtonProps extends ButtonHTMLAttributes { variant?: "primary" | "secondary" | "inline"; theme?: "light" | "dark"; isWide?: boolean; label: string; icon?: ReactNode; isFocusable?: boolean; } export function UiButton({ isFocusable = true, variant = "primary", theme = "dark", isWide = false, label, icon, onClick, ...props }: UiButtonProps) { const isWideButton = isWide ? "wide" : ""; return ( ); } import Card from "../components/Card"; import AndroidIcon from "../assets/ic_android.svg"; import AppleIcon from "../assets/ic_apple.svg"; import MultiplatformIcon from "../assets/ic_multiplatform.svg"; import FrontEndIcon from "../assets/ic_frontend.svg"; const WhatIDo = () => { return (

What I do?

I am highly adaptable and able to collaborate effectively on projects outside of my spectrum, depending on your expectations.

); }; export default WhatIDo; import "../styles/layout/layout.scss"; interface LayoutProps { children: React.ReactNode; } function Layout(props: LayoutProps) { return ( <>
{props.children}
); } export default Layout; import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.tsx' ReactDOM.createRoot(document.getElementById('root')!).render( , ) import CodeFlow from "../components/CodeFlow"; import "../styles/main.scss"; import HeroBanner from "../components/HeroBanner"; import Layout from "../layouts/Layout"; import About from "../components/About"; import WhatIDo from "../components/WhatIDo"; import Contact from "../components/Contact"; function Home() { return (
); } export default Home; import React from "react"; import "../styles/main.scss"; import "../components/HeroBanner"; import Layout from "../layouts/Layout"; import policiesData from "../data/policies.json"; import Link from "../components/Link"; const PrivacyPolicies: React.FC = () => { return (

Privacy Policies

    {policiesData.map((policy) => (
  • ))}
); }; export default PrivacyPolicies; $background-dark: #202124; $background-light: #ffffff; $text-dark: #ffffff; $text-light: #000000; $green: #4faf53; $green-dark: #00490a; $hero-banner: monaco,Consolas,Lucida Console,monospace; @font-face { font-family: "Chakra Petch"; src: url("/public/fonts/Chakra_Petch/ChakraPetch-Regular.ttf") format("truetype"); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: "Chakra Petch"; src: url("/public/fonts/Chakra_Petch/ChakraPetch-Bold.ttf") format("truetype"); font-weight: 700; font-style: normal; font-display: swap; } h1 { @apply text-[34px] font-bold; } p { @apply pb-4 py-4; } .about { &__wrapper { @apply lg:flex lg:flex-row; } &__image { @apply max-w-sm mx-auto max-h-56 lg:max-h-80; } &__content { @apply my-auto; } }.card { @apply p-4 mx-4 lg:mx-0 border border-customGreen rounded-lg w-auto min-h-fit lg:w-[300px] lg:min-h-[250px] relative transition-all ease-out duration-300 top-0; &:hover { @apply border-customGreen shadow-lg transition-all ease-out duration-200; top: -4px; } &__title { @apply flex pb-4 space-x-4 justify-center; h1 { @apply text-xl m-auto; } } } .code-flow { @apply h-screen overflow-hidden absolute inset-0 z-[-100]; background: $background-dark; &__content { @apply select-none leading-tight overflow-hidden flex flex-col px-4; } &__line { white-space: pre; margin: 0; padding: 0; font-family: $hero-banner; color: $green-dark; } }.contact { @apply pt-16 pb-40 mx-auto; &__email-wrapper { @apply flex justify-center pt-4; } &__card-container { @apply grid grid-cols-2 gap-4 lg:flex lg:space-x-2 lg:align-middle lg:justify-center; .ui-button { @apply w-full; } } } .desktop-header { @apply z-[100] w-full sticky top-0 items-center justify-between px-4 py-4 hidden lg:flex bg-customDarkBackground; &__logo { @apply flex-shrink-0 h-10; } &__navigation { @apply absolute left-1/2 transform -translate-x-1/2; &__item { @apply flex space-x-16; } } &__language-selector { @apply flex-shrink-0 min-w-[50]; } } .dropdown-selection { &--open { @apply block; } &--closed { @apply hidden; } &__option { @apply flex space-x-2; } } .footer { @apply py-8 px-4 text-white bg-customDarkBackground w-full; &__content { @apply grid grid-cols-1 lg:grid-cols-4 gap-8; &__copyright { @apply pt-7 mx-auto; } &__logo { @apply flex items-center h-16 lg:h-20 mx-auto; } &__banner { @apply flex items-center lg:justify-end space-x-4 h-16 lg:h-20 mx-auto w-36; } &__button { @apply min-w-[120] } } }.greeting { @apply m-0 space-y-16 lg:space-y-32 align-middle text-white; &__title { @apply text-[34px] flex flex-row justify-center space-x-2 lg:space-x-4; &__wave { animation-name: wave-animation; animation-duration: 2.5s; animation-iteration-count: infinite; transform-origin: 70% 70%; } @keyframes wave-animation { 0% { transform: rotate(0deg); } 10% { transform: rotate(14deg); } 20% { transform: rotate(-8deg); } 30% { transform: rotate(14deg); } 40% { transform: rotate(-4deg); } 50% { transform: rotate(10deg); } 60% { transform: rotate(0deg); } 100% { transform: rotate(0deg); } } } &__subtitle { @apply text-[20px] lg:text-[24px]; } } .hero-banner { @apply h-[94vh] text-center pt-[14vh] space-y-16; &__button-holder { position: absolute; @apply bottom-16 font-bold mx-auto w-24 left-0 right-0; } &__chevron-animation { -moz-animation: bounce 2s infinite; -webkit-animation: bounce 2s infinite; animation: bounce 2s infinite; @keyframes bounce { 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } 40% { transform: translateY(-10px); } 60% { transform: translateY(-5px); } } } } .link:focus { @apply outline-none; } .link:focus-visible { @apply outline outline-customGreen outline-offset-4; } .link:hover { @apply text-customGreen; } .mobile-header { @apply z-[100] w-full sticky top-0 flex items-center justify-between px-4 py-4 lg:hidden bg-customDarkBackground text-white; &__menu { &__drop-down { @apply absolute left-0 right-0 top-full overflow-hidden bg-customDarkBackground h-0; &.open { @apply h-60 } &__item { @apply p-4 flex-none text-center; } } } &__logo { @apply absolute left-1/2 transform -translate-x-1/2 h-10; } &__language-selector { @apply flex-shrink-0 w-12; } }.ui-button { @apply flex border rounded-[25px] p-3 px-5 border-customGreen justify-center; align-items: center !important; //leave it as it is &__primary { @apply bg-customDarkBackground; color: $text-dark !important; &:hover { @apply transition-all ease-out duration-200 bg-buttonBackground; color: $text-light !important; } } &__secondary { @apply bg-buttonBackground; color: $text-light !important; &:hover { @apply transition-all ease-out duration-200 bg-customDarkBackground; color: $text-dark !important; } } &--light { @apply text-black; } &--dark { @apply text-white; } &__inline { @apply p-0 border-none; mix-blend-mode: difference; color: white !important; &:hover { background: transparent !important; color: $green !important; } } &:focus { @apply outline-none; } &:focus-visible { @apply outline-2 outline-customGreen outline-offset-4; } span { @apply inline-flex align-middle; align-items: center; //leave it as it is } } .what-i-do { @apply pt-16; &__card-container { @apply lg:flex justify-between pt-8 space-y-4 lg:space-y-0; } }.layout { @apply max-w-[1280px] mx-auto px-4; }@tailwind base; @tailwind components; @tailwind utilities; //Pages @import "../styles/pages/page", "../styles/pages/privacy-policies"; //Variables @import "../styles/base/colors", "../styles/base/fonts", "../styles/base/typography"; //Components @import "../styles/components/code-flow", "../styles/components/hero-banner", "../styles/components/ui-button", "../styles/components/desktop-header", "../styles/components/mobile-header", "../styles/components/footer", "../styles/components/dropdown-selection", "../styles/components/link", "../styles/components/greeting", "../styles/components/about", "../styles/components/what-i-do", "../styles/components/card", "../styles/components/contact"; body { font-family: "Chakra Petch", sans-serif; @apply m-0 select-none; }.page { @apply flex flex-col min-h-screen; &__content { @apply flex-1; } }.privacy-policies { @apply mx-4 space-y-8 py-16; &__list { @apply space-y-2 mt-8 mb-8; } } let position = 0; let scrollHeight = 0; // Define the types of messages exchanged interface WorkerInitMessage { type: "init"; scrollHeight: number; } interface WorkerStartMessage { type: "start"; } type WorkerMessage = WorkerInitMessage | WorkerStartMessage; onmessage = (event: MessageEvent) => { switch (event.data.type) { case "init": scrollHeight = event.data.scrollHeight; break; case "start": const updatePosition = () => { position -= 6; // Move upward by decreasing position if (position <= -scrollHeight + 950) { position = 0; // Reset when content scrolls out of view } // Send the updated position to the main thread postMessage({ type: "update", position }); setTimeout(updatePosition, 16); // Roughly 60 FPS }; updatePosition(); break; default: break; } }; ///