Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added conterminousness/web-portfolio.zip
Binary file not shown.
11 changes: 7 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ import Projects from './components/Projects'
import Contact from './components/Contact'
import ErrorBoundary from './components/ErrorBoundary'
import { LanguageProvider } from './contexts/LanguageContext.tsx'
import { ThemeProvider } from './contexts/ThemeContext'
import { useState } from 'react'

function App() {
const [isCollapsed, setIsCollapsed] = useState(false)

return (
<ErrorBoundary>
<LanguageProvider>
<div className="min-h-screen bg-gray-900 text-white overflow-y-scroll">
<ThemeProvider>
<LanguageProvider>
<div className="min-h-screen bg-white dark:bg-gray-900 text-gray-900 dark:text-white overflow-y-scroll">
<ErrorBoundary>
<Navbar onCollapseChange={setIsCollapsed} />
</ErrorBoundary>
Expand All @@ -41,8 +43,9 @@ function App() {
<Contact />
</ErrorBoundary>
</div>
</div>
</LanguageProvider>
</div>
</LanguageProvider>
</ThemeProvider>
</ErrorBoundary>
)
}
Expand Down
32 changes: 16 additions & 16 deletions src/components/Hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const Hero = () => {
}

return (
<section id="hero" className="min-h-screen flex items-center justify-center bg-gray-900 relative overflow-hidden pt-24 pb-16">
<section id="hero" className="min-h-screen flex items-center justify-center bg-white dark:bg-gray-900 relative overflow-hidden pt-24 pb-16">
{/* Squares Background Pattern */}
<SquaresBackground
speed={0.3}
Expand All @@ -42,8 +42,8 @@ const Hero = () => {
/>

{/* Floating Elements */}
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-gray-600 rounded-full mix-blend-multiply filter blur-3xl opacity-10"></div>
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-gray-500 rounded-full mix-blend-multiply filter blur-3xl opacity-10"></div>
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-gray-300 dark:bg-gray-600 rounded-full mix-blend-multiply filter blur-3xl opacity-10"></div>
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-gray-200 dark:bg-gray-500 rounded-full mix-blend-multiply filter blur-3xl opacity-10"></div>

<div className="container mx-auto px-6 relative z-10">
<div className="flex flex-col lg:flex-row items-center justify-between gap-12">
Expand All @@ -57,17 +57,17 @@ const Hero = () => {
transition={{ duration: 0.6, delay: 0.2 }}
>
{/* Terminal Header */}
<div className="flex items-center gap-2 px-4 py-2 bg-gray-800 border border-gray-700 rounded-t-lg">
<div className="flex items-center gap-2 px-4 py-2 bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-t-lg">
<div className="flex gap-2">
<div className="w-3 h-3 bg-red-500 rounded-full"></div>
<div className="w-3 h-3 bg-yellow-500 rounded-full"></div>
<div className="w-3 h-3 bg-green-500 rounded-full"></div>
</div>
<span className="text-gray-400 text-sm ml-4">mely@portfolio:~$</span>
<span className="text-gray-600 dark:text-gray-400 text-sm ml-4">mely@portfolio:~$</span>
</div>

{/* Terminal Content */}
<div className="bg-gray-900 border border-gray-700 border-t-0 rounded-b-lg p-8 text-left font-mono">
<div className="bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 border-t-0 rounded-b-lg p-8 text-left font-mono">
<div className="space-y-4">
{/* whoami command */}
<div className="flex items-center gap-2">
Expand All @@ -80,7 +80,7 @@ const Hero = () => {
/>
</div>

<div className="text-4xl lg:text-6xl font-bold text-white ml-4">
<div className="text-4xl lg:text-6xl font-bold text-gray-900 dark:text-white ml-4">
<TextType
text={t('hero.name')}
speed={30}
Expand Down Expand Up @@ -117,7 +117,7 @@ const Hero = () => {
</div>

{/* Description with Typewriter Effect */}
<div className="text-lg text-gray-300 ml-4 max-w-2xl leading-relaxed">
<div className="text-lg text-gray-600 dark:text-gray-300 ml-4 max-w-2xl leading-relaxed">
<TextType
text={t('hero.description')}
speed={15}
Expand All @@ -134,25 +134,25 @@ const Hero = () => {
>
<a
href="https://github.com/MelihIlker"
className="p-3 bg-gray-800 hover:bg-gray-700 rounded border border-gray-600 transition-all duration-300 transform hover:scale-110"
className="p-3 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 rounded border border-gray-300 dark:border-gray-600 transition-all duration-300 transform hover:scale-110"
target="_blank"
rel="noopener noreferrer"
>
<Github className="w-5 h-5 text-gray-300" />
<Github className="w-5 h-5 text-gray-600 dark:text-gray-300" />
</a>
<a
href="https://www.linkedin.com/in/melihilker"
className="p-3 bg-gray-800 hover:bg-gray-700 rounded border border-gray-600 transition-all duration-300 transform hover:scale-110"
className="p-3 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 rounded border border-gray-300 dark:border-gray-600 transition-all duration-300 transform hover:scale-110"
target="_blank"
rel="noopener noreferrer"
>
<Linkedin className="w-5 h-5 text-gray-300" />
<Linkedin className="w-5 h-5 text-gray-600 dark:text-gray-300" />
</a>
<a
href="mailto:melihilker9@gmail.com"
className="p-3 bg-gray-800 hover:bg-gray-700 rounded border border-gray-600 transition-all duration-300 transform hover:scale-110"
className="p-3 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 rounded border border-gray-300 dark:border-gray-600 transition-all duration-300 transform hover:scale-110"
>
<Mail className="w-5 h-5 text-gray-300" />
<Mail className="w-5 h-5 text-gray-600 dark:text-gray-300" />
</a>
</motion.div>

Expand All @@ -165,7 +165,7 @@ const Hero = () => {
>
<motion.button
onClick={scrollToProjects}
className="group flex items-center gap-2 px-6 py-3 bg-gray-800 hover:bg-gray-700 text-white text-sm rounded border border-gray-600 transition-all duration-300"
className="group flex items-center gap-2 px-6 py-3 bg-gray-200 dark:bg-gray-800 hover:bg-gray-300 dark:hover:bg-gray-700 text-gray-800 dark:text-white text-sm rounded border border-gray-300 dark:border-gray-600 transition-all duration-300"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
Expand All @@ -175,7 +175,7 @@ const Hero = () => {
</motion.button>
<motion.button
onClick={downloadCV}
className="group flex items-center gap-2 px-6 py-3 border border-gray-600 text-gray-300 hover:bg-gray-800 hover:text-white text-sm rounded transition-all duration-300"
className="group flex items-center gap-2 px-6 py-3 border border-gray-300 dark:border-gray-600 text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-800 hover:text-gray-800 dark:hover:text-white text-sm rounded transition-all duration-300"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
Expand Down
63 changes: 50 additions & 13 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import {
ChevronDown,
File,
Folder,
Globe
Globe,
Sun,
Moon
} from 'lucide-react'
import { useLanguage } from '../hooks/useLanguage'
import { useTheme } from '../contexts/ThemeContext'

interface SidebarProps {
onCollapseChange?: (isCollapsed: boolean) => void
Expand All @@ -23,6 +26,7 @@ const Sidebar = ({ onCollapseChange }: SidebarProps) => {
const [isMobileOpen, setIsMobileOpen] = useState(false)
const [activeSection, setActiveSection] = useState('hero')
const { language, setLanguage } = useLanguage()
const { theme, toggleTheme } = useTheme()

useEffect(() => {
const handleScroll = () => {
Expand Down Expand Up @@ -126,20 +130,31 @@ const Sidebar = ({ onCollapseChange }: SidebarProps) => {
{/* Mobile Language Toggle Button */}
<button
onClick={() => setLanguage(language === 'tr' ? 'en' : 'tr')}
className={`md:hidden fixed top-4 left-16 z-[60] p-2 bg-gray-800 border border-gray-600 rounded text-gray-300 hover:text-white transition-all duration-200 ${
className={`md:hidden fixed top-4 left-16 z-[60] p-2 bg-gray-800 dark:bg-gray-800 border border-gray-600 dark:border-gray-600 rounded text-gray-300 dark:text-gray-300 hover:text-white dark:hover:text-white transition-all duration-200 ${
isMobileOpen ? 'opacity-0 pointer-events-none' : 'opacity-100'
}`}
title={language === 'tr' ? 'Switch to English' : 'Türkçe\'ye Geç'}
>
<Globe className="w-4 h-4" />
</button>

{/* Mobile Theme Toggle Button */}
<button
onClick={toggleTheme}
className={`md:hidden fixed top-4 left-28 z-[60] p-2 bg-gray-800 dark:bg-gray-800 border border-gray-600 dark:border-gray-600 rounded text-gray-300 dark:text-gray-300 hover:text-white dark:hover:text-white transition-all duration-200 ${
isMobileOpen ? 'opacity-0 pointer-events-none' : 'opacity-100'
}`}
title={theme === 'dark' ? 'Switch to Light Mode' : 'Switch to Dark Mode'}
>
{theme === 'dark' ? <Sun className="w-4 h-4" /> : <Moon className="w-4 h-4" />}
</button>

{/* Sidebar */}
<div className={`fixed left-0 top-0 h-full bg-gray-900 border-r border-gray-700 transition-all duration-300 z-50 ${
<div className={`fixed left-0 top-0 h-full bg-white dark:bg-gray-900 border-r border-gray-300 dark:border-gray-700 transition-all duration-300 z-50 ${
isCollapsed ? 'w-12' : 'w-64'
} ${isMobileOpen ? 'translate-x-0' : '-translate-x-full md:translate-x-0'}`}>
{/* VS Code Header */}
<div className="h-8 bg-gray-800 border-b border-gray-700 flex items-center relative">
<div className="h-8 bg-gray-100 dark:bg-gray-800 border-b border-gray-300 dark:border-gray-700 flex items-center relative">
{/* Traffic Lights */}
<div className={`flex gap-1 ${isCollapsed ? 'justify-center w-full' : 'ml-3'}`}>
<div className="w-2 h-2 bg-red-500 rounded-full"></div>
Expand All @@ -149,27 +164,38 @@ const Sidebar = ({ onCollapseChange }: SidebarProps) => {

{/* EXPLORER Text - Only when expanded */}
{!isCollapsed && (
<span className="absolute left-1/2 transform -translate-x-1/2 text-gray-400 text-xs font-mono">EXPLORER</span>
<span className="absolute left-1/2 transform -translate-x-1/2 text-gray-600 dark:text-gray-400 text-xs font-mono">EXPLORER</span>
)}

{/* Language Toggle Button - Only when expanded */}
{!isCollapsed && (
<button
onClick={() => setLanguage(language === 'tr' ? 'en' : 'tr')}
className="absolute right-3 top-1/2 transform -translate-y-1/2 p-1 bg-gray-700 hover:bg-gray-600 border border-gray-600 rounded text-gray-300 hover:text-white transition-colors duration-200"
className="absolute right-12 top-1/2 transform -translate-y-1/2 p-1 bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 border border-gray-300 dark:border-gray-600 rounded text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-white transition-colors duration-200"
title={language === 'tr' ? 'Switch to English' : 'Türkçe\'ye Geç'}
>
<Globe className="w-3 h-3" />
</button>
)}

{/* Theme Toggle Button - Only when expanded */}
{!isCollapsed && (
<button
onClick={toggleTheme}
className="absolute right-3 top-1/2 transform -translate-y-1/2 p-1 bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 border border-gray-300 dark:border-gray-600 rounded text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-white transition-colors duration-200"
title={theme === 'dark' ? 'Switch to Light Mode' : 'Switch to Dark Mode'}
>
{theme === 'dark' ? <Sun className="w-3 h-3" /> : <Moon className="w-3 h-3" />}
</button>
)}
</div>

{/* Portfolio Folder */}
<div className="p-2">
{!isCollapsed && (
<div className="flex items-center gap-2 text-gray-300 text-sm font-mono mb-2">
<div className="flex items-center gap-2 text-gray-700 dark:text-gray-300 text-sm font-mono mb-2">
<ChevronDown className="w-3 h-3" />
<Folder className="w-4 h-4 text-blue-400" />
<Folder className="w-4 h-4 text-blue-500 dark:text-blue-400" />
<span>mely-portfolio</span>
</div>
)}
Expand All @@ -185,12 +211,12 @@ const Sidebar = ({ onCollapseChange }: SidebarProps) => {
onClick={() => scrollToSection(item.href)}
className={`w-full flex items-center gap-2 px-2 py-1.5 text-left transition-all duration-200 group ${
isActive
? 'bg-blue-600/20 text-blue-400 border-r-2 border-blue-400'
: 'text-gray-400 hover:text-gray-200 hover:bg-gray-800/50'
? 'bg-blue-100 dark:bg-blue-600/20 text-blue-600 dark:text-blue-400 border-r-2 border-blue-500 dark:border-blue-400'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800/50'
} ${isCollapsed ? 'justify-center' : ''}`}
>
{item.type === 'folder' ? (
<Folder className="w-4 h-4 text-blue-400" />
<Folder className="w-4 h-4 text-blue-500 dark:text-blue-400" />
) : (
<File className="w-4 h-4" />
)}
Expand All @@ -210,21 +236,32 @@ const Sidebar = ({ onCollapseChange }: SidebarProps) => {
{isCollapsed && (
<button
onClick={() => setLanguage(language === 'tr' ? 'en' : 'tr')}
className="hidden md:flex absolute bottom-4 left-1/2 transform -translate-x-1/2 p-2 bg-gray-800 border border-gray-600 rounded text-gray-300 hover:text-white transition-colors duration-200"
className="hidden md:flex absolute bottom-12 left-1/2 transform -translate-x-1/2 p-2 bg-gray-200 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-white transition-colors duration-200"
title={language === 'tr' ? 'Switch to English' : 'Türkçe\'ye Geç'}
>
<Globe className="w-4 h-4" />
</button>
)}

{/* Desktop Theme Toggle Button - Only when collapsed */}
{isCollapsed && (
<button
onClick={toggleTheme}
className="hidden md:flex absolute bottom-4 left-1/2 transform -translate-x-1/2 p-2 bg-gray-200 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-white transition-colors duration-200"
title={theme === 'dark' ? 'Switch to Light Mode' : 'Switch to Dark Mode'}
>
{theme === 'dark' ? <Sun className="w-4 h-4" /> : <Moon className="w-4 h-4" />}
</button>
)}

{/* Collapse Button */}
<button
onClick={() => {
const newCollapsed = !isCollapsed
setIsCollapsed(newCollapsed)
onCollapseChange?.(newCollapsed)
}}
className="hidden md:flex absolute top-1/2 -right-3 w-6 h-6 bg-gray-800 border border-gray-600 rounded-full items-center justify-center text-gray-400 hover:text-white transition-colors duration-200"
className="hidden md:flex absolute top-1/2 -right-3 w-6 h-6 bg-gray-200 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-full items-center justify-center text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-white transition-colors duration-200"
>
<ChevronRight className={`w-3 h-3 transition-transform duration-200 ${isCollapsed ? '' : 'rotate-180'}`} />
</button>
Expand Down
61 changes: 61 additions & 0 deletions src/contexts/ThemeContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { createContext, useContext, useEffect, useState, ReactNode } from 'react'

type Theme = 'light' | 'dark'

interface ThemeContextType {
theme: Theme
toggleTheme: () => void
}

const ThemeContext = createContext<ThemeContextType | undefined>(undefined)

export const useTheme = () => {
const context = useContext(ThemeContext)
if (context === undefined) {
throw new Error('useTheme must be used within a ThemeProvider')
}
return context
}

interface ThemeProviderProps {
children: ReactNode
}

export const ThemeProvider = ({ children }: ThemeProviderProps) => {
const [theme, setTheme] = useState<Theme>(() => {
// Check localStorage first, then system preference
const savedTheme = localStorage.getItem('theme') as Theme
if (savedTheme) {
return savedTheme
}

// Check system preference
if (window.matchMedia('(prefers-color-scheme: light)').matches) {
return 'light'
}

return 'dark'
})

useEffect(() => {
// Update localStorage when theme changes
localStorage.setItem('theme', theme)

// Update document class for Tailwind dark mode
if (theme === 'dark') {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
}, [theme])

const toggleTheme = () => {
setTheme((prevTheme: Theme) => prevTheme === 'light' ? 'dark' : 'light')
}

return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
)
}
1 change: 1 addition & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
darkMode: 'class',
theme: {
extend: {
colors: {
Expand Down