11import React , { useState , useEffect , useMemo } from 'react' ;
22import { motion , AnimatePresence } from 'framer-motion' ;
3- import { ArrowLeftIcon , GithubLogoIcon , GlobeIcon } from '@phosphor-icons/react' ;
3+ import { ArrowLeftIcon , GithubLogoIcon , GlobeIcon , SunIcon , MoonIcon } from '@phosphor-icons/react' ;
44import { useNavigate , useParams } from 'react-router-dom' ;
55import { useProjects } from '../utils/projectParser' ;
66import Loading from '../components/Loading' ;
@@ -15,6 +15,7 @@ const MinimalModernProjectPage = () => {
1515 const [ sections , setSections ] = useState ( [ ] ) ;
1616 const [ activeSectionId , setActiveSectionId ] = useState ( null ) ;
1717 const [ loadingContent , setLoadingContent ] = useState ( true ) ;
18+ const [ isBlackMode , setIsBlackMode ] = useState ( false ) ;
1819
1920 useEffect ( ( ) => {
2021 if ( projects . length > 0 ) {
@@ -92,22 +93,46 @@ const MinimalModernProjectPage = () => {
9293 return < Loading /> ;
9394 }
9495
96+ const themeClasses = {
97+ bg : isBlackMode ? 'bg-[#050505]' : 'bg-[#f3f1e9]' ,
98+ text : isBlackMode ? 'text-white' : 'text-black' ,
99+ textMuted : isBlackMode ? 'text-zinc-500' : 'text-zinc-400' ,
100+ border : isBlackMode ? 'border-white' : 'border-black' ,
101+ borderMuted : isBlackMode ? 'border-zinc-800' : 'border-zinc-200' ,
102+ shadow : isBlackMode ? 'shadow-[30px_30px_0px_0px_rgba(255,255,255,1)]' : 'shadow-[30px_30px_0px_0px_rgba(0,0,0,1)]' ,
103+ prose : isBlackMode ? 'prose-invert' : 'prose-zinc' ,
104+ activeTab : isBlackMode ? 'text-white' : 'text-black' ,
105+ inactiveTab : isBlackMode ? 'text-zinc-800' : 'text-zinc-300' ,
106+ subtextActive : isBlackMode ? 'text-zinc-400' : 'text-zinc-500' ,
107+ subtextInactive : isBlackMode ? 'text-zinc-800' : 'text-zinc-300'
108+ } ;
109+
95110 return (
96- < div className = " min-h-screen bg-[#f3f1e9] text-black p-8 md:p-16 flex flex-col font-instr-sans overflow-hidden" >
111+ < div className = { ` min-h-screen ${ themeClasses . bg } ${ themeClasses . text } p-8 md:p-16 flex flex-col font-instr-sans overflow-hidden transition-colors duration-500` } >
97112 < Seo
98113 title = { `${ project . title } | Fezcodex` }
99114 description = { project . shortDescription }
100115 image = { project . image }
101116 keywords = { project . technologies }
102117 />
103118 < div className = "flex justify-between items-center mb-16 z-10" >
104- < button
105- onClick = { ( ) => navigate ( '/projects' ) }
106- className = "flex items-center gap-2 text-zinc-500 hover:text-black transition-colors group w-fit"
107- >
108- < ArrowLeftIcon size = { 20 } className = "group-hover:-translate-x-1 transition-transform" />
109- < span className = "text-sm font-bold uppercase tracking-widest" > Back to Projects</ span >
110- </ button >
119+ < div className = "flex items-center gap-8" >
120+ < button
121+ onClick = { ( ) => navigate ( '/projects' ) }
122+ className = { `flex items-center gap-2 ${ isBlackMode ? 'text-zinc-400 hover:text-white' : 'text-zinc-500 hover:text-black' } transition-colors group w-fit` }
123+ >
124+ < ArrowLeftIcon size = { 20 } className = "group-hover:-translate-x-1 transition-transform" />
125+ < span className = "text-sm font-bold uppercase tracking-widest" > Back to Projects</ span >
126+ </ button >
127+
128+ < button
129+ onClick = { ( ) => setIsBlackMode ( ! isBlackMode ) }
130+ className = { `p-2 rounded-full border-2 ${ themeClasses . border } hover:bg-zinc-500/10 transition-all` }
131+ title = { isBlackMode ? 'Switch to Light' : 'Switch to Black' }
132+ >
133+ { isBlackMode ? < SunIcon size = { 20 } weight = "bold" /> : < MoonIcon size = { 20 } weight = "bold" /> }
134+ </ button >
135+ </ div >
111136
112137 < div className = "flex gap-12 items-center" >
113138 < div className = "hidden md:flex gap-6 items-center border-r-2 border-zinc-200 pr-12 mr-4" >
@@ -116,7 +141,7 @@ const MinimalModernProjectPage = () => {
116141 href = { project . repo_link }
117142 target = "_blank"
118143 rel = "noopener noreferrer"
119- className = " flex items-center gap-2 hover:opacity-50 transition-opacity"
144+ className = { ` flex items-center gap-2 ${ isBlackMode ? ' hover:text-zinc-400' : 'hover: opacity-50' } transition-opacity` }
120145 title = "Github Repository"
121146 >
122147 < GithubLogoIcon size = { 20 } weight = "bold" />
@@ -128,7 +153,7 @@ const MinimalModernProjectPage = () => {
128153 href = { project . demo_link }
129154 target = "_blank"
130155 rel = "noopener noreferrer"
131- className = " flex items-center gap-2 hover:opacity-50 transition-opacity"
156+ className = { ` flex items-center gap-2 ${ isBlackMode ? ' hover:text-zinc-400' : 'hover: opacity-50' } transition-opacity` }
132157 title = "Live Demo"
133158 >
134159 < GlobeIcon size = { 20 } weight = "bold" />
@@ -137,10 +162,10 @@ const MinimalModernProjectPage = () => {
137162 ) }
138163 </ div >
139164 < div className = "hidden md:flex flex-col items-end" >
140- < span className = " text-[10px] text-zinc-400 font-bold uppercase tracking-[0.2em]" > Project Phase</ span >
165+ < span className = { ` text-[10px] ${ themeClasses . textMuted } font-bold uppercase tracking-[0.2em]` } > Project Phase</ span >
141166 < span className = "text-sm font-black uppercase tracking-widest" > { activeSection ?. id ?. toUpperCase ( ) } </ span >
142167 </ div >
143- < div className = " w-12 h-12 border-2 border-black flex items-center justify-center font-black" >
168+ < div className = { ` w-12 h-12 border-2 ${ themeClasses . border } flex items-center justify-center font-black` } >
144169 { sections . findIndex ( s => s . id === activeSectionId ) + 1 }
145170 </ div >
146171 </ div >
@@ -155,16 +180,16 @@ const MinimalModernProjectPage = () => {
155180 className = "group cursor-pointer relative"
156181 >
157182 < div className = "flex items-center gap-6" >
158- < span className = { `text-sm font-black transition-colors ${ activeSectionId === section . id ? 'text-black' : 'text-zinc-300' } ` } >
183+ < span className = { `text-sm font-black transition-colors ${ activeSectionId === section . id ? themeClasses . activeTab : themeClasses . inactiveTab } ` } >
159184 0{ idx + 1 }
160185 </ span >
161186 < div className = "flex flex-col" >
162- < span className = { `text-[10px] font-bold uppercase tracking-[0.3em] transition-colors ${ activeSectionId === section . id ? 'text-zinc-500' : 'text-zinc-300' } ` } >
187+ < span className = { `text-[10px] font-bold uppercase tracking-[0.3em] transition-colors ${ activeSectionId === section . id ? themeClasses . subtextActive : themeClasses . subtextInactive } ` } >
163188 { section . subtext }
164189 </ span >
165190 < h2
166191 className = { `text-4xl md:text-6xl font-black uppercase transition-all duration-300 ${
167- activeSectionId === section . id ? 'text-black translate-x-2' : 'text-zinc-300 group-hover:text-zinc-400 '
192+ activeSectionId === section . id ? themeClasses . activeTab + ' translate-x-2' : themeClasses . inactiveTab + ' group-hover:text-zinc-500 '
168193 } `}
169194 >
170195 { section . label }
@@ -180,13 +205,13 @@ const MinimalModernProjectPage = () => {
180205 exit = { { height : 0 , opacity : 0 , marginTop : 0 } }
181206 className = "overflow-hidden pl-12"
182207 >
183- < div className = " max-w-lg prose prose-sm prose-zinc border-l-4 border-black pl-6" >
208+ < div className = { ` max-w-lg prose prose-sm ${ themeClasses . prose } border-l-4 ${ themeClasses . border } pl-6` } >
184209 < ReactMarkdown components = { {
185210 img : ( ) => null , // Skip images in text view as they are handled by the hero
186211 h1 : ( ) => null ,
187212 h2 : ( ) => null ,
188213 a : ( { node, children, ...props } ) => (
189- < a { ...props } className = " text-black font-black underline" target = "_blank" rel = "noopener noreferrer" >
214+ < a { ...props } className = { ` ${ isBlackMode ? ' text-white' : 'text- black' } font-black underline` } target = "_blank" rel = "noopener noreferrer" >
190215 { children }
191216 </ a >
192217 )
@@ -201,7 +226,7 @@ const MinimalModernProjectPage = () => {
201226 href = { project . repo_link }
202227 target = "_blank"
203228 rel = "noopener noreferrer"
204- className = " inline-flex items-center justify-center gap-3 bg-black text-white px-10 py-5 text-[10px] font-black uppercase tracking-[0.3em] hover:bg-zinc-800 transition-colors w-full sm:w-fit"
229+ className = { `no-underline inline-flex items-center justify-center gap-3 ${ isBlackMode ? ' bg-white text- black' : 'bg-black text-white' } px-10 py-5 text-[10px] font-black uppercase tracking-[0.3em] hover:opacity-80 transition-colors w-full sm:w-fit` }
205230 >
206231 < GithubLogoIcon size = { 20 } weight = "bold" />
207232 Download Source
@@ -212,7 +237,7 @@ const MinimalModernProjectPage = () => {
212237 href = { project . demo_link }
213238 target = "_blank"
214239 rel = "noopener noreferrer"
215- className = " inline-flex items-center justify-center gap-3 border-[3px] border-black text-black px-10 py-5 text-[10px] font-black uppercase tracking-[0.3em] hover:bg-black hover:text-white transition-all w-full sm:w-fit"
240+ className = { ` inline-flex items-center justify-center gap-3 border-[3px] ${ themeClasses . border } ${ themeClasses . text } px-10 py-5 text-[10px] font-black uppercase tracking-[0.3em] ${ isBlackMode ? ' hover:bg-white hover:text- black' : ' hover:bg-black hover: text-white' } transition-all w-full sm:w-fit` }
216241 >
217242 < GlobeIcon size = { 20 } weight = "bold" />
218243 Launch Application
@@ -229,7 +254,7 @@ const MinimalModernProjectPage = () => {
229254 </ div >
230255
231256 < div className = "lg:w-3/5 relative" >
232- < div className = " w-full aspect-[4/5] lg:h-[70vh] relative overflow-hidden border-[8px] border-black shadow-[30px_30px_0px_0px_rgba(0,0,0,1)] bg-zinc-200" >
257+ < div className = { ` w-full aspect-[4/5] lg:h-[70vh] relative overflow-hidden border-[8px] ${ themeClasses . border } ${ themeClasses . shadow } bg-zinc-200 transition-all duration-500` } >
233258 < AnimatePresence mode = "wait" >
234259 < motion . div
235260 key = { `${ project . slug } -${ activeSectionId } ` }
@@ -273,13 +298,13 @@ const MinimalModernProjectPage = () => {
273298 </ div >
274299 </ div >
275300
276- < div className = " mt-12 flex justify-between items-end border-t-2 border-black pt-8" >
277- < div className = " text-[10px] font-black uppercase tracking-[0.5em] text-zinc-400" >
301+ < div className = { ` mt-12 flex justify-between items-end border-t-2 ${ themeClasses . border } pt-8` } >
302+ < div className = { ` text-[10px] font-black uppercase tracking-[0.5em] ${ themeClasses . textMuted } ` } >
278303 Digital Archive / { project . title } / { new Date ( ) . getFullYear ( ) }
279304 </ div >
280305 < div className = "flex gap-2" >
281306 { sections . map ( ( s , i ) => (
282- < div key = { s . id } className = { `w-8 h-2 ${ s . id === activeSectionId ? 'bg-black' : 'bg-zinc-200' } ` } />
307+ < div key = { s . id } className = { `w-8 h-2 ${ s . id === activeSectionId ? ( isBlackMode ? 'bg-white' : 'bg- black') : ( isBlackMode ? 'bg-zinc-900' : 'bg-zinc- 200') } ` } />
283308 ) ) }
284309 </ div >
285310 </ div >
0 commit comments