diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 81af689e8..377289058 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -132,6 +132,7 @@ import LowPolyTerrain from './components/portfolio/templates/Low_Poly_Terrain/in import HighFashion from './components/portfolio/templates/High_Fashion/index.jsx'; import TypographicWheatpastePosterWall from './components/portfolio/templates/Typographic_Wheatpaste_Poster_Wall/index.jsx'; import DigitalManifestoScroll from './components/portfolio/templates/Digital_Manifesto_Scroll/index.jsx'; +import CeramicMinimal from './components/portfolio/templates/Ceramic_Minimal/index.jsx'; import TestSocialLinks from './pages/TestSocialLinks'; import ZineCollage from './components/portfolio/templates/ZineCollage'; import TransparentDesktopOverlayOS from './components/portfolio/templates/Transparent_Desktop_Overlay_OS/index.jsx'; @@ -338,7 +339,7 @@ function AppRoutes() { } /> } /> } /> - } /> + } /> {/* Core Protected Routes */} { + if (isOpen && brokenUrl) { + setTitle("Broken Link"); + + setDescription( + `Broken URL: ${brokenUrl}\n\nPlease describe what happened...` + ); + } +}, [isOpen, brokenUrl]); + + const [isSubmitting, setIsSubmitting] = useState(false); const handleSubmit = async (e) => { diff --git a/frontend/src/components/portfolio/templates/Ceramic_Minimal/index.jsx b/frontend/src/components/portfolio/templates/Ceramic_Minimal/index.jsx index a60481252..3f762dfa0 100644 --- a/frontend/src/components/portfolio/templates/Ceramic_Minimal/index.jsx +++ b/frontend/src/components/portfolio/templates/Ceramic_Minimal/index.jsx @@ -1,32 +1,252 @@ -import { usePortfolio } from "../../../../context/PortfolioContext"; -import React from 'react'; - -/** - * Ceramic Minimal Portfolio Template - * Category: Glass / Modern UI - * Description: Ceramic/pottery-inspired smooth matte surfaces. Earthy, warm undertones. Rounded shapes that look like sculpted clay objects. Organic plus minimal. - */ +import React from "react"; +import { motion } from "framer-motion"; +import data from "../../../../data/dummy_data.json"; + export default function CeramicMinimal() { const { portfolioData: data } = usePortfolio(); return ( -
-
-

+
+ + {/* HERO */} +
+ + + {data.personal.name} -

-

{data.personal.title}

-
- - Glass / Modern UI - -

Ceramic Minimal Template

-

- Ceramic/pottery-inspired smooth matte surfaces. Earthy, warm undertones. Rounded shapes that look like sculpted clay objects. Organic plus minimal. + + +

+ {data.personal.title} +

+ +

+ {data.personal.tagline} +

+ + + {/* ABOUT */} +
+

+ About Me +

+ +
+

+ {data.personal.bio}

-

Open an issue to contribute and build this template!

+ +

+ 📍 {data.personal.location} +

+
+
+ + {/* STATS */} +
+
+
+

+ {data.stats.yearsExperience}+ +

+

Years Experience

+
+ +
+

+ {data.stats.projectsCompleted}+ +

+

Projects Completed

+
+ +
+

+ {data.stats.happyClients}+ +

+

Happy Clients

+
+
+
+ + {/* SKILLS */} +
+

+ Skills +

+ +
+ {data.skills.map((skill) => ( + + {skill.name} + + ))} +
+
+ + {/* PROJECTS */} +
+

+ Projects +

+ +
+ {data.projects.map((project) => ( +
+ {project.title} + +
+

+ {project.title} +

+ +

+ {project.description} +

+ +
+ {project.techStack.map((tech) => ( + + {tech} + + ))} +
+ + +
+
+ ))}
-
+ + + {/* EXPERIENCE */} +
+

+ Experience +

+ +
+ {data.experience.map((job, idx) => ( +
+

+ {job.role} +

+ +

+ {job.company} +

+ +

+ {job.period} +

+ +

+ {job.description} +

+
+ ))} +
+
+ + {/* TESTIMONIALS */} +
+

+ Testimonials +

