Implement Dark Glassmorphism Theme (Navbar, Cards, Fonts)

This commit is contained in:
dyzulk
2026-01-16 18:30:57 +07:00
parent e165bc96ab
commit 301f3da6bb
8 changed files with 135 additions and 83 deletions

20
package-lock.json generated
View File

@@ -8,6 +8,8 @@
"name": "dyzulk.github.io", "name": "dyzulk.github.io",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@fontsource/geist-mono": "^5.2.7",
"@fontsource/geist-sans": "^5.2.5",
"@supabase/supabase-js": "^2.90.1", "@supabase/supabase-js": "^2.90.1",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
@@ -932,6 +934,24 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@fontsource/geist-mono": {
"version": "5.2.7",
"resolved": "https://registry.npmjs.org/@fontsource/geist-mono/-/geist-mono-5.2.7.tgz",
"integrity": "sha512-xVPVFISJg/K0VVd+aQN0Y7X/sw9hUcJPyDWFJ5GpyU3bHELhoRsJkPSRSHXW32mOi0xZCUQDOaPj1sqIFJ1FGg==",
"license": "OFL-1.1",
"funding": {
"url": "https://github.com/sponsors/ayuhito"
}
},
"node_modules/@fontsource/geist-sans": {
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/@fontsource/geist-sans/-/geist-sans-5.2.5.tgz",
"integrity": "sha512-anllOHyJbElRs9fV15TeDRqAeb1IKm4bSknPl6ZMoyPTx1BBy7logudcUwpNjmQLkzn4Q0JGQLRCUKJYoyST6A==",
"license": "OFL-1.1",
"funding": {
"url": "https://github.com/sponsors/ayuhito"
}
},
"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",

View File

@@ -10,6 +10,8 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@fontsource/geist-mono": "^5.2.7",
"@fontsource/geist-sans": "^5.2.5",
"@supabase/supabase-js": "^2.90.1", "@supabase/supabase-js": "^2.90.1",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",

View File

@@ -11,27 +11,36 @@ export default function Navbar() {
] ]
return ( return (
<header className="sticky top-0 z-50 w-full border-b border-slate-200 dark:border-slate-800 bg-white/80 dark:bg-slate-950/80 backdrop-blur-md"> <div className="fixed top-6 left-0 right-0 z-50 flex justify-center px-4">
<div className="container mx-auto px-4 h-16 flex items-center justify-between"> <nav className="flex items-center gap-1 p-1 rounded-full border border-white/10 bg-black/50 backdrop-blur-xl shadow-lg ring-1 ring-white/5">
<Link to="/" className="text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-blue-600 to-cyan-500"> <Link
Dyzulk. to="/"
className="ml-2 mr-4 flex items-center gap-2 font-bold text-white tracking-tight"
>
<img src="/logo.svg" alt="Dyzulk" className="w-6 h-6" />
<span>Dyzulk.</span>
</Link> </Link>
<nav className="flex gap-6"> <div className="flex items-center gap-1 pr-1">
{links.map((link) => ( {links.map((link) => {
const isActive = location.pathname === link.href
return (
<Link <Link
key={link.href} key={link.href}
to={link.href} to={link.href}
className={cn( className={cn(
"text-sm font-medium transition-colors hover:text-blue-600", "px-4 py-2 rounded-full text-sm font-medium transition-all duration-300",
location.pathname === link.href ? "text-blue-600" : "text-slate-600 dark:text-slate-400" isActive
? "bg-white text-black shadow-sm"
: "text-zinc-400 hover:text-white hover:bg-white/5"
)} )}
> >
{link.label} {link.label}
</Link> </Link>
))} )
})}
</div>
</nav> </nav>
</div> </div>
</header>
) )
} }

View File

