feat: about me page
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/backups
|
/backups
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
/__pycache__/*
|
__pycache__
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
Binary file not shown.
Generated
+97
-1
@@ -8,11 +8,14 @@
|
|||||||
"name": "blogs-app",
|
"name": "blogs-app",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
||||||
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
"@tailwindcss/vite": "^4.1.7",
|
"@tailwindcss/vite": "^4.1.7",
|
||||||
"fs": "^0.0.1-security",
|
"fs": "^0.0.1-security",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-hook-form": "^7.57.0",
|
"react-hook-form": "^7.57.0",
|
||||||
|
"react-icons": "^5.5.0",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router-dom": "^7.6.0"
|
"react-router-dom": "^7.6.0"
|
||||||
},
|
},
|
||||||
@@ -881,6 +884,53 @@
|
|||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@fortawesome/fontawesome-common-types": {
|
||||||
|
"version": "6.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz",
|
||||||
|
"integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/fontawesome-svg-core": {
|
||||||
|
"version": "6.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz",
|
||||||
|
"integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.7.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/free-brands-svg-icons": {
|
||||||
|
"version": "6.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.2.tgz",
|
||||||
|
"integrity": "sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==",
|
||||||
|
"license": "(CC-BY-4.0 AND MIT)",
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.7.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/react-fontawesome": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "~1 || ~6",
|
||||||
|
"react": ">=16.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanfs/core": {
|
"node_modules/@humanfs/core": {
|
||||||
"version": "0.19.1",
|
"version": "0.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||||
@@ -3076,7 +3126,6 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
@@ -3424,6 +3473,18 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"loose-envify": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
@@ -4159,6 +4220,15 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/optionator": {
|
"node_modules/optionator": {
|
||||||
"version": "0.9.4",
|
"version": "0.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||||
@@ -4331,6 +4401,17 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prop-types": {
|
||||||
|
"version": "15.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"object-assign": "^4.1.1",
|
||||||
|
"react-is": "^16.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/property-information": {
|
"node_modules/property-information": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz",
|
||||||
@@ -4409,6 +4490,21 @@
|
|||||||
"react": "^16.8.0 || ^17 || ^18 || ^19"
|
"react": "^16.8.0 || ^17 || ^18 || ^19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-icons": {
|
||||||
|
"version": "5.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
|
||||||
|
"integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-is": {
|
||||||
|
"version": "16.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/react-markdown": {
|
"node_modules/react-markdown": {
|
||||||
"version": "10.1.0",
|
"version": "10.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz",
|
||||||
|
|||||||
@@ -10,11 +10,14 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
||||||
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
"@tailwindcss/vite": "^4.1.7",
|
"@tailwindcss/vite": "^4.1.7",
|
||||||
"fs": "^0.0.1-security",
|
"fs": "^0.0.1-security",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-hook-form": "^7.57.0",
|
"react-hook-form": "^7.57.0",
|
||||||
|
"react-icons": "^5.5.0",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router-dom": "^7.6.0"
|
"react-router-dom": "^7.6.0"
|
||||||
},
|
},
|
||||||
|
|||||||
+116
-26
@@ -1,3 +1,10 @@
|
|||||||
|
import React, {
|
||||||
|
createContext,
|
||||||
|
useContext,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
} from "react";
|
||||||
import {
|
import {
|
||||||
BrowserRouter as Router,
|
BrowserRouter as Router,
|
||||||
Routes,
|
Routes,
|
||||||
@@ -5,15 +12,22 @@ import {
|
|||||||
Link,
|
Link,
|
||||||
useNavigate,
|
useNavigate,
|
||||||
} from "react-router-dom";
|
} from "react-router-dom";
|
||||||
import { useState, useContext, useEffect, createContext, useRef } from "react";
|
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { BlogViewer } from "./utils/BlogViewer";
|
import { BlogViewer } from "./utils/BlogViewer";
|
||||||
import { BlogList } from "./utils/BlogList";
|
import { BlogList } from "./utils/BlogList";
|
||||||
import { RequireAdmin } from "./utils/RouteGuard";
|
import { RequireAdmin } from "./utils/RouteGuard";
|
||||||
import { AdminPage } from "./utils/AdminPage";
|
import { AdminPage } from "./utils/AdminPage";
|
||||||
import Unauthorized from "./utils/UnauthorizedPage";
|
import Unauthorized from "./utils/UnauthorizedPage";
|
||||||
|
import {
|
||||||
|
FaGithub,
|
||||||
|
FaGitAlt,
|
||||||
|
FaLinkedin,
|
||||||
|
FaTwitter,
|
||||||
|
FaSun,
|
||||||
|
FaMoon,
|
||||||
|
} from "react-icons/fa";
|
||||||
|
|
||||||
// Use Vite environment variable for API base URL
|
// Base API URL from env
|
||||||
const API_URL = import.meta.env.VITE_API_URL || "http://localhost:8000";
|
const API_URL = import.meta.env.VITE_API_URL || "http://localhost:8000";
|
||||||
|
|
||||||
// Auth Context
|
// Auth Context
|
||||||
@@ -59,14 +73,30 @@ const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [darkMode, setDarkMode] = useState(true);
|
// Initialize theme from localStorage or default to light
|
||||||
|
const [darkMode, setDarkMode] = useState<boolean>(() => {
|
||||||
|
return localStorage.getItem("theme") === "dark";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sync dark mode state with <html> class and localStorage
|
||||||
|
useEffect(() => {
|
||||||
|
if (darkMode) {
|
||||||
|
document.documentElement.classList.add("dark");
|
||||||
|
localStorage.setItem("theme", "dark");
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove("dark");
|
||||||
|
localStorage.setItem("theme", "light");
|
||||||
|
}
|
||||||
|
}, [darkMode]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<div className={darkMode ? "dark" : ""}>
|
<div className="min-h-screen bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100 transition-colors duration-300">
|
||||||
<div className="min-h-screen bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100">
|
<AppBar
|
||||||
<AppBar toggleDarkMode={() => setDarkMode(!darkMode)} />
|
darkMode={darkMode}
|
||||||
|
toggleDarkMode={() => setDarkMode((prev) => !prev)}
|
||||||
|
/>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<LandingPage />} />
|
<Route path="/" element={<LandingPage />} />
|
||||||
@@ -89,13 +119,18 @@ function App() {
|
|||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AppBar({ toggleDarkMode }: { toggleDarkMode: () => void }) {
|
function AppBar({
|
||||||
|
darkMode,
|
||||||
|
toggleDarkMode,
|
||||||
|
}: {
|
||||||
|
darkMode: boolean;
|
||||||
|
toggleDarkMode: () => void;
|
||||||
|
}) {
|
||||||
const { isAuthenticated, logout } = useAuth();
|
const { isAuthenticated, logout } = useAuth();
|
||||||
const [menuOpen, setMenuOpen] = useState(false);
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
const menuRef = useRef<HTMLDivElement>(null);
|
const menuRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -111,9 +146,7 @@ function AppBar({ toggleDarkMode }: { toggleDarkMode: () => void }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
document.addEventListener("mousedown", handleClickOutside);
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
return () => {
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||||
document.removeEventListener("mousedown", handleClickOutside);
|
|
||||||
};
|
|
||||||
}, [menuOpen]);
|
}, [menuOpen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -159,7 +192,7 @@ function AppBar({ toggleDarkMode }: { toggleDarkMode: () => void }) {
|
|||||||
<div className="relative" ref={menuRef}>
|
<div className="relative" ref={menuRef}>
|
||||||
<button
|
<button
|
||||||
onClick={() => setMenuOpen(!menuOpen)}
|
onClick={() => setMenuOpen(!menuOpen)}
|
||||||
className="w-8 h-8 rounded-full bg-gray-300 dark:bg-gray-600 flex items-center justify-center"
|
className="w-8 h-8 rounded-full bg-gray-200 dark:bg-gray-700 flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<span className="text-gray-700 dark:text-gray-200">U</span>
|
<span className="text-gray-700 dark:text-gray-200">U</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -183,15 +216,16 @@ function AppBar({ toggleDarkMode }: { toggleDarkMode: () => void }) {
|
|||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={toggleDarkMode}
|
onClick={toggleDarkMode}
|
||||||
className="text-sm bg-gray-200 dark:bg-gray-700 px-2 py-1 rounded"
|
className="text-xl p-1 bg-gray-200 dark:bg-gray-700 rounded-full"
|
||||||
>
|
>
|
||||||
Toggle Dark Mode
|
{darkMode ? <FaMoon /> : <FaSun />}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pages and forms
|
||||||
function LandingPage() {
|
function LandingPage() {
|
||||||
return (
|
return (
|
||||||
<div className="text-center py-10">
|
<div className="text-center py-10">
|
||||||
@@ -203,20 +237,67 @@ function LandingPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profile placeholder
|
|
||||||
function Profile() {
|
|
||||||
return (
|
|
||||||
<div className="text-center py-10">
|
|
||||||
<h2 className="text-2xl font-bold mb-4">Profile</h2>
|
|
||||||
<p>Profile page coming soon.</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
function About() {
|
function About() {
|
||||||
return (
|
return (
|
||||||
<div className="text-center py-10">
|
<div className="py-10">
|
||||||
<h2 className="text-2xl font-bold mb-4">About Me</h2>
|
<div className="flex justify-center items-end space-x-4">
|
||||||
<p>About page content coming soon.</p>
|
<img
|
||||||
|
src="/images/photo1.jpg"
|
||||||
|
alt="Photo 1"
|
||||||
|
className="w-24 h-24 rounded-full"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src="/images/photo2.jpg"
|
||||||
|
alt="Photo 2"
|
||||||
|
className="w-24 h-24 rounded-full transform translate-y-4"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src="/images/photo3.jpg"
|
||||||
|
alt="Photo 3"
|
||||||
|
className="w-24 h-24 rounded-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-center mt-8 px-4">
|
||||||
|
<h2 className="text-3xl font-bold mb-4">About Me</h2>
|
||||||
|
<p className="text-lg text-gray-700 dark:text-gray-300 max-w-2xl mx-auto">
|
||||||
|
I am a software engineer at Whisker who designs and implements
|
||||||
|
whatever is highest priority. I work with every team in the
|
||||||
|
engineering organization to coordinate mission-critical projects
|
||||||
|
across backend, mobile, and firmware. I’m comfortable in many tech
|
||||||
|
stacks and learn new ones quickly—never afraid to jump in the deep end
|
||||||
|
and adapt on the fly.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="mt-8 flex flex-col items-center space-y-2">
|
||||||
|
<a
|
||||||
|
href="https://github.com/amuszyn"
|
||||||
|
className="flex items-center space-x-2 text-blue-600 hover:underline"
|
||||||
|
>
|
||||||
|
<FaGithub />
|
||||||
|
<span>github.com/amuszyn</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://gitea.muszyn.dev/"
|
||||||
|
className="flex items-center space-x-2 text-blue-600 hover:underline"
|
||||||
|
>
|
||||||
|
<FaGitAlt />
|
||||||
|
<span>gitea.muszyn.dev/</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://www.linkedin.com/in/almuszynski/"
|
||||||
|
className="flex items-center space-x-2 text-blue-600 hover:underline"
|
||||||
|
>
|
||||||
|
<FaLinkedin />
|
||||||
|
<span>linkedin.com/in/almuszynski</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://x.com/Muszynlol"
|
||||||
|
className="flex items-center space-x-2 text-blue-600 hover:underline"
|
||||||
|
>
|
||||||
|
<FaTwitter />
|
||||||
|
<span>x.com/Muszynlol</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -230,6 +311,15 @@ function Contact() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Profile() {
|
||||||
|
return (
|
||||||
|
<div className="text-center py-10">
|
||||||
|
<h2 className="text-2xl font-bold mb-4">Profile</h2>
|
||||||
|
<p>Profile page coming soon.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Registration form with API integration
|
// Registration form with API integration
|
||||||
interface RegisterForm {
|
interface RegisterForm {
|
||||||
username: string;
|
username: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user