+ +
+ {data.testimonials.map((item) => ( +
+
+ {item.name} + +
+

+ {item.name} +

+

+ {item.role} +

+
+
+ +

+ "{item.text}" +

+
+ ))} +
+
+ + {/* CONTACT */} +
+

+ Let's Work Together +

+ +

+ Open to freelance work, collaborations and opportunities. +

+ + + Contact Me + +
); -} +} \ No newline at end of file diff --git a/frontend/src/pages/NotFound.jsx b/frontend/src/pages/NotFound.jsx index acbdcde28..942e4426c 100644 --- a/frontend/src/pages/NotFound.jsx +++ b/frontend/src/pages/NotFound.jsx @@ -1,93 +1,157 @@ -import React, { useState, useEffect } from 'react'; -import { Link } from 'react-router-dom'; - -const NotFound = () => { - const [terminalText, setTerminalText] = useState(''); - const fullText = [ - '> git checkout page', - 'error: pathspec \'page\' did not match any file(s) known to git.', - '> npm run locate-dashboard', - 'sh: locate-dashboard: command not found', - '404: Brain Not Found', - '> _' - ]; + import React, { useState, useEffect } from 'react'; + import { Link, useLocation, useNavigate, useSearchParams } from "react-router-dom"; + import SearchInput from "../components/SearchInput"; + import ReportBugModal from "../components/ReportBugModal"; + + const NotFound = () => { + const [terminalText, setTerminalText] = useState(''); + const fullText = [ + '> git checkout page', + 'error: pathspec \'page\' did not match any file(s) known to git.', + '> npm run locate-dashboard', + 'sh: locate-dashboard: command not found', + '404: Brain Not Found', + '> _' + ]; + + const location = useLocation(); + const navigate = useNavigate(); + const [searchParams, setSearchParams] = useSearchParams(); + + const attemptedPath = location.pathname; + + const [search, setSearch] = useState( + searchParams.get("query") || attemptedPath + ); + + const [isBugModalOpen, setIsBugModalOpen] = useState(false); useEffect(() => { - let currentLine = 0; - let currentChar = 0; - const typingInterval = setInterval(() => { - if (currentLine < fullText.length) { - if (currentChar < fullText[currentLine].length) { - setTerminalText(prev => prev + fullText[currentLine][currentChar]); - currentChar++; + setSearchParams({ + query: search, + }); + }, [search, setSearchParams]); + + useEffect(() => { + let currentLine = 0; + let currentChar = 0; + const typingInterval = setInterval(() => { + if (currentLine < fullText.length) { + if (currentChar < fullText[currentLine].length) { + const char = fullText[currentLine][currentChar]; + setTerminalText(prev => prev + char); + currentChar++; +} else { + setTerminalText(prev => prev + '\n'); + currentLine++; + currentChar = 0; + } } else { - setTerminalText(prev => prev + '\n'); - currentLine++; - currentChar = 0; + clearInterval(typingInterval); } - } else { - clearInterval(typingInterval); - } - }, 50); - - return () => clearInterval(typingInterval); - }, []); - - return ( -
- {/* Glitching 404 Heading */} -
-

- 404 -

-
- 404 -
-
- 404 -
-
+ }, 50); + + + + return () => clearInterval(typingInterval); + }, []); + + - {/* Humorous Headline */} -
-

- FATAL: HEAD detached at unknown-route -

-

- This page has been force-pushed into a black hole or never existed in this branch. -

-
- {/* Simulated Code Error Block */} -
-
-
-
-
- terminal — career-pilot + + return ( +
+ {/* Glitching 404 Heading */} +
+

+ 404 +

+
+ 404 +
+
+ 404 +
-
-
-            {terminalText}
-          
+ + {/* Humorous Headline */} +
+

+ FATAL: HEAD detached at unknown-route +

+

+ This page has been force-pushed into a black hole or never existed in this branch. +

-
- {/* Action Button */} - +
+
+
+
+ terminal — career-pilot +
+
+
+              {terminalText}
+            
+
+
+ +
+

+ You tried to visit: + + {attemptedPath} + +

+ + + +
+ + +
- ); -}; +
+ + setIsBugModalOpen(false)} + brokenUrl={attemptedPath} + /> + + {/* Action Button */} + + git checkout dashboard + + + + + + {/* Subtle background element */} +
+
+ ); + }; -export default NotFound; + export default NotFound;