Compare commits

...

10 Commits

Author SHA1 Message Date
e6c1b201a6 Fixed styles 2025-04-06 14:03:38 +01:00
29b0ab533c Fixed css imports 2025-04-06 13:51:18 +01:00
88f92bc0d6 Fixed linting issues 2025-04-01 22:57:28 +01:00
22c1fed14b Changed auth icon 2025-03-29 17:59:52 +00:00
4233b17908 Added SSO Support 2025-03-29 17:50:22 +00:00
56c598415d Fixed tag issue. 2025-03-27 23:09:16 +00:00
02b04da10d Added Google Analytics 2025-03-27 22:56:48 +00:00
a55c0575fe Minor improvements 2025-03-26 00:29:47 +00:00
f6f716d346 Fixed minor position issues 2025-03-26 00:19:46 +00:00
8a01012122 Clean up + fix vite. 2025-03-26 00:01:47 +00:00
26 changed files with 369 additions and 124 deletions

View File

@ -16,13 +16,14 @@
rel="apple-touch-icon" rel="apple-touch-icon"
href="https://cdn.tombutcher.work/favicon/favicon192.png" href="https://cdn.tombutcher.work/favicon/favicon192.png"
/> />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="stylesheet" href="/global.css" />
<link rel="stylesheet" href="%PUBLIC_URL%/fonts.css?e=e.css" /> <link rel="stylesheet" href="/fonts.css" />
<link rel="stylesheet" href="%PUBLIC_URL%/global.css?t=test" /> <link rel="manifest" href="/manifest.json" />
<title>TOM BUTCHER</title> <title>TOM BUTCHER</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body> </body>
</html> </html>

9
main.jsx Normal file
View File

@ -0,0 +1,9 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.jsx";
createRoot(document.getElementById("root")).render(
<StrictMode>
<App />
</StrictMode>,
);

14
package-lock.json generated
View File