@@ -3,13 +3,13 @@ import Navbar from './Navbar'
export default function PublicLayout() { export default function PublicLayout() {
return ( return (
<div className="flex flex-col min-h-screen bg-white dark:bg-slate-950 text-slate-900 dark:text-slate-50"> <div className="flex flex-col min-h-screen bg-background text-foreground selection:bg-white/20">
<Navbar /> <Navbar />
<main className="flex-1"> <main className="flex-1 pt-24 pb-12">
<Outlet /> <Outlet />
</main> </main>
<footer className="py-8 border-t border-slate-100 dark:border-slate-900 text-center text-slate-500 text-sm"> <footer className="py-8 border-t border-white/5 text-center text-muted-foreground text-sm">
<p>© {new Date().getFullYear()} Dyzulk. Built with React & Supabase.</p> <p>© {new Date().getFullYear()} DyzulkDev. Built with React & Supabase.</p>
</footer> </footer>
</div> </div>
) )

View File

@@ -6,9 +6,9 @@ interface ProjectCardProps {
export function ProjectCard({ project }: ProjectCardProps) { export function ProjectCard({ project }: ProjectCardProps) {
return ( return (
<div className="group relative bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-xl overflow-hidden hover:shadow-xl transition-all duration-300 flex flex-col h-full"> <div className="group relative glass-card h-full flex flex-col overflow-hidden">
{/* Image */} {/* Image */}
<div className="aspect-video w-full overflow-hidden bg-slate-100 dark:bg-slate-800"> <div className="aspect-video w-full overflow-hidden bg-white/5 border-b border-white/5">
{project.cover_image ? ( {project.cover_image ? (
<img <img
src={project.cover_image} src={project.cover_image}
@@ -16,7 +16,7 @@ export function ProjectCard({ project }: ProjectCardProps) {
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500" className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
/> />
) : ( ) : (
<div className="w-full h-full flex items-center justify-center text-slate-400"> <div className="w-full h-full flex items-center justify-center text-muted-foreground">
No Image No Image
</div> </div>
)} )}
@@ -24,30 +24,30 @@ export function ProjectCard({ project }: ProjectCardProps) {
{/* Content */} {/* Content */}
<div className="p-5 flex flex-col flex-1"> <div className="p-5 flex flex-col flex-1">
<h3 className="text-xl font-bold mb-2 group-hover:text-blue-500 transition-colors"> <h3 className="text-xl font-bold mb-2 group-hover:text-primary transition-colors tracking-tight">
{project.title} {project.title}
</h3> </h3>
<p className="text-slate-600 dark:text-slate-400 text-sm mb-4 line-clamp-3 flex-1"> <p className="text-muted-foreground text-sm mb-4 line-clamp-3 flex-1 leading-relaxed">
{project.description} {project.description}
</p> </p>
{/* Tech Stack */} {/* Tech Stack */}
<div className="flex flex-wrap gap-2 mb-4"> <div className="flex flex-wrap gap-2 mb-6">
{project.tech_stack?.map((tech: string) => ( {project.tech_stack?.map((tech: string) => (
<span key={tech} className="px-2 py-1 text-xs bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 rounded-md"> <span key={tech} className="px-2.5 py-1 text-[10px] font-medium bg-white/5 border border-white/5 text-muted-foreground rounded-full">
{tech} {tech}
</span> </span>
))} ))}
</div> </div>
{/* Links */} {/* Links */}
<div className="flex items-center gap-4 mt-auto pt-4 border-t border-slate-100 dark:border-slate-800"> <div className="flex items-center gap-4 mt-auto pt-4 border-t border-white/5">
{project.demo_url && ( {project.demo_url && (
<a <a
href={project.demo_url} href={project.demo_url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="flex items-center gap-1 text-sm font-medium text-blue-600 hover:underline" className="flex items-center gap-2 text-xs font-semibold text-white hover:text-blue-400 transition-colors"
> >
<ExternalLink size={14} /> Live Demo <ExternalLink size={14} /> Live Demo
</a> </a>
@@ -57,7 +57,7 @@ export function ProjectCard({ project }: ProjectCardProps) {
href={project.repo_url} href={project.repo_url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="flex items-center gap-1 text-sm font-medium text-slate-600 hover:text-black dark:text-slate-400 dark:hover:text-white" className="flex items-center gap-2 text-xs font-semibold text-muted-foreground hover:text-white transition-colors"
> >
<Github size={14} /> Code <Github size={14} /> Code
</a> </a>

View File

@@ -4,58 +4,59 @@
@layer base { @layer base {
:root { :root {
--background: 0 0% 100%; /* Deep Graphite / Black Theme Base */
--foreground: 222.2 84% 4.9%; --background: 0 0% 4%; /* #0a0a0a */
--card: 0 0% 100%; --foreground: 0 0% 98%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%; --card: 0 0% 4%;
--popover-foreground: 222.2 84% 4.9%; --card-foreground: 0 0% 98%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%; --popover: 0 0% 4%;
--secondary: 210 40% 96.1%; --popover-foreground: 0 0% 98%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%; --primary: 0 0% 98%;
--muted-foreground: 215.4 16.3% 46.9%; --primary-foreground: 240 5.9% 10%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%; --secondary: 240 3.7% 15.9%;
--destructive: 0 84.2% 60.2%; --secondary-foreground: 0 0% 98%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%; --muted: 240 3.7% 15.9%;
--input: 214.3 31.8% 91.4%; --muted-foreground: 240 5% 64.9%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem; --accent: 240 3.7% 15.9%;
--chart-1: 12 76% 61%; --accent-foreground: 0 0% 98%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%; --destructive: 0 62.8% 30.6%;
--chart-4: 43 74% 66%; --destructive-foreground: 0 0% 98%;
--chart-5: 27 87% 67%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
--radius: 0.75rem; /* More rounded */
} }
/* Force Dark Mode Default */
.dark { .dark {
--background: 222.2 84% 4.9%; --background: 0 0% 4%;
--foreground: 210 40% 98%; --foreground: 0 0% 98%;
--card: 222.2 84% 4.9%; --card: 0 0% 4%;
--card-foreground: 210 40% 98%; --card-foreground: 0 0% 98%;
--popover: 222.2 84% 4.9%; --popover: 0 0% 4%;
--popover-foreground: 210 40% 98%; --popover-foreground: 0 0% 98%;
--primary: 210 40% 98%; --primary: 0 0% 98%;
--primary-foreground: 222.2 47.4% 11.2%; --primary-foreground: 240 5.9% 10%;
--secondary: 217.2 32.6% 17.5%; --secondary: 240 3.7% 15.9%;
--secondary-foreground: 210 40% 98%; --secondary-foreground: 0 0% 98%;
--muted: 217.2 32.6% 17.5%; --muted: 240 3.7% 15.9%;
--muted-foreground: 215 20.2% 65.1%; --muted-foreground: 240 5% 64.9%;
--accent: 217.2 32.6% 17.5%; --accent: 240 3.7% 15.9%;
--accent-foreground: 210 40% 98%; --accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%; --destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%; --destructive-foreground: 0 0% 98%;
--border: 217.2 32.6% 17.5%; --border: 240 3.7% 15.9%;
--input: 217.2 32.6% 17.5%; --input: 240 3.7% 15.9%;
--ring: 212.7 26.8% 83.9%; --ring: 240 4.9% 83.9%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
} }
} }
@@ -64,6 +65,20 @@
@apply border-border; @apply border-border;
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground antialiased selection:bg-white/20 selection:text-white;
font-feature-settings: "rlig" 1, "calt" 1;
}
}
/* Glassmorphism Utilities */
@layer utilities {
.glass {
@apply bg-white/5 backdrop-blur-md border border-white/10 shadow-lg;
}
.glass-hover {
@apply hover:bg-white/10 hover:border-white/20 transition-all duration-300;
}
.glass-card {
@apply glass glass-hover rounded-xl;
} }
} }

View File

@@ -1,5 +1,7 @@
import { StrictMode } from 'react' import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client' import { createRoot } from 'react-dom/client'
import '@fontsource/geist-sans'
import '@fontsource/geist-mono'
import './index.css' import './index.css'
import App from './App.tsx' import App from './App.tsx'

View File

@@ -7,6 +7,10 @@ export default {
], ],
theme: { theme: {
extend: { extend: {
fontFamily: {
sans: ['Geist Sans', 'sans-serif'],
mono: ['Geist Mono', 'monospace'],
},
borderRadius: { borderRadius: {
lg: 'var(--radius)', lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)', md: 'calc(var(--radius) - 2px)',