From 347229a9cd820edcc47c9c79180af294d6392dad Mon Sep 17 00:00:00 2001 From: yousifpa98 Date: Tue, 14 Jan 2025 19:29:00 +0100 Subject: [PATCH] labguage and colormode support --- src/App.css | 2 +- src/Context/LangContext.jsx | 29 ++++ src/Context/ThemeContext.jsx | 32 +++++ src/components/Hero.jsx | 16 ++- src/components/LangSelect.jsx | 13 +- src/components/Location.jsx | 10 +- src/components/Mail.jsx | 8 +- src/components/Navigation.jsx | 52 +++++-- src/components/Switch.jsx | 24 ++-- src/components/TallContent.jsx | 6 +- src/components/TechStack.jsx | 16 ++- src/components/mainViews/Projects.jsx | 12 +- .../subComponents/About/Specialties.jsx | 16 ++- .../subComponents/About/TallContentAbout.jsx | 63 ++++++-- .../subComponents/Projects/ProjectCard.jsx | 9 +- .../subComponents/Projects/ProjectsMain.jsx | 19 ++- src/components/subComponents/Toggle.jsx | 7 +- src/css/GridContainer.css | 8 ++ src/css/Hero.css | 7 +- src/css/Location.css | 8 ++ src/css/Mail.css | 9 ++ src/css/Navigation.css | 12 ++ src/css/ProjectCard.css | 16 ++- src/css/Specialties.css | 4 + src/css/Switch.css | 2 +- src/css/TallContentAbout.css | 4 + src/css/TechStack.css | 136 +++++++++--------- src/index.css | 37 ++++- src/main.jsx | 8 +- 29 files changed, 431 insertions(+), 154 deletions(-) create mode 100644 src/Context/LangContext.jsx create mode 100644 src/Context/ThemeContext.jsx diff --git a/src/App.css b/src/App.css index 3430c6d..701846a 100644 --- a/src/App.css +++ b/src/App.css @@ -4,5 +4,5 @@ main { display: flex; align-items: center; justify-content: center; - padding: 2rem; + /* padding: 2rem; */ } diff --git a/src/Context/LangContext.jsx b/src/Context/LangContext.jsx new file mode 100644 index 0000000..fe4d760 --- /dev/null +++ b/src/Context/LangContext.jsx @@ -0,0 +1,29 @@ +import React, { createContext, useContext, useEffect, useState } from "react"; + +const LangContext = createContext(); + +export const useLang = () => { + return useContext(LangContext); +}; + +const LangProvider = ({ children }) => { + const [language, setLanguage] = useState(() => { + return localStorage.getItem("language") || "en-GB"; + }); + + useEffect(() => { + localStorage.setItem("language", language); + }, [language]); + + const toggleLanguage = () => { + setLanguage((prevLang) => (prevLang === "en-GB" ? "de-DE" : "en-GB")); + }; + + return ( + + {children} + + ); +}; + +export default LangProvider; diff --git a/src/Context/ThemeContext.jsx b/src/Context/ThemeContext.jsx new file mode 100644 index 0000000..336019f --- /dev/null +++ b/src/Context/ThemeContext.jsx @@ -0,0 +1,32 @@ +import React, { createContext, useContext, useEffect, useState } from "react"; + +// Create the ThemeContext +const ThemeContext = createContext(); + +// Custom hook for consuming ThemeContext +export const useTheme = () => { + return useContext(ThemeContext); +}; + +const ThemeProvider = ({ children }) => { + const [colormode, setColormode] = useState(() => { + return localStorage.getItem("colormode") || "dark"; // Default to dark mode + }); + + useEffect(() => { + localStorage.setItem("colormode", colormode); + document.documentElement.setAttribute("data-theme", colormode); // For global CSS styling + }, [colormode]); + + const toggleColorMode = () => { + setColormode((prevMode) => (prevMode === "dark" ? "light" : "dark")); + }; + + return ( + + {children} + + ); +}; + +export default ThemeProvider; diff --git a/src/components/Hero.jsx b/src/components/Hero.jsx index 4b512ad..a3638bd 100644 --- a/src/components/Hero.jsx +++ b/src/components/Hero.jsx @@ -1,21 +1,29 @@ import React, { useState } from "react"; import "../css/Hero.css"; import "animate.css"; +import { useTheme } from "../Context/ThemeContext"; +import { useLang } from "../Context/LangContext"; const Hero = ({ initialAnimation, onMouseEnter, onAnimationEnd }) => { const [animation, setAnimation] = useState(initialAnimation); - + const { colormode } = useTheme(); + const { language } = useLang(); return (
onMouseEnter(setAnimation)} onAnimationEnd={() => onAnimationEnd(setAnimation)} >