@ -16,8 +16,10 @@
"@tsparticles/slim": "^3.8.1", "@tsparticles/slim": "^3.8.1",
"antd": "^5.24.2", "antd": "^5.24.2",
"framer-motion": "^12.4.7", "framer-motion": "^12.4.7",
"keycloak-js": "^26.1.4",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-ga4": "^2.1.0",
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
"react-particles": "^2.12.2", "react-particles": "^2.12.2",
"react-responsive": "^10.0.0", "react-responsive": "^10.0.0",
@ -15158,6 +15160,12 @@
"node": ">=4.0" "node": ">=4.0"
} }
}, },
"node_modules/keycloak-js": {
"version": "26.1.4",
"resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.1.4.tgz",
"integrity": "sha512-4h2RicCzIAtsjKIG8DIO+8NKlpWX2fiNkbS0jlbtjZFbIGGjbQBzjS/5NkyWlzxamXVow9prHTIgIiwfo3GAmQ==",
"license": "Apache-2.0"
},
"node_modules/keyv": { "node_modules/keyv": {
"version": "4.5.4", "version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@ -18874,6 +18882,12 @@
"integrity": "sha512-SN/U6Ytxf1QGkw/9ve5Y+NxBbZM6Ht95tuXNMKs8EJyFa/Vy/+Co3stop3KBHARfn/giv+Lj1uUnTfOJ3moFEQ==", "integrity": "sha512-SN/U6Ytxf1QGkw/9ve5Y+NxBbZM6Ht95tuXNMKs8EJyFa/Vy/+Co3stop3KBHARfn/giv+Lj1uUnTfOJ3moFEQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/react-ga4": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/react-ga4/-/react-ga4-2.1.0.tgz",
"integrity": "sha512-ZKS7PGNFqqMd3PJ6+C2Jtz/o1iU9ggiy8Y8nUeksgVuvNISbmrQtJiZNvC/TjDsqD0QlU5Wkgs7i+w9+OjHhhQ==",
"license": "MIT"
},
"node_modules/react-icons": { "node_modules/react-icons": {
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",

View File

@ -13,8 +13,10 @@
"@tsparticles/slim": "^3.8.1", "@tsparticles/slim": "^3.8.1",
"antd": "^5.24.2", "antd": "^5.24.2",
"framer-motion": "^12.4.7", "framer-motion": "^12.4.7",
"keycloak-js": "^26.1.4",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-ga4": "^2.1.0",
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
"react-particles": "^2.12.2", "react-particles": "^2.12.2",
"react-responsive": "^10.0.0", "react-responsive": "^10.0.0",

View File

@ -509,3 +509,16 @@ h1 {
flex: 1 1 0px; flex: 1 1 0px;
margin-left: 15px; margin-left: 15px;
} }
.tbauthbutton {
background: rgba(255, 255, 255, 0.1) !important;
color: white !important;
border: none;
border-radius: 20px;
}
.tbauthbutton:hover {
box-shadow:
6px 6px 12px #c5c5c52b,
-6px -6px 12px #ffffff30;
}

View File

@ -1,14 +1,14 @@
{ {
"short_name": "TomButcher", "short_name": "Tom Butcher",
"name": "TOM BUTCHER", "name": "TOM BUTCHER",
"icons": [ "icons": [
{ {
"src": "favicon192.png", "src": "https://cdn.tombutcher.work/favicon/favicon192.png",
"type": "image/png", "type": "image/png",
"sizes": "192x192" "sizes": "192x192"
}, },
{ {
"src": "favicon512.png", "src": "https://cdn.tombutcher.work/favicon/favicon512.png",
"type": "image/png", "type": "image/png",
"sizes": "512x512" "sizes": "512x512"
} }

View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Silent Check SSO</title>
</head>
<body>
<script>
parent.postMessage(location.href, location.origin);
</script>
</body>
</html>

View File

@ -1,9 +1,10 @@
import React, { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { Layout, Space } from "antd"; import { Layout, Space } from "antd";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion } from "framer-motion";
import ParticlesBackground from "./components/ParticlesBackground"; import ParticlesBackground from "./components/ParticlesBackground";
import { useMediaQuery } from "react-responsive"; import { useMediaQuery } from "react-responsive";
import { useKeycloak } from "./utils/KeycloakProvider";
import MainView from "./views/MainView"; import MainView from "./views/MainView";
import NotFoundView from "./views/NotFoundView"; import NotFoundView from "./views/NotFoundView";
import CVView from "./views/CVView"; import CVView from "./views/CVView";
@ -13,7 +14,7 @@ import ExperienceView from "./views/ExperienceView";
import BlogsView from "./views/BlogsView"; import BlogsView from "./views/BlogsView";
import BlogView from "./views/BlogView"; import BlogView from "./views/BlogView";
import CacheReloadView from "./utils/CacheReloadView"; import CacheReloadView from "./utils/CacheReloadView";
import { LinkOutlined } from "@ant-design/icons"; import { LoadingOutlined } from "@ant-design/icons";
const { Content } = Layout; const { Content } = Layout;
const { Footer } = Layout; const { Footer } = Layout;
@ -24,6 +25,8 @@ const App = () => {
const isMobile = useMediaQuery({ maxWidth: 600 }); const isMobile = useMediaQuery({ maxWidth: 600 });
const { isAuthenticated, loading, keycloak } = useKeycloak();
// Get the query parameter from the URL // Get the query parameter from the URL
const getQueryParam = (param) => { const getQueryParam = (param) => {
const searchParams = new URLSearchParams(location.search); // Use location.search directly const searchParams = new URLSearchParams(location.search); // Use location.search directly
@ -173,7 +176,10 @@ const App = () => {
<motion.div <motion.div
initial={{ paddingLeft: "20px" }} initial={{ paddingLeft: "20px" }}
animate={{ animate={{
paddingLeft: currentView === "index" && isMobile ? "50px" : "20px", paddingLeft:
(currentView === "index" || currentView === "socials") && isMobile
? "50px"
: "20px",
}} }}
transition={{ duration: 0.5 }} transition={{ duration: 0.5 }}
style={{ style={{
@ -214,8 +220,35 @@ const App = () => {
setCurrentView("socials"); setCurrentView("socials");
}} }}
> >
<LinkOutlined /> <img
src="https://cdn.tombutcher.work/icons/web/w-link.svg"
alt="Social Media Links"
height={16}
style={{ marginBottom: "2px" }}
/>
</a> </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> </Space>
</Footer> </Footer>
</motion.div> </motion.div>

View File

@ -1,3 +1,4 @@
import PropTypes from "prop-types";
import { useState } from "react"; import { useState } from "react";
import { Modal } from "antd"; import { Modal } from "antd";
import Turnstile from "react-turnstile"; import Turnstile from "react-turnstile";
@ -25,4 +26,10 @@ const TurnstileModal = ({ open, onClose, onSuccess }) => {
); );
}; };
TurnstileModal.propTypes = {
open: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
onSuccess: PropTypes.func.isRequired,
};
export default TurnstileModal; export default TurnstileModal;

View File

@ -1,15 +0,0 @@
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "antd/dist/reset.css"; // Import Ant Design styles
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
,
</React.StrictMode>,
);

19
src/main.jsx Normal file
View File

@ -0,0 +1,19 @@
import ReactGA from "react-ga4";
import { BrowserRouter } from "react-router-dom";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { KeycloakProvider } from "./utils/KeycloakProvider";
import App from "./App.jsx";
import "antd/dist/reset.css"; // Import Ant Design styles
ReactGA.initialize("G-MN5S04W1HB");
createRoot(document.getElementById("root")).render(
<KeycloakProvider>
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>
</KeycloakProvider>,
);

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useMediaQuery } from "react-responsive"; import { useMediaQuery } from "react-responsive";
import { Card, Flex, message } from "antd"; import { Card, Flex, message } from "antd";
import { LoadingOutlined } from "@ant-design/icons"; import { LoadingOutlined } from "@ant-design/icons";
@ -14,7 +14,7 @@ const CacheReloadView = () => {
const reloadCache = async () => { const reloadCache = async () => {
try { try {
const response = await fetch( const response = await fetch(
"http://192.168.68.53:8787/api/utils/cache", "https://web.tombutcher.work/api/utils/cache",
{ method: "POST" }, { method: "POST" },
); );
if (!response.ok) { if (!response.ok) {

View File

@ -0,0 +1,49 @@
import React, { createContext, useContext, useEffect, useState } from "react";
import Keycloak from "keycloak-js";
// Initialize Keycloak
const keycloak = new Keycloak({
url: "https://auth.tombutcher.work", // Your Keycloak server
realm: "master", // Your Keycloak realm
clientId: "web-client", // Your Keycloak client ID
});
const KeycloakContext = createContext(null);
export const KeycloakProvider = ({ children }) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
keycloak
.init({
onLoad: "check-sso",
silentCheckSsoRedirectUri:
window.location.origin + "/silent-check-sso.html",
})
.then((authenticated) => {
setIsAuthenticated(authenticated);
if (authenticated) {
setUser({
username: keycloak.tokenParsed?.preferred_username,
email: keycloak.tokenParsed?.email,
firstName: keycloak.tokenParsed?.given_name,
lastName: keycloak.tokenParsed?.family_name,
roles: keycloak.tokenParsed?.realm_access?.roles || [],
});
}
})
.finally(() => setLoading(false));
}, []);
return (
<KeycloakContext.Provider
value={{ keycloak, isAuthenticated, user, loading }}
>
{children}
</KeycloakContext.Provider>
);
};
export const useKeycloak = () => useContext(KeycloakContext);

View File

@ -1,4 +1,5 @@
import React, { useState, useEffect } from "react"; import PropTypes from "prop-types";
import { useState, useEffect } from "react";
import { useMediaQuery } from "react-responsive"; import { useMediaQuery } from "react-responsive";
import { Tag, Button, Card, Flex, message } from "antd"; import { Tag, Button, Card, Flex, message } from "antd";
import { LoadingOutlined } from "@ant-design/icons"; import { LoadingOutlined } from "@ant-design/icons";
@ -60,11 +61,13 @@ const BlogView = ({ setCurrentView, slug }) => {
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
}} }}
bodyStyle={{ styles={{
flex: 1, body: {
overflowY: "auto", flex: 1,
padding: "0", overflowY: "auto",
margin: "20px 0", padding: "0",
margin: "20px 0",
},
}} }}
actions={[ actions={[
<Button <Button
@ -140,4 +143,9 @@ const BlogView = ({ setCurrentView, slug }) => {
); );
}; };
BlogView.propTypes = {
setCurrentView: PropTypes.func.isRequired,
slug: PropTypes.string.isRequired,
};
export default BlogView; export default BlogView;

View File

@ -1,4 +1,5 @@
import React, { useState, useEffect } from "react"; import PropTypes from "prop-types";
import { useState, useEffect } from "react";
import { useMediaQuery } from "react-responsive"; import { useMediaQuery } from "react-responsive";
import { Tag, Button, Card, Flex, message } from "antd"; import { Tag, Button, Card, Flex, message } from "antd";
import { LoadingOutlined } from "@ant-design/icons"; import { LoadingOutlined } from "@ant-design/icons";
@ -81,11 +82,13 @@ const BlogsView = ({ setCurrentView }) => {
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
}} }}
bodyStyle={{ styles={{
flex: 1, body: {
overflowY: "hidden", // Changed from auto to hidden flex: 1,
display: "flex", overflowY: "auto",
flexDirection: "column", padding: "0",
margin: "20px 0",
},
}} }}
actions={[ actions={[
<Button <Button
@ -201,4 +204,8 @@ const BlogsView = ({ setCurrentView }) => {
); );
}; };
BlogsView.propTypes = {
setCurrentView: PropTypes.func.isRequired,
};
export default BlogsView; export default BlogsView;

View File

@ -1,7 +1,8 @@
import React from "react"; import PropTypes from "prop-types";
import { useMediaQuery } from "react-responsive"; import { useMediaQuery } from "react-responsive";
import { Form, Input, Button, Card, Flex } from "antd"; import { Form, Input, Button, Card, Flex } from "antd";
import { FilePdfOutlined, CloudDownloadOutlined } from "@ant-design/icons"; import { FilePdfOutlined, CloudDownloadOutlined } from "@ant-design/icons";
const CVView = ({ setCurrentView }) => { const CVView = ({ setCurrentView }) => {
const onFinish = (values) => { const onFinish = (values) => {
console.log("Form values:", values); console.log("Form values:", values);
@ -16,6 +17,16 @@ const CVView = ({ setCurrentView }) => {
style={{ style={{
width: isMobile ? "100%" : "70%", width: isMobile ? "100%" : "70%",
height: isMobile ? "100%" : "70%", height: isMobile ? "100%" : "70%",
display: "flex",
flexDirection: "column",
}}
styles={{
body: {
flex: 1,
overflowY: "auto",
padding: "0",
margin: "20px 0",
},
}} }}
actions={[ actions={[
<Button <Button
@ -110,4 +121,8 @@ const CVView = ({ setCurrentView }) => {
); );
}; };
CVView.propTypes = {
setCurrentView: PropTypes.func.isRequired,
};
export default CVView; export default CVView;

View File

@ -1,8 +1,10 @@
import React, { useState } from "react"; import PropTypes from "prop-types";
import { useState } from "react";
import { useMediaQuery } from "react-responsive"; import { useMediaQuery } from "react-responsive";
import { Form, Input, Button, Card, Flex, message } from "antd"; import { Form, Input, Button, Card, Flex, message } from "antd";
import TurnstileModal from "../components/TurnstileModal"; import TurnstileModal from "../components/TurnstileModal";
import { ArrowRightOutlined } from "@ant-design/icons"; import { ArrowRightOutlined } from "@ant-design/icons";
const ContactView = ({ setCurrentView }) => { const ContactView = ({ setCurrentView }) => {
const isMobile = useMediaQuery({ maxWidth: 600 }); const isMobile = useMediaQuery({ maxWidth: 600 });
const [turnstileOpen, setTurnstileOpen] = useState(false); const [turnstileOpen, setTurnstileOpen] = useState(false);
@ -30,7 +32,7 @@ const ContactView = ({ setCurrentView }) => {
message.error("Verification failed. Try again."); message.error("Verification failed. Try again.");
} }
} catch (error) { } catch (error) {
message.error("Error sending request."); message.error(`Error sending request: ${error.message}`);
} }
}; };
return ( return (
@ -41,6 +43,16 @@ const ContactView = ({ setCurrentView }) => {
style={{ style={{
width: isMobile ? "100%" : "70%", width: isMobile ? "100%" : "70%",
height: isMobile ? "100%" : "70%", height: isMobile ? "100%" : "70%",
display: "flex",
flexDirection: "column",
}}
styles={{
body: {
flex: 1,
overflowY: "auto",
padding: "0",
margin: "20px 0",
},
}} }}
actions={[ actions={[
<Button <Button
@ -106,4 +118,8 @@ const ContactView = ({ setCurrentView }) => {
); );
}; };
ContactView.propTypes = {
setCurrentView: PropTypes.func.isRequired,
};
export default ContactView; export default ContactView;

View File

@ -1,4 +1,4 @@
import React from "react"; import PropTypes from "prop-types";
import { useMediaQuery } from "react-responsive"; import { useMediaQuery } from "react-responsive";
import { Button, Card, Flex } from "antd"; import { Button, Card, Flex } from "antd";
const ExperienceView = ({ setCurrentView }) => { const ExperienceView = ({ setCurrentView }) => {
@ -11,6 +11,16 @@ const ExperienceView = ({ setCurrentView }) => {
style={{ style={{
width: isMobile ? "100%" : "70%", width: isMobile ? "100%" : "70%",
height: isMobile ? "100%" : "70%", height: isMobile ? "100%" : "70%",
display: "flex",
flexDirection: "column",
}}
styles={{
body: {
flex: 1,
overflowY: "auto",
padding: "0",
margin: "20px 0",
},
}} }}
actions={[ actions={[
<Button <Button
@ -65,4 +75,7 @@ const ExperienceView = ({ setCurrentView }) => {
); );
}; };
ExperienceView.propTypes = {
setCurrentView: PropTypes.func.isRequired,
};
export default ExperienceView; export default ExperienceView;

View File

@ -1,13 +1,75 @@
// views/MainView.jsx import PropTypes from "prop-types";
import React from "react"; import { Button, Flex, Dropdown, message } from "antd";
import { Button, Flex } from "antd";
import { ReactComponent as LogoHorizontal } from "./logo-horizontal.svg";
import { ReactComponent as LogoVertical } from "./logo-vertical.svg";
import { useMediaQuery } from "react-responsive"; import { useMediaQuery } from "react-responsive";
import { useKeycloak } from "../utils/KeycloakProvider";
const MainView = ({ setCurrentView }) => { const MainView = ({ setCurrentView }) => {
const isMobile = useMediaQuery({ maxWidth: 600 }); const isMobile = useMediaQuery({ maxWidth: 600 });
const { isAuthenticated, user, keycloak } = useKeycloak();
const authItems = [
{
label: user?.username,
key: "1",
icon: (
<img
src={"https://cdn.tombutcher.work/icons/auth/c-person.svg"}
width={8}
/>
),
disabled: true,
},
{
label: user?.email,
key: "2",
icon: (
<img
src={"https://cdn.tombutcher.work/icons/auth/c-at.svg"}
width={8}
/>
),
disabled: true,
},
{
label: "Manage Account",
key: "3",
icon: (
<img
src={"https://cdn.tombutcher.work/icons/auth/c-settings.svg"}
width={8}
/>
),
},
{
label: "Logout",
key: "4",
icon: (
<img
src={"https://cdn.tombutcher.work/icons/auth/c-power.svg"}
width={8}
/>
),
},
];
const onAuthItemClick = ({ key }) => {
switch (key) {
case "3":
window.location.href = keycloak.createAccountUrl();
break;
case "4":
keycloak.logout();
break;
default:
message.info(`Click on item ${key}`);
}
};
const authMenuProps = {
items: authItems,
onClick: onAuthItemClick,
};
return ( return (
<Flex <Flex
justify="center" justify="center"
@ -16,13 +78,19 @@ const MainView = ({ setCurrentView }) => {
style={{ height: "100%", padding: "24px 50px" }} style={{ height: "100%", padding: "24px 50px" }}
> >
<div style={{ textAlign: "center", maxWidth: "800px", margin: "0 0" }}> <div style={{ textAlign: "center", maxWidth: "800px", margin: "0 0" }}>
<div className={"tblogo"}> <Flex className={"tblogo"}>
{isMobile ? ( {isMobile ? (
<LogoVertical height={180} /> <img
src="https://cdn.tombutcher.work/logos/logo-vertical.svg"
height={180}
/>
) : ( ) : (
<LogoHorizontal height={60} /> <img
src="https://cdn.tombutcher.work/logos/logo-horizontal.svg"
height={60}
/>
)} )}
</div> </Flex>
{isMobile ? ( {isMobile ? (
<Flex <Flex
justify="left" justify="left"
@ -81,9 +149,31 @@ const MainView = ({ setCurrentView }) => {
</Button> </Button>
</Flex> </Flex>
)} )}
{isAuthenticated ? (
<>
<Dropdown
menu={authMenuProps}
placement={isMobile ? "topLeft" : "bottom"}
>
<Button
className="tbauthbutton"
style={{
marginTop: "15px",
float: isMobile ? "left" : "unset",
}}
>
Hello, {user?.firstName + " " + user?.lastName || "Guest"}!
</Button>
</Dropdown>
</>
) : null}
</div> </div>
</Flex> </Flex>
); );
}; };
MainView.propTypes = {
setCurrentView: PropTypes.func.isRequired,
};
export default MainView; export default MainView;

View File

@ -1,4 +1,4 @@
import React from "react"; import PropTypes from "prop-types";
import { Button, Flex } from "antd"; import { Button, Flex } from "antd";
const NotFoundView = ({ setCurrentView }) => { const NotFoundView = ({ setCurrentView }) => {
@ -14,4 +14,8 @@ const NotFoundView = ({ setCurrentView }) => {
); );
}; };
NotFoundView.propTypes = {
setCurrentView: PropTypes.func.isRequired,
};
export default NotFoundView; export default NotFoundView;

View File

@ -1,8 +1,7 @@
import React, { useState } from "react"; import PropTypes from "prop-types";
import { useState } from "react";
import { useMediaQuery } from "react-responsive"; import { useMediaQuery } from "react-responsive";
import { Flex, Spin } from "antd"; import { Flex, Spin } from "antd";
import { ReactComponent as LogoHorizontal } from "./logo-horizontal.svg";
import { ReactComponent as LogoVertical } from "./logo-vertical.svg";
import { LoadingOutlined } from "@ant-design/icons"; import { LoadingOutlined } from "@ant-design/icons";
import { useEffect } from "react"; import { useEffect } from "react";
import * as FaIcons from "react-icons/fa6"; // Import all FA6 icons dynamically import * as FaIcons from "react-icons/fa6"; // Import all FA6 icons dynamically
@ -38,13 +37,19 @@ const SocialsView = ({ referrer }) => {
style={{ height: "100%", padding: "24px 50px" }} style={{ height: "100%", padding: "24px 50px" }}
> >
<div style={{ textAlign: "center", maxWidth: "900px", margin: "0 0" }}> <div style={{ textAlign: "center", maxWidth: "900px", margin: "0 0" }}>
<div className={"tblogo"}> <Flex className={"tblogo"}>
{isMobile ? ( {isMobile ? (
<LogoVertical height={180} /> <img
src="https://cdn.tombutcher.work/logos/logo-vertical.svg"
height={180}
/>
) : ( ) : (
<LogoHorizontal height={60} /> <img
src="https://cdn.tombutcher.work/logos/logo-horizontal.svg"
height={60}
/>
)} )}
</div> </Flex>
<Flex <Flex
gap="20px" gap="20px"
align={"center"} align={"center"}
@ -95,4 +100,8 @@ const SocialsView = ({ referrer }) => {
); );
}; };
SocialsView.propTypes = {
referrer: PropTypes.string, // Adjust type as needed
};
export default SocialsView; export default SocialsView;

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 894 87" version="1.1" xmlns="http://www.w3.org/2000/svg" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-91.7237,-316.8)">
<g transform="matrix(1,0,0,1,-186.893,-49.2326)">
<path d="M282.793,367.473L335.641,367.473C336.697,367.473 337.657,367.881 338.521,368.697C339.385,369.513 339.817,370.449 339.817,371.505L339.817,381.153C339.817,382.209 339.385,383.145 338.521,383.961C337.657,384.777 336.697,385.185 335.641,385.185L318.937,385.185L318.937,446.673C318.937,447.729 318.529,448.689 317.713,449.553C316.897,450.417 315.961,450.849 314.905,450.849L303.529,450.849C302.473,450.849 301.537,450.417 300.721,449.553C299.905,448.689 299.497,447.729 299.497,446.673L299.497,385.185L282.793,385.185C281.737,385.185 280.777,384.777 279.913,383.961C279.049,383.145 278.617,382.209 278.617,381.153L278.617,371.505C278.617,370.449 279.049,369.513 279.913,368.697C280.777,367.881 281.737,367.473 282.793,367.473Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M354.937,378.273C361.657,370.113 371.017,366.033 383.017,366.033C395.017,366.033 404.353,370.113 411.025,378.273C417.697,386.433 421.033,396.753 421.033,409.233C421.033,421.617 417.673,431.913 410.953,440.121C404.233,448.329 394.921,452.433 383.017,452.433C371.113,452.433 361.801,448.329 355.081,440.121C348.361,431.913 345.001,421.617 345.001,409.233C345.001,396.753 348.313,386.433 354.937,378.273ZM365.017,409.233C365.017,426.225 371.017,434.721 383.017,434.721C395.017,434.721 401.017,426.225 401.017,409.233C401.017,392.241 395.017,383.745 383.017,383.745C371.017,383.745 365.017,392.241 365.017,409.233Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M477.049,439.761L475.321,439.761C474.265,439.761 473.545,439.377 473.161,438.609L455.593,406.497L455.593,446.673C455.593,447.729 455.185,448.689 454.369,449.553C453.553,450.417 452.617,450.849 451.561,450.849L440.329,450.849C439.273,450.849 438.337,450.417 437.521,449.553C436.705,448.689 436.297,447.729 436.297,446.673L436.297,371.649C436.297,370.593 436.705,369.633 437.521,368.769C438.337,367.905 439.273,367.473 440.329,367.473L453.289,367.473C454.825,367.473 455.881,368.049 456.457,369.201L476.041,404.337L495.625,369.201C496.201,368.049 497.257,367.473 498.793,367.473L511.753,367.473C512.809,367.473 513.745,367.905 514.561,368.769C515.377,369.633 515.785,370.593 515.785,371.649L515.785,446.673C515.785,447.729 515.377,448.689 514.561,449.553C513.745,450.417 512.809,450.849 511.753,450.849L500.521,450.849C499.465,450.849 498.529,450.417 497.713,449.553C496.897,448.689 496.489,447.729 496.489,446.673L496.489,406.497L478.921,438.609C478.537,439.377 477.913,439.761 477.049,439.761Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M574.969,433.425L583.177,433.425C589.801,433.425 593.113,430.641 593.113,425.073C593.113,419.697 589.801,417.009 583.177,417.009L574.969,417.009L574.969,433.425ZM583.033,384.897L574.969,384.897L574.969,399.297L583.033,399.297C583.609,399.297 584.305,399.249 585.121,399.153C585.937,399.057 587.041,398.409 588.433,397.209C589.825,396.009 590.521,394.305 590.521,392.097C590.521,389.889 589.897,388.185 588.649,386.985C587.401,385.785 586.153,385.137 584.905,385.041L583.033,384.897ZM559.705,367.473L583.177,367.473C583.945,367.473 584.905,367.521 586.057,367.617C587.209,367.713 589.321,368.121 592.393,368.841C595.465,369.561 598.177,370.593 600.529,371.937C602.881,373.281 605.017,375.369 606.937,378.201C608.857,381.033 609.817,384.417 609.817,388.353C609.817,391.329 609.409,393.993 608.593,396.345C607.777,398.697 606.817,400.521 605.713,401.817C604.609,403.113 603.433,404.217 602.185,405.129C600.937,406.041 599.929,406.641 599.161,406.929C598.393,407.217 597.913,407.361 597.721,407.361C598.969,407.745 600.145,408.225 601.249,408.801C602.353,409.377 604.009,410.385 606.217,411.825C608.425,413.265 610.177,415.257 611.473,417.801C612.769,420.345 613.417,423.249 613.417,426.513C613.417,442.737 602.185,450.849 579.721,450.849L559.705,450.849C558.649,450.849 557.713,450.417 556.897,449.553C556.081,448.689 555.673,447.729 555.673,446.673L555.673,371.649C555.673,370.593 556.081,369.633 556.897,368.769C557.713,367.905 558.649,367.473 559.705,367.473Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M657.337,452.433C656.953,452.433 656.377,452.409 655.609,452.361C654.841,452.313 653.377,452.097 651.217,451.713C649.057,451.329 647.017,450.753 645.097,449.985C643.177,449.217 641.017,447.993 638.617,446.313C636.217,444.633 634.153,442.665 632.425,440.409C630.697,438.153 629.257,435.153 628.105,431.409C626.953,427.665 626.377,423.489 626.377,418.881L626.377,371.649C626.377,370.593 626.785,369.633 627.601,368.769C628.417,367.905 629.353,367.473 630.409,367.473L641.785,367.473C642.841,367.473 643.777,367.905 644.593,368.769C645.409,369.633 645.817,370.593 645.817,371.649L645.817,421.905C645.817,422.289 645.841,422.769 645.889,423.345C645.937,423.921 646.177,424.929 646.609,426.369C647.041,427.809 647.617,429.105 648.337,430.257C649.057,431.409 650.209,432.441 651.793,433.353C653.377,434.265 655.225,434.721 657.337,434.721C660.697,434.721 663.337,433.665 665.257,431.553C667.177,429.441 668.233,427.329 668.425,425.217L668.857,421.905L668.857,371.649C668.857,370.593 669.265,369.633 670.081,368.769C670.897,367.905 671.833,367.473 672.889,367.473L684.265,367.473C685.321,367.473 686.257,367.905 687.073,368.769C687.889,369.633 688.297,370.593 688.297,371.649L688.297,418.881C688.297,423.489 687.721,427.665 686.569,431.409C685.417,435.153 683.929,438.153 682.105,440.409C680.281,442.665 678.265,444.633 676.057,446.313C673.849,447.993 671.665,449.217 669.505,449.985C667.345,450.753 665.353,451.329 663.529,451.713C661.705,452.097 660.217,452.289 659.065,452.289L657.337,452.433Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M704.713,367.473L757.561,367.473C758.617,367.473 759.577,367.881 760.441,368.697C761.305,369.513 761.737,370.449 761.737,371.505L761.737,381.153C761.737,382.209 761.305,383.145 760.441,383.961C759.577,384.777 758.617,385.185 757.561,385.185L740.857,385.185L740.857,446.673C740.857,447.729 740.449,448.689 739.633,449.553C738.817,450.417 737.881,450.849 736.825,450.849L725.449,450.849C724.393,450.849 723.457,450.417 722.641,449.553C721.825,448.689 721.417,447.729 721.417,446.673L721.417,385.185L704.713,385.185C703.657,385.185 702.697,384.777 701.833,383.961C700.969,383.145 700.537,382.209 700.537,381.153L700.537,371.505C700.537,370.449 700.969,369.513 701.833,368.697C702.697,367.881 703.657,367.473 704.713,367.473Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M805.081,452.433C793.081,452.433 783.601,448.329 776.641,440.121C769.681,431.913 766.201,421.617 766.201,409.233C766.201,396.849 769.681,386.553 776.641,378.345C783.601,370.137 793.081,366.033 805.081,366.033C825.721,366.033 838.249,375.633 842.665,394.833C842.473,395.889 841.969,396.801 841.153,397.569C840.337,398.337 839.401,398.721 838.345,398.721L825.961,398.721C824.521,398.721 823.417,398.001 822.649,396.561C820.345,388.017 814.489,383.745 805.081,383.745C798.649,383.745 793.897,386.097 790.825,390.801C787.753,395.505 786.217,401.649 786.217,409.233C786.217,416.721 787.753,422.841 790.825,427.593C793.897,432.345 798.649,434.721 805.081,434.721C814.489,434.721 820.345,430.449 822.649,421.905C823.417,420.465 824.521,419.745 825.961,419.745L838.345,419.745C839.401,419.745 840.337,420.129 841.153,420.897C841.969,421.665 842.473,422.577 842.665,423.633C838.249,442.833 825.721,452.433 805.081,452.433Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M896.521,446.673L896.521,421.905L874.633,421.905L874.633,446.673C874.633,447.729 874.225,448.689 873.409,449.553C872.593,450.417 871.657,450.849 870.601,450.849L859.369,450.849C858.313,450.849 857.377,450.417 856.561,449.553C855.745,448.689 855.337,447.729 855.337,446.673L855.337,371.649C855.337,370.593 855.745,369.633 856.561,368.769C857.377,367.905 858.313,367.473 859.369,367.473L870.601,367.473C871.657,367.473 872.593,367.905 873.409,368.769C874.225,369.633 874.633,370.593 874.633,371.649L874.633,404.337L896.521,404.337L896.521,371.649C896.521,370.593 896.929,369.633 897.745,368.769C898.561,367.905 899.497,367.473 900.553,367.473L911.785,367.473C912.841,367.473 913.777,367.905 914.593,368.769C915.409,369.633 915.817,370.593 915.817,371.649L915.817,446.673C915.817,447.729 915.409,448.689 914.593,449.553C913.777,450.417 912.841,450.849 911.785,450.849L900.553,450.849C899.497,450.849 898.561,450.417 897.745,449.553C896.929,448.689 896.521,447.729 896.521,446.673Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M932.521,446.817L932.521,371.505C932.521,370.449 932.953,369.513 933.817,368.697C934.681,367.881 935.641,367.473 936.697,367.473L977.881,367.473C978.937,367.473 979.897,367.881 980.761,368.697C981.625,369.513 982.057,370.449 982.057,371.505L982.057,381.153C982.057,382.209 981.625,383.145 980.761,383.961C979.897,384.777 978.937,385.185 977.881,385.185L951.817,385.185L951.817,401.025L974.857,401.025C975.913,401.025 976.873,401.433 977.737,402.249C978.601,403.065 979.033,404.001 979.033,405.057L979.033,414.705C979.033,415.761 978.601,416.697 977.737,417.513C976.873,418.329 975.913,418.737 974.857,418.737L951.817,418.737L951.817,433.137L977.881,433.137C978.937,433.137 979.897,433.545 980.761,434.361C981.625,435.177 982.057,436.113 982.057,437.169L982.057,446.817C982.057,447.873 981.625,448.809 980.761,449.625C979.897,450.441 978.937,450.849 977.881,450.849L936.697,450.849C935.641,450.849 934.681,450.441 933.817,449.625C932.953,448.809 932.521,447.873 932.521,446.817Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M1022.23,409.953C1025.79,409.953 1028.66,408.945 1030.87,406.929C1033.08,404.913 1034.18,401.745 1034.18,397.425C1034.18,393.105 1033.08,389.913 1030.87,387.849C1028.66,385.785 1025.79,384.753 1022.23,384.753L1015.75,384.753L1015.75,409.953L1022.23,409.953ZM1037.64,449.409L1025.98,426.945L1022.67,427.233L1015.75,427.233L1015.75,446.673C1015.75,447.729 1015.35,448.689 1014.53,449.553C1013.71,450.417 1012.78,450.849 1011.72,450.849L1000.49,450.849C999.433,450.849 998.497,450.417 997.681,449.553C996.865,448.689 996.457,447.729 996.457,446.673L996.457,371.505C996.457,370.449 996.889,369.513 997.753,368.697C998.617,367.881 999.577,367.473 1000.63,367.473L1022.67,367.473C1023.14,367.473 1023.77,367.497 1024.54,367.545C1025.31,367.593 1026.82,367.809 1029.07,368.193C1031.33,368.577 1033.46,369.105 1035.48,369.777C1037.5,370.449 1039.75,371.553 1042.25,373.089C1044.75,374.625 1046.88,376.401 1048.66,378.417C1050.43,380.433 1051.94,383.097 1053.19,386.409C1054.44,389.721 1055.07,393.393 1055.07,397.425C1055.07,407.505 1051.51,415.137 1044.41,420.321L1058.09,446.817C1058.09,447.969 1057.73,448.929 1057.01,449.697C1056.29,450.465 1055.35,450.849 1054.2,450.849L1040.81,450.849C1039.46,450.849 1038.41,450.369 1037.64,449.409Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,4,0)">
<path d="M947.978,337.608L901.718,337.608C900.662,337.608 899.702,337.2 898.838,336.384C897.974,335.568 897.542,334.632 897.542,333.576L897.542,322.344C897.542,321.288 897.974,320.352 898.838,319.536C899.702,318.72 900.662,318.312 901.718,318.312L967.817,318.312C971.199,318.312 974.203,319.676 976.827,322.403C979.554,325.027 980.918,328.031 980.918,331.413L980.918,397.512C980.918,398.568 980.51,399.528 979.694,400.392C978.878,401.256 977.942,401.688 976.886,401.688L965.654,401.688C964.598,401.688 963.662,401.256 962.846,400.392C962.03,399.528 961.622,398.568 961.622,397.512L961.622,351.252L912.36,400.515C911.613,401.262 910.646,401.652 909.458,401.686C908.27,401.72 907.302,401.363 906.556,400.617L898.614,392.674C897.867,391.928 897.51,390.96 897.544,389.772C897.578,388.585 897.969,387.617 898.715,386.87L947.978,337.608Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

View File

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 503 301" preserveAspectRatio="xMinYMin meet" version="1.1" xmlns="http://www.w3.org/2000/svg" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-91.7237,-144)">
<g transform="matrix(1,0,0,1,-186.893,-46.2326)">
<g transform="matrix(1,0,0,1,0,-68.8)">
<path d="M282.793,367.473L335.641,367.473C336.697,367.473 337.657,367.881 338.521,368.697C339.385,369.513 339.817,370.449 339.817,371.505L339.817,381.153C339.817,382.209 339.385,383.145 338.521,383.961C337.657,384.777 336.697,385.185 335.641,385.185L318.937,385.185L318.937,446.673C318.937,447.729 318.529,448.689 317.713,449.553C316.897,450.417 315.961,450.849 314.905,450.849L303.529,450.849C302.473,450.849 301.537,450.417 300.721,449.553C299.905,448.689 299.497,447.729 299.497,446.673L299.497,385.185L282.793,385.185C281.737,385.185 280.777,384.777 279.913,383.961C279.049,383.145 278.617,382.209 278.617,381.153L278.617,371.505C278.617,370.449 279.049,369.513 279.913,368.697C280.777,367.881 281.737,367.473 282.793,367.473Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-68.8)">
<path d="M354.937,378.273C361.657,370.113 371.017,366.033 383.017,366.033C395.017,366.033 404.353,370.113 411.025,378.273C417.697,386.433 421.033,396.753 421.033,409.233C421.033,421.617 417.673,431.913 410.953,440.121C404.233,448.329 394.921,452.433 383.017,452.433C371.113,452.433 361.801,448.329 355.081,440.121C348.361,431.913 345.001,421.617 345.001,409.233C345.001,396.753 348.313,386.433 354.937,378.273ZM365.017,409.233C365.017,426.225 371.017,434.721 383.017,434.721C395.017,434.721 401.017,426.225 401.017,409.233C401.017,392.241 395.017,383.745 383.017,383.745C371.017,383.745 365.017,392.241 365.017,409.233Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-68.8)">
<path d="M477.049,439.761L475.321,439.761C474.265,439.761 473.545,439.377 473.161,438.609L455.593,406.497L455.593,446.673C455.593,447.729 455.185,448.689 454.369,449.553C453.553,450.417 452.617,450.849 451.561,450.849L440.329,450.849C439.273,450.849 438.337,450.417 437.521,449.553C436.705,448.689 436.297,447.729 436.297,446.673L436.297,371.649C436.297,370.593 436.705,369.633 437.521,368.769C438.337,367.905 439.273,367.473 440.329,367.473L453.289,367.473C454.825,367.473 455.881,368.049 456.457,369.201L476.041,404.337L495.625,369.201C496.201,368.049 497.257,367.473 498.793,367.473L511.753,367.473C512.809,367.473 513.745,367.905 514.561,368.769C515.377,369.633 515.785,370.593 515.785,371.649L515.785,446.673C515.785,447.729 515.377,448.689 514.561,449.553C513.745,450.417 512.809,450.849 511.753,450.849L500.521,450.849C499.465,450.849 498.529,450.417 497.713,449.553C496.897,448.689 496.489,447.729 496.489,446.673L496.489,406.497L478.921,438.609C478.537,439.377 477.913,439.761 477.049,439.761Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,-277.056,38)">
<path d="M574.969,433.425L583.177,433.425C589.801,433.425 593.113,430.641 593.113,425.073C593.113,419.697 589.801,417.009 583.177,417.009L574.969,417.009L574.969,433.425ZM583.033,384.897L574.969,384.897L574.969,399.297L583.033,399.297C583.609,399.297 584.305,399.249 585.121,399.153C585.937,399.057 587.041,398.409 588.433,397.209C589.825,396.009 590.521,394.305 590.521,392.097C590.521,389.889 589.897,388.185 588.649,386.985C587.401,385.785 586.153,385.137 584.905,385.041L583.033,384.897ZM559.705,367.473L583.177,367.473C583.945,367.473 584.905,367.521 586.057,367.617C587.209,367.713 589.321,368.121 592.393,368.841C595.465,369.561 598.177,370.593 600.529,371.937C602.881,373.281 605.017,375.369 606.937,378.201C608.857,381.033 609.817,384.417 609.817,388.353C609.817,391.329 609.409,393.993 608.593,396.345C607.777,398.697 606.817,400.521 605.713,401.817C604.609,403.113 603.433,404.217 602.185,405.129C600.937,406.041 599.929,406.641 599.161,406.929C598.393,407.217 597.913,407.361 597.721,407.361C598.969,407.745 600.145,408.225 601.249,408.801C602.353,409.377 604.009,410.385 606.217,411.825C608.425,413.265 610.177,415.257 611.473,417.801C612.769,420.345 613.417,423.249 613.417,426.513C613.417,442.737 602.185,450.849 579.721,450.849L559.705,450.849C558.649,450.849 557.713,450.417 556.897,449.553C556.081,448.689 555.673,447.729 555.673,446.673L555.673,371.649C555.673,370.593 556.081,369.633 556.897,368.769C557.713,367.905 558.649,367.473 559.705,367.473Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,-277.056,38)">
<path d="M657.337,452.433C656.953,452.433 656.377,452.409 655.609,452.361C654.841,452.313 653.377,452.097 651.217,451.713C649.057,451.329 647.017,450.753 645.097,449.985C643.177,449.217 641.017,447.993 638.617,446.313C636.217,444.633 634.153,442.665 632.425,440.409C630.697,438.153 629.257,435.153 628.105,431.409C626.953,427.665 626.377,423.489 626.377,418.881L626.377,371.649C626.377,370.593 626.785,369.633 627.601,368.769C628.417,367.905 629.353,367.473 630.409,367.473L641.785,367.473C642.841,367.473 643.777,367.905 644.593,368.769C645.409,369.633 645.817,370.593 645.817,371.649L645.817,421.905C645.817,422.289 645.841,422.769 645.889,423.345C645.937,423.921 646.177,424.929 646.609,426.369C647.041,427.809 647.617,429.105 648.337,430.257C649.057,431.409 650.209,432.441 651.793,433.353C653.377,434.265 655.225,434.721 657.337,434.721C660.697,434.721 663.337,433.665 665.257,431.553C667.177,429.441 668.233,427.329 668.425,425.217L668.857,421.905L668.857,371.649C668.857,370.593 669.265,369.633 670.081,368.769C670.897,367.905 671.833,367.473 672.889,367.473L684.265,367.473C685.321,367.473 686.257,367.905 687.073,368.769C687.889,369.633 688.297,370.593 688.297,371.649L688.297,418.881C688.297,423.489 687.721,427.665 686.569,431.409C685.417,435.153 683.929,438.153 682.105,440.409C680.281,442.665 678.265,444.633 676.057,446.313C673.849,447.993 671.665,449.217 669.505,449.985C667.345,450.753 665.353,451.329 663.529,451.713C661.705,452.097 660.217,452.289 659.065,452.289L657.337,452.433Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,-277.056,38)">
<path d="M704.713,367.473L757.561,367.473C758.617,367.473 759.577,367.881 760.441,368.697C761.305,369.513 761.737,370.449 761.737,371.505L761.737,381.153C761.737,382.209 761.305,383.145 760.441,383.961C759.577,384.777 758.617,385.185 757.561,385.185L740.857,385.185L740.857,446.673C740.857,447.729 740.449,448.689 739.633,449.553C738.817,450.417 737.881,450.849 736.825,450.849L725.449,450.849C724.393,450.849 723.457,450.417 722.641,449.553C721.825,448.689 721.417,447.729 721.417,446.673L721.417,385.185L704.713,385.185C703.657,385.185 702.697,384.777 701.833,383.961C700.969,383.145 700.537,382.209 700.537,381.153L700.537,371.505C700.537,370.449 700.969,369.513 701.833,368.697C702.697,367.881 703.657,367.473 704.713,367.473Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,-277.056,38)">
<path d="M805.081,452.433C793.081,452.433 783.601,448.329 776.641,440.121C769.681,431.913 766.201,421.617 766.201,409.233C766.201,396.849 769.681,386.553 776.641,378.345C783.601,370.137 793.081,366.033 805.081,366.033C825.721,366.033 838.249,375.633 842.665,394.833C842.473,395.889 841.969,396.801 841.153,397.569C840.337,398.337 839.401,398.721 838.345,398.721L825.961,398.721C824.521,398.721 823.417,398.001 822.649,396.561C820.345,388.017 814.489,383.745 805.081,383.745C798.649,383.745 793.897,386.097 790.825,390.801C787.753,395.505 786.217,401.649 786.217,409.233C786.217,416.721 787.753,422.841 790.825,427.593C793.897,432.345 798.649,434.721 805.081,434.721C814.489,434.721 820.345,430.449 822.649,421.905C823.417,420.465 824.521,419.745 825.961,419.745L838.345,419.745C839.401,419.745 840.337,420.129 841.153,420.897C841.969,421.665 842.473,422.577 842.665,423.633C838.249,442.833 825.721,452.433 805.081,452.433Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,-277.056,38)">
<path d="M896.521,446.673L896.521,421.905L874.633,421.905L874.633,446.673C874.633,447.729 874.225,448.689 873.409,449.553C872.593,450.417 871.657,450.849 870.601,450.849L859.369,450.849C858.313,450.849 857.377,450.417 856.561,449.553C855.745,448.689 855.337,447.729 855.337,446.673L855.337,371.649C855.337,370.593 855.745,369.633 856.561,368.769C857.377,367.905 858.313,367.473 859.369,367.473L870.601,367.473C871.657,367.473 872.593,367.905 873.409,368.769C874.225,369.633 874.633,370.593 874.633,371.649L874.633,404.337L896.521,404.337L896.521,371.649C896.521,370.593 896.929,369.633 897.745,368.769C898.561,367.905 899.497,367.473 900.553,367.473L911.785,367.473C912.841,367.473 913.777,367.905 914.593,368.769C915.409,369.633 915.817,370.593 915.817,371.649L915.817,446.673C915.817,447.729 915.409,448.689 914.593,449.553C913.777,450.417 912.841,450.849 911.785,450.849L900.553,450.849C899.497,450.849 898.561,450.417 897.745,449.553C896.929,448.689 896.521,447.729 896.521,446.673Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,-277.056,38)">
<path d="M932.521,446.817L932.521,371.505C932.521,370.449 932.953,369.513 933.817,368.697C934.681,367.881 935.641,367.473 936.697,367.473L977.881,367.473C978.937,367.473 979.897,367.881 980.761,368.697C981.625,369.513 982.057,370.449 982.057,371.505L982.057,381.153C982.057,382.209 981.625,383.145 980.761,383.961C979.897,384.777 978.937,385.185 977.881,385.185L951.817,385.185L951.817,401.025L974.857,401.025C975.913,401.025 976.873,401.433 977.737,402.249C978.601,403.065 979.033,404.001 979.033,405.057L979.033,414.705C979.033,415.761 978.601,416.697 977.737,417.513C976.873,418.329 975.913,418.737 974.857,418.737L951.817,418.737L951.817,433.137L977.881,433.137C978.937,433.137 979.897,433.545 980.761,434.361C981.625,435.177 982.057,436.113 982.057,437.169L982.057,446.817C982.057,447.873 981.625,448.809 980.761,449.625C979.897,450.441 978.937,450.849 977.881,450.849L936.697,450.849C935.641,450.849 934.681,450.441 933.817,449.625C932.953,448.809 932.521,447.873 932.521,446.817Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,-277.056,38)">
<path d="M1022.23,409.953C1025.79,409.953 1028.66,408.945 1030.87,406.929C1033.08,404.913 1034.18,401.745 1034.18,397.425C1034.18,393.105 1033.08,389.913 1030.87,387.849C1028.66,385.785 1025.79,384.753 1022.23,384.753L1015.75,384.753L1015.75,409.953L1022.23,409.953ZM1037.64,449.409L1025.98,426.945L1022.67,427.233L1015.75,427.233L1015.75,446.673C1015.75,447.729 1015.35,448.689 1014.53,449.553C1013.71,450.417 1012.78,450.849 1011.72,450.849L1000.49,450.849C999.433,450.849 998.497,450.417 997.681,449.553C996.865,448.689 996.457,447.729 996.457,446.673L996.457,371.505C996.457,370.449 996.889,369.513 997.753,368.697C998.617,367.881 999.577,367.473 1000.63,367.473L1022.67,367.473C1023.14,367.473 1023.77,367.497 1024.54,367.545C1025.31,367.593 1026.82,367.809 1029.07,368.193C1031.33,368.577 1033.46,369.105 1035.48,369.777C1037.5,370.449 1039.75,371.553 1042.25,373.089C1044.75,374.625 1046.88,376.401 1048.66,378.417C1050.43,380.433 1051.94,383.097 1053.19,386.409C1054.44,389.721 1055.07,393.393 1055.07,397.425C1055.07,407.505 1051.51,415.137 1044.41,420.321L1058.09,446.817C1058.09,447.969 1057.73,448.929 1057.01,449.697C1056.29,450.465 1055.35,450.849 1054.2,450.849L1040.81,450.849C1039.46,450.849 1038.41,450.369 1037.64,449.409Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</g>
<g transform="matrix(1,0,0,1,-805.818,-174.312)">
<path d="M947.978,337.608L901.718,337.608C900.662,337.608 899.702,337.2 898.838,336.384C897.974,335.568 897.542,334.632 897.542,333.576L897.542,322.344C897.542,321.288 897.974,320.352 898.838,319.536C899.702,318.72 900.662,318.312 901.718,318.312L967.817,318.312C971.199,318.312 974.203,319.676 976.827,322.403C979.554,325.027 980.918,328.031 980.918,331.413L980.918,397.512C980.918,398.568 980.51,399.528 979.694,400.392C978.878,401.256 977.942,401.688 976.886,401.688L965.654,401.688C964.598,401.688 963.662,401.256 962.846,400.392C962.03,399.528 961.622,398.568 961.622,397.512L961.622,351.252L912.36,400.515C911.613,401.262 910.646,401.652 909.458,401.686C908.27,401.72 907.302,401.363 906.556,400.617L898.614,392.674C897.867,391.928 897.51,390.96 897.544,389.772C897.578,388.585 897.969,387.617 898.715,386.87L947.978,337.608Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -31,7 +31,7 @@
* Environment Variables * Environment Variables
* https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables * https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables
*/ */
// "vars": { "MY_VARIABLE": "production_value" }, // "vars": { "GA_MEASUREMENT_ID": "" },
/** /**
* Note: Use secrets to store sensitive data. * Note: Use secrets to store sensitive data.
* https://developers.cloudflare.com/workers/configuration/secrets/ * https://developers.cloudflare.com/workers/configuration/secrets/