261 lines
7.6 KiB
JavaScript
261 lines
7.6 KiB
JavaScript
import React, { useState, useEffect } from "react";
|
|
import { Layout, Space, Spin } from "antd";
|
|
import { useLocation, useNavigate } from "react-router-dom";
|
|
import { AnimatePresence, motion } from "framer-motion";
|
|
import ParticlesBackground from "./components/ParticlesBackground";
|
|
import { useMediaQuery } from "react-responsive";
|
|
import { useKeycloak } from "./utils/KeycloakProvider";
|
|
import MainView from "./views/MainView";
|
|
import NotFoundView from "./views/NotFoundView";
|
|
import CVView from "./views/CVView";
|
|
import ContactView from "./views/ContactView";
|
|
import SocialsView from "./views/SocialsView";
|
|
import ExperienceView from "./views/ExperienceView";
|
|
import BlogsView from "./views/BlogsView";
|
|
import BlogView from "./views/BlogView";
|
|
import CacheReloadView from "./utils/CacheReloadView";
|
|
import { LinkOutlined, UserOutlined, LoadingOutlined } from "@ant-design/icons";
|
|
|
|
const { Content } = Layout;
|
|
const { Footer } = Layout;
|
|
|
|
const App = () => {
|
|
const location = useLocation(); // This gives you access to location object
|
|
const navigate = useNavigate(); // To navigate programmatically
|
|
|
|
const isMobile = useMediaQuery({ maxWidth: 600 });
|
|
|
|
const { isAuthenticated, loading, keycloak } = useKeycloak();
|
|
|
|
// Get the query parameter from the URL
|
|
const getQueryParam = (param) => {
|
|
const searchParams = new URLSearchParams(location.search); // Use location.search directly
|
|
return searchParams.get(param) || "index"; // Default to "index" if param is not found
|
|
};
|
|
|
|
// Initialize state with query parameters
|
|
const [currentView, setCurrentView] = useState(getQueryParam("to"));
|
|
const referrer = getQueryParam("r");
|
|
|
|
useEffect(() => {
|
|
const queryParams = new URLSearchParams();
|
|
|
|
// Add the "to" parameter to the query
|
|
queryParams.set("to", currentView);
|
|
|
|
// If the referrer exists, add it to the query as well
|
|
if (referrer) {
|
|
queryParams.set("r", referrer);
|
|
}
|
|
|
|
// Navigate with the updated query string
|
|
navigate(`?${queryParams.toString()}`);
|
|
|
|
// Initial body setup to prevent scrollbars
|
|
document.body.style.overflow = "hidden";
|
|
document.body.style.margin = "0";
|
|
document.body.style.padding = "0";
|
|
}, [currentView, referrer, navigate]);
|
|
|
|
const fadeVariants = {
|
|
initial: {
|
|
clipPath: "polygon(0 0, 0 0, 0 100%, 0% 100%)",
|
|
opacity: 0,
|
|
},
|
|
animate: {
|
|
clipPath: "polygon(0 0, 100% 0, 100% 100%, 0 100%)",
|
|
opacity: 1,
|
|
transition: {
|
|
duration: 0.7,
|
|
ease: "easeInOut",
|
|
},
|
|
},
|
|
exit: {
|
|
clipPath: "polygon(100% 0, 100% 0, 100% 100%, 100% 100%)",
|
|
opacity: 0,
|
|
transition: {
|
|
duration: 0.7,
|
|
ease: "easeInOut",
|
|
},
|
|
},
|
|
};
|
|
|
|
// Render different views based on currentView state
|
|
const renderView = () => {
|
|
if (currentView.startsWith("blog-")) {
|
|
const blogSlug = currentView.replace("blog-", "");
|
|
return <BlogView setCurrentView={setCurrentView} slug={blogSlug} />;
|
|
}
|
|
switch (currentView) {
|
|
case "index":
|
|
return <MainView setCurrentView={setCurrentView} />;
|
|
case "cv":
|
|
return <CVView setCurrentView={setCurrentView} />;
|
|
case "experience":
|
|
return <ExperienceView setCurrentView={setCurrentView} />;
|
|
case "blogs":
|
|
return <BlogsView setCurrentView={setCurrentView} />;
|
|
case "contact":
|
|
return <ContactView setCurrentView={setCurrentView} />;
|
|
case "socials":
|
|
return (
|
|
<SocialsView setCurrentView={setCurrentView} referrer={referrer} />
|
|
);
|
|
case "cacheReload":
|
|
return <CacheReloadView setCurrentView={setCurrentView} />;
|
|
default:
|
|
return <NotFoundView setCurrentView={setCurrentView} />;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
position: "fixed",
|
|
top: 0,
|
|
left: 0,
|
|
width: "100%",
|
|
height: "100%",
|
|
overflow: "hidden",
|
|
}}
|
|
>
|
|
<ParticlesBackground />
|
|
<div
|
|
style={{
|
|
background: "rgba(255, 255, 255, 0.0)",
|
|
backdropFilter: "blur(50px)",
|
|
width: "100%",
|
|
height: "100%",
|
|
top: 0,
|
|
left: 0,
|
|
position: "absolute",
|
|
display: "inline",
|
|
}}
|
|
></div>
|
|
<Layout
|
|
style={{
|
|
height: "100%",
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
background: "transparent",
|
|
}}
|
|
>
|
|
{/* Content */}
|
|
<Content
|
|
style={{
|
|
position: "relative",
|
|
flex: 1,
|
|
overflow: "hidden",
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
}}
|
|
>
|
|
<AnimatePresence mode="wait">
|
|
<motion.div
|
|
key={currentView}
|
|
variants={fadeVariants}
|
|
initial="initial"
|
|
animate="animate"
|
|
exit="exit"
|
|
style={{
|
|
width: "100%",
|
|
height: "100%",
|
|
overflow: "auto",
|
|
position: "absolute",
|
|
top: 0,
|
|
left: 0,
|
|
}}
|
|
>
|
|
{renderView()}
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
</Content>
|
|
|
|
{/* Footer */}
|
|
|
|
<motion.div
|
|
initial={{ paddingLeft: "20px" }}
|
|
animate={{
|
|
paddingLeft:
|
|
(currentView === "index" || currentView === "socials") && isMobile
|
|
? "50px"
|
|
: "20px",
|
|
}}
|
|
transition={{ duration: 0.5 }}
|
|
style={{
|
|
position: "fixed",
|
|
bottom: "0",
|
|
left: isMobile ? "0" : "50%",
|
|
transform: isMobile ? "unset" : "translateX(-50%)",
|
|
}}
|
|
>
|
|
<Footer
|
|
style={{
|
|
zIndex: 1,
|
|
textAlign: isMobile ? "left" : "center",
|
|
backgroundRepeat: "no-repeat",
|
|
backgroundSize: "cover",
|
|
background: "transparent",
|
|
color: "#FFFFFF",
|
|
padding: "20px 25px",
|
|
paddingLeft: "0px",
|
|
paddingTop: "0px",
|
|
fontSize: "16px",
|
|
}}
|
|
>
|
|
<Space>
|
|
<a
|
|
href="#"
|
|
onClick={(e) => {
|
|
e.preventDefault();
|
|
setCurrentView("index");
|
|
}}
|
|
>
|
|
© {new Date().getFullYear()}{" "}
|
|
</a>
|
|
<a
|
|
href="#"
|
|
onClick={(e) => {
|
|
e.preventDefault();
|
|
setCurrentView("socials");
|
|
}}
|
|
>
|
|
<img
|
|
src="https://cdn.tombutcher.work/icons/web/w-link.svg"
|
|
alt="Social Media Links"
|
|
height={16}
|
|
style={{ marginBottom: "2px" }}
|
|
/>
|
|
</a>
|
|
{loading ? (
|
|
<LoadingOutlined spinning />
|
|
) : (
|
|
<>
|
|
{!isAuthenticated && (
|
|
<a
|
|
href="#"
|
|
onClick={(e) => {
|
|
e.preventDefault();
|
|
keycloak.login();
|
|
}}
|
|
>
|
|
<img
|
|
src="https://cdn.tombutcher.work/icons/web/w-auth.svg"
|
|
alt="Login to tombutcher.work"
|
|
height={16}
|
|
style={{ marginBottom: "2px" }}
|
|
/>
|
|
</a>
|
|
)}
|
|
</>
|
|
)}
|
|
</Space>
|
|
</Footer>
|
|
</motion.div>
|
|
</Layout>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default App;
|