- Hi, I'm Yousif.
+ {language === "en-GB" ? "Hi, I'm Yousif." : "Hi, ich bin Yousif."}{" "} +
{" "} - I'm a Full-Stack Developer from Germany. + {language === "en-GB" + ? "I'm a Full-Stack Developer from" + : "Ich bin ein Full-Stack Entwickler aus"}{" "} +
+ {language === "en-GB" ? "Germany" : "Köln"}.

); diff --git a/src/components/LangSelect.jsx b/src/components/LangSelect.jsx index 3965fc6..4c413fc 100644 --- a/src/components/LangSelect.jsx +++ b/src/components/LangSelect.jsx @@ -2,18 +2,23 @@ import React from "react"; import "../css/LangSelect.css"; import { useState } from "react"; import Toggle from "./subComponents/Toggle"; +import { useTheme } from "../Context/ThemeContext"; +import { useLang } from "../Context/LangContext"; const LangSelect = ({ initialAnimation, onMouseEnter, onAnimationEnd }) => { const [animation, setAnimation] = useState(initialAnimation); + + const { colormode } = useTheme(); + const { language, toggleLanguage } = useLang(); + return (
onMouseEnter(setAnimation)} */ + className={`langSelect container animate__animated ${animation} ${colormode}`} + /* onMouseEnter={() => onMouseEnter(setAnimation)} */ onAnimationEnd={() => onAnimationEnd(setAnimation)} >
🇬🇧
- -
🇩🇪
+
🇩🇪
); }; diff --git a/src/components/Location.jsx b/src/components/Location.jsx index 0c9153b..12105af 100644 --- a/src/components/Location.jsx +++ b/src/components/Location.jsx @@ -1,13 +1,19 @@ import React from "react"; import "../css/Location.css"; import LocationPin from "../assets/icons/navIcons/location-pin.svg?react"; +import { useTheme } from "../Context/ThemeContext"; +import { useLang } from "../Context/LangContext"; const Location = () => { + const { colormode } = useTheme(); + const { language } = useLang(); + return ( -
+

- Cologne, Germany + {`${language === "en-GB" ? "Cologne" : "Köln"}`},{" "} + {`${language === "en-GB" ? "Germany" : "Deutschland"}`}

); diff --git a/src/components/Mail.jsx b/src/components/Mail.jsx index aac2a31..a06a95c 100644 --- a/src/components/Mail.jsx +++ b/src/components/Mail.jsx @@ -2,15 +2,19 @@ import React from "react"; import "../css/Mail.css"; import { useState } from "react"; import EnvelopeIcon from "../assets/icons/navIcons/envelope.svg?react"; +import { useTheme } from "../Context/ThemeContext"; const Mail = ({ initialAnimation, onMouseEnter, onAnimationEnd }) => { const [animation, setAnimation] = useState(initialAnimation); const emailUser = "yousif.paulus"; const domain = "hotmail.de"; + + const { colormode } = useTheme(); + return (
onMouseEnter(setAnimation)} */ + className={`eMail container animate__animated ${animation} ${colormode}`} + /* onMouseEnter={() => onMouseEnter(setAnimation)} */ onAnimationEnd={() => onAnimationEnd(setAnimation)} > { const [animation, setAnimation] = useState(initialAnimation); + const { colormode } = useTheme(); + const navItems = [ - { name: "Home", to: "/", icon: HouseIcon, id: 1 }, - { name: "About", to: "/about", icon: AddressCardIcon, id: 2 }, - { name: "Experience", to: "/workExp", icon: SuitcaseIcon, id: 3 }, - { name: "Projects", to: "/projects", icon: CodeIcon, id: 4 }, - { name: "Contact", to: "/contact", icon: EnvelopeIcon, id: 5 }, - { name: "CV", to: "", icon: DownloadIcon, id: 6 }, + { name: { enGB: "Home", deDE: "Start" }, to: "/", icon: HouseIcon, id: 1 }, + { + name: { enGB: "About", deDE: "Über Mich" }, + to: "/about", + icon: AddressCardIcon, + id: 2, + }, + { + name: { enGB: "Experience", deDE: "Erfahrung" }, + to: "/workExp", + icon: SuitcaseIcon, + id: 3, + }, + { + name: { enGB: "Projects", deDE: "Projekte" }, + to: "/projects", + icon: CodeIcon, + id: 4, + }, + { + name: { enGB: "Contact", deDE: "Kontakt" }, + to: "/contact", + icon: EnvelopeIcon, + id: 5, + }, + { + name: { enGB: "CV", deDE: "Lebenslauf" }, + to: "", + icon: DownloadIcon, + id: 6, + }, ]; + + const { language } = useLang(); return (
onMouseEnter(setAnimation)} */ onAnimationEnd={() => onAnimationEnd(setAnimation)} > @@ -38,11 +69,14 @@ const Navigation = ({ initialAnimation, onMouseEnter, onAnimationEnd }) => { clsx( "navLink", { active: isActive }, - item.name === "CV" && "cv" // Add "cv" class if item.name is "CV" + item.name.enGB === "CV" && "cv" // Add "cv" class if item.name is "CV" ) } > - {item.name} + + {language === "en-GB" ? item.name.enGB : item.name.deDE} + {" "} + ); diff --git a/src/components/Switch.jsx b/src/components/Switch.jsx index 7629a88..1be8867 100644 --- a/src/components/Switch.jsx +++ b/src/components/Switch.jsx @@ -4,6 +4,7 @@ import "animate.css"; import styled from "styled-components"; import SunIcon from "../assets/icons/colorModeToggle/sun.svg?react"; import MoonIcon from "../assets/icons/colorModeToggle/moon.svg?react"; +import { useTheme } from "../Context/ThemeContext"; const SwitchBtn = styled.button` background-color: ${(props) => @@ -20,8 +21,8 @@ const SwitchBtn = styled.button` `; const SwitchContainer = styled.div` - transition: background-color 1s ease; grid-area: 8 / 4 / 10 / 5; + transition: background-color 1s ease; background-color: ${(props) => props.colormode === "dark" ? "#131862" : "#69d0ff"}; display: flex; @@ -46,28 +47,19 @@ const PlanetsContainer = styled.div` `; const Switch = ({ initialAnimation, onMouseEnter, onAnimationEnd }) => { - const [animation, setAnimation] = useState(initialAnimation); - const [colormode, setcolormode] = useState(() => { - // Retrieve initial color mode from localStorage or default to "dark" - return localStorage.getItem("colormode") || "dark"; - }); + const { colormode, toggleColorMode } = useTheme(); const [rotation, setRotation] = useState(0); - useEffect(() => { - // Save the current color mode to localStorage whenever it changes - localStorage.setItem("colormode", colormode); - }, [colormode]); - - const toggleColorMode = () => { - setcolormode((prevMode) => (prevMode === "dark" ? "light" : "dark")); + const handleClick = () => { + toggleColorMode(); setRotation((prevRotation) => prevRotation + 90); }; return ( onAnimationEnd(setAnimation)} + className={`container animate__animated ${initialAnimation}`} + onAnimationEnd={() => onAnimationEnd && onAnimationEnd()} >
@@ -100,7 +92,7 @@ const Switch = ({ initialAnimation, onMouseEnter, onAnimationEnd }) => {
diff --git a/src/components/TallContent.jsx b/src/components/TallContent.jsx index 2df331a..6395bbd 100644 --- a/src/components/TallContent.jsx +++ b/src/components/TallContent.jsx @@ -1,12 +1,16 @@ import React, { useState } from "react"; import "../css/TallContent.css"; +import { useTheme } from "../Context/ThemeContext"; +import { useLang } from "../Context/LangContext"; const TallContent = ({ initialAnimation, onMouseEnter, onAnimationEnd }) => { const [animation, setAnimation] = useState(initialAnimation); + const { colormode } = useTheme(); + const { language } = useLang(); return (
onMouseEnter(setAnimation)} onAnimationEnd={() => onAnimationEnd(setAnimation)} > diff --git a/src/components/TechStack.jsx b/src/components/TechStack.jsx index e5c15b9..db918a4 100644 --- a/src/components/TechStack.jsx +++ b/src/components/TechStack.jsx @@ -18,6 +18,8 @@ import Linux from "../assets/icons/skill-icons/icons/Linux-Dark.svg?react"; import "../css/TechStack.css"; import { Link } from "react-router-dom"; import "animate.css"; +import { useTheme } from "../Context/ThemeContext"; +import { useLang } from "../Context/LangContext"; const TechStack = ({ initialAnimation, @@ -95,17 +97,19 @@ const TechStack = ({ ]; const [animation, setAnimation] = useState(initialAnimation); - + const { colormode } = useTheme(); + const { language } = useLang(); return (
onMouseEnter(setAnimation)} */ + /* onMouseEnter={() => onMouseEnter(setAnimation)} */ onAnimationEnd={() => onAnimationEnd(setAnimation)} >

Tech Stack

@@ -125,11 +129,13 @@ const TechStack = ({ to="#" className="techStackShowMore" onClick={(e) => { - e.preventDefault(); // Prevent default link behavior - onExpandToggle(); // Toggle the expanded state + e.preventDefault(); + onExpandToggle(); }} > - {isExpanded ? "Show Less" : "Show More"} {/* Toggle link text */} + {isExpanded + ? `${language === "en-GB" ? "Show Less" : "Weniger"}` + : `${language === "en-GB" ? "Show More" : "Mehr"}`}
); diff --git a/src/components/mainViews/Projects.jsx b/src/components/mainViews/Projects.jsx index 517fdf7..f1922f4 100644 --- a/src/components/mainViews/Projects.jsx +++ b/src/components/mainViews/Projects.jsx @@ -18,15 +18,18 @@ import animedbImg1 from "../../assets/img/projects/animedb1.png"; import animedbImg2 from "../../assets/img/projects/animedb2.png"; import animedbImg3 from "../../assets/img/projects/animedb3.png"; import strogasoImg from "../../assets/img/projects/strogaso.png"; +import { useLang } from "../../Context/LangContext"; const Projects = () => { +const {language} = useLang() + const projectArr = [ { name: "inkspire.", urls: { ghUrl: "https://github.com/yousifpa98/inkspire" }, year: "2024", - job: "freelance", - imgs: [inkspireImg], + job: language === "en-GB" ? "freelance" : "freiberuflich", + imgs: [inkspireImg], id: 1, }, { @@ -36,7 +39,7 @@ const Projects = () => { liveUrl: "https://druckerei-eberwein.de/", }, year: "2024", - job: "freelance", + job: language === "en-GB" ? "freelance" : "freiberuflich", imgs: [debImg], id: 2, }, @@ -47,7 +50,7 @@ const Projects = () => { liveUrl: "https://otakucritics.netlify.app/", }, year: "2024", - job: "personal project", + job: language === "en-GB" ? "personal project" : "pers. Projekt", imgs: [animeDBImg], id: 3, }, @@ -76,6 +79,7 @@ const Projects = () => { const handleAnimationEnd = (setAnimation) => { setAnimation(""); // Clear animation to prevent re-triggering }; + return (
diff --git a/src/components/subComponents/About/Specialties.jsx b/src/components/subComponents/About/Specialties.jsx index a26971a..09bb75a 100644 --- a/src/components/subComponents/About/Specialties.jsx +++ b/src/components/subComponents/About/Specialties.jsx @@ -1,21 +1,25 @@ import React from "react"; import "../../../css/Specialties.css"; import { useState } from "react"; +import { useTheme } from "../../../Context/ThemeContext"; +import { useLang } from "../../../Context/LangContext"; const Specialties = ({ initialAnimation, onMouseEnter, onAnimationEnd }) => { const [animation, setAnimation] = useState(initialAnimation); + const { colormode } = useTheme(); + const { language } = useLang(); return (
onMouseEnter(setAnimation)} onAnimationEnd={() => onAnimationEnd(setAnimation)} >

- I’m a fullstack developer who loves creating web applications that are - functional and easy to use. My go-to tools are React, Node.js, and - TypeScript, and I enjoy working on both the front-end and back-end. I - focus on clean, practical solutions that work in the real world and - approach every project with curiosity and attention to detail. + {`${ + language === "en-GB" + ? "I'm a fullstack developer who loves creating web applications that are functional and easy to use. My go-to tools are React, Node.js, and TypeScript, and I enjoy working on both the front-end and back-end. I focus on clean, practical solutions that work in the real world and approach every project with curiosity and attention to detail." + : "Ich liebe es, funktionale und einfach zu bedienende Webanwendungen zu erstellen. Meine bevorzugten Tools sind React, Node.js und TypeScript, und ich arbeite gerne sowohl am Frontend als auch am Backend. Ich konzentriere mich auf saubere, praktische Lösungen, die in der realen Welt funktionieren, und gehe jedes Projekt mit Neugier und Liebe zum Detail an." + }`}

); diff --git a/src/components/subComponents/About/TallContentAbout.jsx b/src/components/subComponents/About/TallContentAbout.jsx index 8acd668..1b83fd6 100644 --- a/src/components/subComponents/About/TallContentAbout.jsx +++ b/src/components/subComponents/About/TallContentAbout.jsx @@ -1,6 +1,8 @@ import React from "react"; import { useState } from "react"; import "../../../css/TallContentAbout.css"; +import { useTheme } from "../../../Context/ThemeContext"; +import { useLang } from "../../../Context/LangContext"; const TallContentAbout = ({ initialAnimation, @@ -9,51 +11,86 @@ const TallContentAbout = ({ }) => { const [animation, setAnimation] = useState(initialAnimation); + const { colormode } = useTheme(); + const { language } = useLang(); + return (
onMouseEnter(setAnimation)} onAnimationEnd={() => onAnimationEnd(setAnimation)} >
-

Some Fun-Facts about me:

+

{`${ + language === "en-GB" + ? "Some Fun-Facts about me:" + : "Ein paar Fun-Facts über mich:" + }`}

  • - 2300+ Chess.com blitz rating and a lifelong love for strategy. + {`${ + language === "en-GB" + ? "2300+ Chess.com blitz rating and a lifelong love for strategy." + : "2300+ Blitz-Rating auf Chess.com und eine lange Liebe für Strategie" + }`}

  • - Big fan of tycoon simulation games—I could spend hours building - and managing virtual worlds. + {`${ + language === "en-GB" + ? "Big fan of tycoon simulation games—I could spend hours building and managing virtual worlds." + : "Großer Fan von Tycoon-Sim Spielen—Ich könnte Stunden damit verbringen, virtuelle Welten zu managen." + }`}

  • - I love Asian food, especially Japanese cuisine, and enjoy trying - new recipes. + {`${ + language === "en-GB" + ? "I love Asian food, especially Japanese cuisine, and enjoy trying new recipes." + : "Ich liebe asiatische Küche, besonders die japanische, und probiere gern neue Rezepte aus." + }`}

  • -

    Football is my passion (and no, I won’t call it soccer).

    +

    + {`${ + language === "en-GB" + ? "Football is my passion (and no, I won't call it soccer)." + : "Fußball ist eine meiner liebsten Leidenschaften." + }`} +

  • - I have a guilty pleasure for sitcoms like The Big Bang Theory and - can’t resist a good Taylor Swift track. + {`${ + language === "en-GB" + ? "I have a guilty pleasure for sitcoms like The Big Bang Theory and can't resist a good Taylor Swift track." + : "Ich habe eine Schwäche für Sitcoms wie 'The Big Bang Theory' und kann einem guten Taylor Swift Song nicht wiederstehen." + }`}

  • {/*
  • Hiking is one of my favorite ways to relax and recharge.

  • */}
  • -

    I enjoy baking, especially experimenting with new desserts.

    +

    + {`${ + language === "en-GB" + ? "I enjoy baking, especially experimenting with new desserts.." + : "Ich backe gern und experimentiere gerne mit neuen Desserts." + }`} +

  • - I’ve been drawing and painting since I was young, and it’s still - one of my favorite creative outlets. + {`${ + language === "en-GB" + ? "I've been drawing and painting since I was young, and it's still one of my favorite creative outlets." + : "Ich zeichne und male seit meiner Kindheit - es ist bis heute eines meiner liebsten kreativen Hobbies." + }`}

diff --git a/src/components/subComponents/Projects/ProjectCard.jsx b/src/components/subComponents/Projects/ProjectCard.jsx index f52790a..bd8512a 100644 --- a/src/components/subComponents/Projects/ProjectCard.jsx +++ b/src/components/subComponents/Projects/ProjectCard.jsx @@ -2,10 +2,13 @@ import React from "react"; import "../../../css/ProjectCard.css"; import GitHubIcon from "../../../assets/icons/socials/square-github.svg?react"; import GlobeIcon from "../../../assets/icons/socials/globe.svg?react"; +import { useTheme } from "../../../Context/ThemeContext"; const ProjectCard = ({ project }) => { + const { colormode } = useTheme(); + return ( -
+
1 ? "imgs" : "img"}> {project.imgs.map((img, index) => ( {

{project.job}

- {Object.entries(project.urls).map(([key, value]) => { + {Object.entries(project.urls).map(([key, value]) => { // Determine the correct icon to render based on the key const Icon = key === "ghUrl" ? GitHubIcon : GlobeIcon; @@ -39,7 +42,7 @@ const ProjectCard = ({ project }) => { rel="noopener noreferrer" href={value} > - + ); })} diff --git a/src/components/subComponents/Projects/ProjectsMain.jsx b/src/components/subComponents/Projects/ProjectsMain.jsx index 84cfb10..16ca394 100644 --- a/src/components/subComponents/Projects/ProjectsMain.jsx +++ b/src/components/subComponents/Projects/ProjectsMain.jsx @@ -2,6 +2,8 @@ import React from "react"; import "../../../css/ProjectsMain.css"; import { useState } from "react"; import ProjectCard from "./ProjectCard"; +import { useTheme } from "../../../Context/ThemeContext"; +import { useLang } from "../../../Context/LangContext"; const ProjectsMain = ({ initialAnimation, @@ -11,17 +13,24 @@ const ProjectsMain = ({ }) => { const [animation, setAnimation] = useState(initialAnimation); + const { colormode } = useTheme(); + const { language } = useLang(); + return (
onMouseEnter(setAnimation)} */ onAnimationEnd={() => onAnimationEnd(setAnimation)} > -

Some of my latest projects:

+

{`${ + language === "en-GB" + ? "Some of my latest projects:" + : "Ein paar meiner letzten Projekte:" + }`}

- {projects.map((project) => ( - - ))} + {projects.map((project) => ( + + ))}
); diff --git a/src/components/subComponents/Toggle.jsx b/src/components/subComponents/Toggle.jsx index c984112..26c4b6f 100644 --- a/src/components/subComponents/Toggle.jsx +++ b/src/components/subComponents/Toggle.jsx @@ -1,12 +1,11 @@ -import React, { useState } from "react"; +import React from "react"; import "../../css/Toggle.css"; -const Toggle = () => { - const [toggled, setToggled] = useState(false); +const Toggle = ({ toggled, onToggle }) => { return ( diff --git a/src/css/GridContainer.css b/src/css/GridContainer.css index be2b9e8..ef8caef 100644 --- a/src/css/GridContainer.css +++ b/src/css/GridContainer.css @@ -4,6 +4,7 @@ grid-template-rows: repeat(9, 1fr); gap: 10px; width: 50%; + min-width: 960px; height: 80%; } @@ -13,6 +14,13 @@ border-radius: 0.5rem; border: 0.5px solid rgb(73, 73, 73); box-shadow: 0 0 10px -5px rgba(184, 184, 184, 0.2); + transition: all 0.3s ease; +} + +.container.light { + background-color: white; + border: 0.5px solid black; + box-shadow: 0 0 10px -5px rgba(78, 78, 78, 0.4); } .container:hover { diff --git a/src/css/Hero.css b/src/css/Hero.css index c4ea066..3c7ea8a 100644 --- a/src/css/Hero.css +++ b/src/css/Hero.css @@ -1,6 +1,7 @@ .hero { grid-area: 1 / 1 / 4 / 5; animation-duration: 1.5s; + transition: all 0.3s ease; } .hero p span { @@ -10,5 +11,9 @@ .hero p { font-size: 2rem; - color: rgb(151, 151, 151); + color: rgb(90, 90, 90); +} + +.hero.light p span { + color: rgb(40, 40, 40); } diff --git a/src/css/Location.css b/src/css/Location.css index dc30378..33a307d 100644 --- a/src/css/Location.css +++ b/src/css/Location.css @@ -6,3 +6,11 @@ color: white; font-size: 1rem; } + +.location.light { + color: #333; +} + +.location.light .navIcon { + fill: #333; +} diff --git a/src/css/Mail.css b/src/css/Mail.css index 1f7c4b5..59db867 100644 --- a/src/css/Mail.css +++ b/src/css/Mail.css @@ -17,3 +17,12 @@ color: rgb(151, 151, 151); font-size: 0.8rem; } + + +.eMail.light .emailAnchor { + color: #333; +} + +.eMail.light .copyright { + color: rgb(102, 102, 102); +} \ No newline at end of file diff --git a/src/css/Navigation.css b/src/css/Navigation.css index 5ed5fcf..aede446 100644 --- a/src/css/Navigation.css +++ b/src/css/Navigation.css @@ -40,3 +40,15 @@ font-weight: bold; transition: font-weight 0.3s ease, border-bottom 0.3s ease; } + +.navigation.light .navLink { + color: #333; +} + +.navigation.light .navLink.active span { + border-color: #333; +} + +.navigation.light .navIcon { + fill: #333; +} diff --git a/src/css/ProjectCard.css b/src/css/ProjectCard.css index 20af850..f7dfb0b 100644 --- a/src/css/ProjectCard.css +++ b/src/css/ProjectCard.css @@ -39,10 +39,6 @@ margin-bottom: 0.245rem; } -.projectInfo h3 { - color: white; -} - .projectInfo h3 span { color: rgb(151, 151, 151); font-size: 1rem; @@ -70,3 +66,15 @@ justify-content: flex-start; gap: 0.5rem; } + +.projectCard.light .projectInfo h3 span, .projectCard.light .projectJob{ + color: rgb(90, 90, 90); +} + +.projectCard.light .socialIcon { + fill: #333; +} + +.projectCard.light .socialIcon:hover { + fill: #6e6e6e; +} \ No newline at end of file diff --git a/src/css/Specialties.css b/src/css/Specialties.css index 0477612..5b74f10 100644 --- a/src/css/Specialties.css +++ b/src/css/Specialties.css @@ -7,3 +7,7 @@ font-size: 1.2rem; text-align: justify; } + +.specialties.light .specialtyText { + color: #333; +} diff --git a/src/css/Switch.css b/src/css/Switch.css index ebf05e4..5dc81ea 100644 --- a/src/css/Switch.css +++ b/src/css/Switch.css @@ -59,7 +59,7 @@ .moon2 { bottom: 25px; left: 50%; - transform: translateX(-50%); + transform: translateX(-50%) rotate(180deg); } /* Left corner */ diff --git a/src/css/TallContentAbout.css b/src/css/TallContentAbout.css index 6bb4bf8..e8cf0ae 100644 --- a/src/css/TallContentAbout.css +++ b/src/css/TallContentAbout.css @@ -35,3 +35,7 @@ color: white; font-size: 1.1rem; } + +.tallContentAbout.light .funFactList li p { + color: #333; +} diff --git a/src/css/TechStack.css b/src/css/TechStack.css index 4a811ef..2c0463f 100644 --- a/src/css/TechStack.css +++ b/src/css/TechStack.css @@ -1,66 +1,74 @@ .techStackContainer { - grid-area: 4 / 1 / 8 / 5; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - animation-duration: 1s; + grid-area: 4 / 1 / 8 / 5; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + animation-duration: 1s; +} + +.techStackContainer.expanded { + grid-area: 4 / 1 / 10 / 5; + min-width: 356.43px; +} + +.techStackContainer h2 { + margin-bottom: 10px; + align-self: flex-start; +} + +.techIcon { + width: 4rem; + height: 4rem; + filter: grayscale(0.7); + transition: transform 0.3s ease, filter 0.3s ease; +} + +.techStackContainer.light .techIcon { + filter: none; +} + +.techIcon:hover { + filter: none; + animation: tada 1s; + cursor: pointer; +} + +.techStack { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 1rem; +} + +.techStackShowMore { + font-size: 1.2rem; + color: rgb(151, 151, 151); + text-decoration: none; + border-bottom: 1px solid rgb(151, 151, 151); + /* align-self: flex-start; */ +} + +.techStackContainer.light .techStackShowMore { + color: rgb(61, 61, 61); + border-color: rgb(61, 61, 61); +} + +@keyframes techIconHover { + 10% { + transform: scale(); } - - .techStackContainer.expanded { - grid-area: 4 / 1 / 10 / 5; - min-width: 356.43px; - } - - .techStackContainer h2 { - margin-bottom: 10px; - align-self: flex-start; - } - - .techIcon { - width: 4rem; - height: 4rem; - filter: grayscale(0.7); - transition: transform 0.3s ease, filter 0.3s ease; - } - - .techIcon:hover { - filter: none; - animation: tada 1s; - cursor: pointer; - } - - .techStack { - display: flex; - align-items: center; - justify-content: center; - flex-wrap: wrap; - gap: 10px; - margin-bottom: 1rem; - } - - .techStackShowMore { - font-size: 1.2rem; - color: rgb(151, 151, 151); - text-decoration: none; - border-bottom: 1px solid rgb(151, 151, 151); - /* align-self: flex-start; */ - } - - @keyframes techIconHover { - 10% { - transform: scale(); - } - } - - /* Smooth expand/collapse animations */ - .techStackContainer { - max-height: 320px; /* Initial max-height */ - overflow: hidden; - transition: max-height 1s ease-in-out; - } - - .techStackContainer.expanded { - max-height: 600px; /* Expanded max-height */ - } - \ No newline at end of file +} + +/* Smooth expand/collapse animations */ +.techStackContainer { + max-height: 320px; /* Initial max-height */ + overflow: hidden; + transition: max-height 1s ease-in-out; +} + +.techStackContainer.expanded { + max-height: 600px; /* Expanded max-height */ +} diff --git a/src/index.css b/src/index.css index b5ec9c2..ed1abc4 100644 --- a/src/index.css +++ b/src/index.css @@ -1,3 +1,4 @@ +/* Reset and defaults */ * { margin: 0; padding: 0; @@ -6,12 +7,40 @@ body { font-family: "SF Pro Display", sans-serif; + transition: background-color 0.5s ease; +} + +[data-theme="dark"] body { background-color: #000000; - background-color: #000000; + background-image: linear-gradient(43deg, #000000 29%, #454545 75%, #000 100%); +} + +[data-theme="light"] body { + background-color: #ffffff; background-image: linear-gradient( 43deg, - #000000 29%, - #454545 75%, - #000 100% + #ffffff 29%, + #d7d7d7 75%, + #ffffff 100% ); } + +/* Dark theme */ +[data-theme="dark"] h1, +[data-theme="dark"] h2, +[data-theme="dark"] h3, +[data-theme="dark"] h4, +[data-theme="dark"] h5, +[data-theme="dark"] h6 { + color: white; +} + +/* Light theme */ +[data-theme="light"] h1, +[data-theme="light"] h2, +[data-theme="light"] h3, +[data-theme="light"] h4, +[data-theme="light"] h5, +[data-theme="light"] h6 { + color: #333; +} diff --git a/src/main.jsx b/src/main.jsx index 4c7dc41..708ab62 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -3,9 +3,15 @@ import "./index.css"; import App from "./App.jsx"; import { BrowserRouter } from "react-router-dom"; import "./css/fonts.css"; +import ThemeProvider from "./Context/ThemeContext.jsx"; +import LangProvider from "./Context/LangContext.jsx"; createRoot(document.getElementById("root")).render( - + + + + + );