diff --git a/package-lock.json b/package-lock.json index b1e967c..cda5c35 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,8 @@ "@supabase/supabase-js": "^2.107.0", "bcryptjs": "^3.0.3", "jose": "^6.2.3", - "next": "16.2.7", + "lucide-react": "^1.17.0", + "next": "^16.2.9", "react": "19.2.4", "react-dom": "19.2.4" }, @@ -267,9 +268,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "dev": true, "license": "MIT", "optional": true, @@ -1023,9 +1024,9 @@ } }, "node_modules/@next/env": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.7.tgz", - "integrity": "sha512-tMJizPlj6ZYpBMMdK8S0LJufrP4QTdR6pcv9KQ/bVETPAmg0j1mlHE9G2c38UyGHxoBapgwuj7XjbGJ2RcDFOg==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.9.tgz", + "integrity": "sha512-ki5VxxXfzD/9TDe13wyeTKIjQTAwBVpnr8KhRDUr8ltMUq1/NBpWNT5tiPoxiGl+PHM4X2ahSOiPk6iAimIzPg==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1039,9 +1040,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.7.tgz", - "integrity": "sha512-vm1EDI/pVaBNNiychmxk3fft+OhQPVD9cIM/tReLZIQ3TfQ4kqI9DwKk00dzuS1ulC7icbrzCFrmRRlk9PfNdw==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.9.tgz", + "integrity": "sha512-HkfxNYUCmcct0Xsqib5KxqMSHV4AHJq857BNRchyBDs4YS19aHzVfn1kDuBYKqLLQBjXgnkIsjV2Kd4d2wzYhw==", "cpu": [ "arm64" ], @@ -1055,9 +1056,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.7.tgz", - "integrity": "sha512-O3IRSv1ZBL1zs0WrIgefTEcTKFVn+ryxBNe54erJ6KsD+2f/Mmt7g2jOYh8PSBdUwPtKQJuCsTMlZ7tIu2AcsQ==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.9.tgz", + "integrity": "sha512-7IAtK4MeybpqRV9GRABWEhJ62mOS+rzWOzOTFie4cSEtm12xsoOMJRcECoZx3FHPzFAqN/IJtHqWAFOLfl152w==", "cpu": [ "x64" ], @@ -1071,9 +1072,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.7.tgz", - "integrity": "sha512-Re6PZtjBDd0aMU+VcZcC/PrIvj4WhrjDYtMhhCVQamWN4L90EVP0pcEOBQD25prSlw7OzNw5QpHLWMilRLsRNw==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.9.tgz", + "integrity": "sha512-hBD75iWpUtkL9SmQmcRhmLomn9jgkPzCEkbOcLgHymPEKzv+6ONy13RRiIEz/iEObjkS2Jlb5gYS2XGoS3X4rw==", "cpu": [ "arm64" ], @@ -1087,9 +1088,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.7.tgz", - "integrity": "sha512-qyogG9QtBzWxgJfeGBvOEHI3851gTfCF3wLZ5RDLTBJGAmE9p1qDwKCOdrBrvBzRvYDT+gUDp72pzlSEfAXgNA==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.9.tgz", + "integrity": "sha512-qZTI3pf9SGc/obr8NkQAekBxmp1QK+kVm+VAf3BALLfFAj+1kUhkTxmrWpVos9R/UYIA8AWX2p6cGI5WdwzVUA==", "cpu": [ "arm64" ], @@ -1103,9 +1104,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.7.tgz", - "integrity": "sha512-Vhe4ZDuBpmMogrGi5D4R2Kq4JAQlj6+wvgaFYy31zfES0zPmt6TLA+cuYpM/OLrPZjo2MYQTHVqNUSCR6+fDZQ==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.9.tgz", + "integrity": "sha512-xm0HfRNX+UkH4R3c18ynswjj5o5uEj/7iI9p9omdtTSIsRCzQqkGMA+10nzJ4EHnYC3as65IMhbbl5fWRUWHYg==", "cpu": [ "x64" ], @@ -1119,9 +1120,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.7.tgz", - "integrity": "sha512-srvian89JahFLw1YLBEuhvPJ0DO5lpUeJQMXy4xYo7g628ZlNgXdNkqoxSAv9OYrBfByh6vxISMwW/mRbzCY+g==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.9.tgz", + "integrity": "sha512-QumimHkGEG6vM3PfEDWKyKen03NcqLOkeKB1EfcPe7VxzmEiCa4jNnMyBn/US5zcd/VE1CI+O8Ovb3lfjVHfGw==", "cpu": [ "x64" ], @@ -1135,9 +1136,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.7.tgz", - "integrity": "sha512-GX3wvLpULFuRFJzwHaKfm7QZJ18F4ZSuxlPJ96BoBglCzBmdSjyeBKF+ZhWhvL/ckxNfLnNa7bsObO2ipYpszw==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.9.tgz", + "integrity": "sha512-hzQpKZvw8rAwI6A2uQh6SacCSvNAXaIkPNsWwzqqfRiIMiXMfH936skDhz1OO6KpvdKkJrgHHtqQOq5PIXOvdQ==", "cpu": [ "arm64" ], @@ -1151,9 +1152,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.7.tgz", - "integrity": "sha512-J4WlM72NMk076Qsg0jTdK3SNXatlSdnjW7L7oNGLst1tAGjHrJh/FYi+pw9wyIjEtGRKDNzD0zuiY16oWYWVaw==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.9.tgz", + "integrity": "sha512-qr2VL3Ce5QrwgO2yh1ujSBawrimjVKX8FGF/cOynmdYKJY0BdHpGVNIRK1tqONB10Vkm25Ub1BD2bkjWs4+96w==", "cpu": [ "x64" ], @@ -1359,7 +1360,6 @@ "integrity": "sha512-5L7SUaFC1RyDraj2yRhyBzHTobyXHmohD100CChNtyPyleoq37Mqab5Gn8XEKI04dfN/oqPdpHk38MgcQWHbZg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -1952,6 +1952,40 @@ "node": ">=14.0.0" } }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", @@ -4448,6 +4482,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.17.0.tgz", + "integrity": "sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -4554,12 +4597,12 @@ "license": "MIT" }, "node_modules/next": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/next/-/next-16.2.7.tgz", - "integrity": "sha512-eMJxgjRzBaj3olkP4cBamHDXL79A8FC6u1GcsO1D1Tsx8bw/LLXUJCaoajVxtnhD3A1IJqIT8IcRJjgBIPJq4w==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.9.tgz", + "integrity": "sha512-MEOJiq/UvuezAdqVSceHbqDgZt1kDw2tpGVOlsdIoJsQdbN2JY2hpVG4xnXGkbdJUOEWhnRfiu/O4Hpc9Juwww==", "license": "MIT", "dependencies": { - "@next/env": "16.2.7", + "@next/env": "16.2.9", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", @@ -4573,14 +4616,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.2.7", - "@next/swc-darwin-x64": "16.2.7", - "@next/swc-linux-arm64-gnu": "16.2.7", - "@next/swc-linux-arm64-musl": "16.2.7", - "@next/swc-linux-x64-gnu": "16.2.7", - "@next/swc-linux-x64-musl": "16.2.7", - "@next/swc-win32-arm64-msvc": "16.2.7", - "@next/swc-win32-x64-msvc": "16.2.7", + "@next/swc-darwin-arm64": "16.2.9", + "@next/swc-darwin-x64": "16.2.9", + "@next/swc-linux-arm64-gnu": "16.2.9", + "@next/swc-linux-arm64-musl": "16.2.9", + "@next/swc-linux-x64-gnu": "16.2.9", + "@next/swc-linux-x64-musl": "16.2.9", + "@next/swc-win32-arm64-msvc": "16.2.9", + "@next/swc-win32-x64-msvc": "16.2.9", "sharp": "^0.34.5" }, "peerDependencies": { @@ -5295,9 +5338,9 @@ } }, "node_modules/sharp/node_modules/semver": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.2.tgz", - "integrity": "sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", "license": "ISC", "optional": true, "bin": { diff --git a/package.json b/package.json index b9e0275..430fb1d 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "@supabase/supabase-js": "^2.107.0", "bcryptjs": "^3.0.3", "jose": "^6.2.3", - "next": "16.2.7", + "lucide-react": "^1.17.0", + "next": "^16.2.9", "react": "19.2.4", "react-dom": "19.2.4" }, diff --git a/src/app/(main)/blog/page.tsx b/src/app/(main)/blog/page.tsx index b34221c..1653ffc 100644 --- a/src/app/(main)/blog/page.tsx +++ b/src/app/(main)/blog/page.tsx @@ -1,16 +1,20 @@ import { supabase } from "@/lib/supabase"; import ScrollReveal from "@/components/ScrollReveal"; +import FloatingBackButton from "@/components/FloatingBackButton"; export const metadata = { title: "Blog | Cris Charles Garcia", description: "Blog — Thoughts, tutorials, and notes on software development.", }; +export const dynamic = 'force-dynamic'; + export default async function BlogPage() { const { data: articleRows } = await supabase.from('articles').select('*').order('id', { ascending: false }); return ( <> +
Blog diff --git a/src/app/(main)/certifications/page.tsx b/src/app/(main)/certifications/page.tsx index b7005ea..df044d8 100644 --- a/src/app/(main)/certifications/page.tsx +++ b/src/app/(main)/certifications/page.tsx @@ -1,16 +1,20 @@ import { supabase } from "@/lib/supabase"; import ScrollReveal from "@/components/ScrollReveal"; +import FloatingBackButton from "@/components/FloatingBackButton"; export const metadata = { title: "All Certifications | Cris Charles Garcia", description: "Certifications — A collection of my professional certificates and courses.", }; +export const dynamic = 'force-dynamic'; + export default async function CertificationsPage() { const { data: certRows } = await supabase.from('certifications').select('*').order('id', { ascending: false }); return ( <> +
Certifications diff --git a/src/app/(main)/page.tsx b/src/app/(main)/page.tsx index acc476c..a0bd6c9 100644 --- a/src/app/(main)/page.tsx +++ b/src/app/(main)/page.tsx @@ -1,6 +1,9 @@ import { supabase } from "@/lib/supabase"; import ScrollReveal from "@/components/ScrollReveal"; import Link from "next/link"; +import { ProjectCard, ArticleCard, CertCard } from "@/components/ClientCardModals"; + +export const dynamic = 'force-dynamic'; export default async function Home() { const recaptchaSiteKey = process.env.RECAPTCHA_SITE_KEY || ""; @@ -140,24 +143,7 @@ export default async function Home() {
@@ -175,17 +161,12 @@ export default async function Home() { Certifications

My Certifications

-
+
{certRows && certRows.length > 0 ? certRows.map((cert, index) => ( -
-
{cert.icon || "🏆"}
-
-

{cert.title}

-

{cert.issuer}

- Issued {cert.date_issued} -
+
+
- )) :

No certifications available.

} + )) :

No certifications available.

}
All Certifications → @@ -204,15 +185,7 @@ export default async function Home() {
{articleRows && articleRows.length > 0 ? articleRows.map((article, index) => ( -
-
- {article.date_published} - {article.tag && {article.tag}} -
-

{article.title}

-

{article.excerpt}

- Read Article → -
+ )) :

No articles available.

}
diff --git a/src/app/(main)/projects/page.tsx b/src/app/(main)/projects/page.tsx index dd9d6e8..2956731 100644 --- a/src/app/(main)/projects/page.tsx +++ b/src/app/(main)/projects/page.tsx @@ -1,16 +1,20 @@ import { supabase } from "@/lib/supabase"; import ScrollReveal from "@/components/ScrollReveal"; +import FloatingBackButton from "@/components/FloatingBackButton"; export const metadata = { title: "All Projects | Cris Charles Garcia", description: "All Projects — A complete archive of apps, websites, and experiments built by Cris Charles Garcia.", }; +export const dynamic = 'force-dynamic'; + export default async function ProjectsPage() { const { data: projectRows } = await supabase.from('projects').select('*').order('id', { ascending: false }); return ( <> +
Projects diff --git a/src/app/admin/AdminDashboard.tsx b/src/app/admin/AdminDashboard.tsx index b5b40fa..d34fa47 100644 --- a/src/app/admin/AdminDashboard.tsx +++ b/src/app/admin/AdminDashboard.tsx @@ -1,7 +1,30 @@ "use client"; -import { useState, useRef } from "react"; +import { useState, useRef, useEffect } from "react"; import { useRouter } from "next/navigation"; +import { + LayoutDashboard, + FolderKanban, + Award, + BookOpen, + Layers, + ShieldCheck, + LogOut, + Moon, + Sun, + Plus, + Edit2, + Trash2, + MonitorPlay, + ZoomIn, + ZoomOut, + Maximize2, + X, + Menu, + CheckCircle2, + AlertCircle +} from "lucide-react"; + import { updateSettings, upsertProject, @@ -31,17 +54,18 @@ export default function AdminDashboard({ initialTechStack: any[]; username: string; }) { - const [activeTab, setActiveTab] = useState("profile"); + const [activeTab, setActiveTab] = useState("dashboard"); const [isSidebarOpen, setIsSidebarOpen] = useState(false); const router = useRouter(); // Dark mode toggle state - const [isDark, setIsDark] = useState(() => { + const [isDark, setIsDark] = useState(true); + + useEffect(() => { if (typeof window !== "undefined") { - return localStorage.getItem("theme") !== "light"; + setIsDark(localStorage.getItem("theme") !== "light"); } - return true; - }); + }, []); const handleToggle = (e: React.ChangeEvent) => { const checked = e.target.checked; @@ -58,6 +82,10 @@ export default function AdminDashboard({ const [isProjectModalOpen, setIsProjectModalOpen] = useState(false); const [isCertModalOpen, setIsCertModalOpen] = useState(false); const [isArticleModalOpen, setIsArticleModalOpen] = useState(false); + const [isPreviewModalOpen, setIsPreviewModalOpen] = useState(false); + + // Preview Zoom state + const [previewZoom, setPreviewZoom] = useState(1); // Form refs for unsaved changes confirmation const projectFormRef = useRef(null); @@ -148,6 +176,32 @@ export default function AdminDashboard({ onChange={handleToggle} /> + {/* Floating Toast Notification */} + {message.text && ( +
+ {message.type === 'success' ? : } +
{message.text}
+ +
+ )} + {/* Mobile Header */}
@@ -157,30 +211,16 @@ export default function AdminDashboard({
setIsSidebarOpen(!isSidebarOpen)} > - - - + {isSidebarOpen ? : }
{/* Sidebar Navigation */} @@ -219,23 +273,44 @@ export default function AdminDashboard({

{activeTab.toUpperCase()} MANAGEMENT

Welcome back, {username}.

-
- - Active Session +
+ +
+ + Active Session +
- {/* System Alerts */} - {message.text && ( -
- {message.type === "success" ? "✓" : "⚠️"} -
{message.text}
-
- )} - - {/* ================= TAB: PROFILE ================= */} - {activeTab === "profile" && ( + {/* ================= TAB: DASHBOARD / PROFILE ================= */} + {activeTab === "dashboard" && (
+ {/* Stats Overview Cards */} +
+ {[ + { title: "Total Projects", count: initialProjects.length, icon: }, + { title: "Certifications", count: initialCerts.length, icon: }, + { title: "Blog Articles", count: initialArticles.length, icon: }, + { title: "Tech Stack", count: initialTechStack.length, icon: }, + ].map((stat, i) => ( +
+
+ {stat.icon} +
+
+
{stat.count}
+
{stat.title}
+
+
+ ))} +
+
{ e.preventDefault(); handleAction(updateSettings, new FormData(e.currentTarget), "Settings updated!"); }}>
📝 About Me Bio Copy
@@ -249,24 +324,6 @@ export default function AdminDashboard({
-
-
📈 Statistics Counters
-
-
- - -
-
- - -
-
- - -
-
-
-
🔗 Social Links
@@ -293,7 +350,7 @@ export default function AdminDashboard({
- +
)} @@ -305,13 +362,16 @@ export default function AdminDashboard({
-
📁 Current Projects
+
+ Current Projects +
@@ -328,7 +388,9 @@ export default function AdminDashboard({ @@ -348,13 +412,13 @@ export default function AdminDashboard({ {/* Project Modal */} {isProjectModalOpen && ( -
-
e.stopPropagation()}> -
-

{editProject ? "✏️ Edit Project" : "➕ Add New Project"}

- +
+
e.stopPropagation()}> +
+

{editProject ? "Edit Project" : "Add New Project"}

+
-
+
{ e.preventDefault(); const form = e.currentTarget; @@ -374,20 +438,28 @@ export default function AdminDashboard({
-
- - -
+
+ + +
+
+ + +
+
+ + +
- +
-
+
@@ -406,13 +478,16 @@ export default function AdminDashboard({
-
🏆 Current Certifications
+
+ Current Certifications +
{proj.techstack}
- + + }} style={{ display: 'flex', alignItems: 'center', gap: '4px' }}> + Delete +
@@ -426,12 +501,12 @@ export default function AdminDashboard({ {initialCerts.map(cert => ( - + @@ -451,13 +526,13 @@ export default function AdminDashboard({ {/* Certification Modal */} {isCertModalOpen && ( -
-
e.stopPropagation()}> -
-

{editCert ? "✏️ Edit Certification" : "➕ Add Certification"}

- +
+
e.stopPropagation()}> +
+

{editCert ? "Edit Certification" : "Add Certification"}

+
-
+
{ e.preventDefault(); const form = e.currentTarget; @@ -483,10 +558,14 @@ export default function AdminDashboard({
- + +
+
+ +
-
+
@@ -505,13 +584,16 @@ export default function AdminDashboard({
-
📰 Current Articles
+
+ Current Articles +
{cert.icon}{cert.icon?.includes('fa-') ? : cert.icon} {cert.title} {cert.issuer}
- + + }} style={{ display: 'flex', alignItems: 'center', gap: '4px' }}> Delete
@@ -530,7 +612,7 @@ export default function AdminDashboard({ @@ -550,13 +632,13 @@ export default function AdminDashboard({ {/* Article Modal */} {isArticleModalOpen && ( -
-
e.stopPropagation()}> -
-

{editArticle ? "✏️ Edit Article" : "➕ Add Article"}

- +
+
e.stopPropagation()}> +
+

{editArticle ? "Edit Article" : "Add Article"}

+
-
+
{ e.preventDefault(); const form = e.currentTarget; @@ -586,10 +668,10 @@ export default function AdminDashboard({
- +
-
+
@@ -605,7 +687,9 @@ export default function AdminDashboard({ {activeTab === "techstack" && (
-
➕ Add Technology
+
+ Add Technology +
{ e.preventDefault(); const form = e.currentTarget; @@ -615,12 +699,16 @@ export default function AdminDashboard({
- +
-
⚡ Current Technologies
+
+ Current Technologies +
{initialTechStack.length === 0 ? (

No technologies configured.

) : ( @@ -648,7 +736,14 @@ export default function AdminDashboard({ {activeTab === "account" && (
-
🔒 Change Admin Credentials
+
+ Change Admin Credentials +
+ +
+

Update your username or set a new password. You will be logged out upon success.

+
+
{ e.preventDefault(); setIsSubmitting(true); @@ -665,10 +760,18 @@ export default function AdminDashboard({ } }}>
-
+
+ + {/* Visual Divider */} +
+
+ PASSWORD +
+
+
@@ -678,7 +781,7 @@ export default function AdminDashboard({
-
+
@@ -688,6 +791,44 @@ export default function AdminDashboard({
)} + + {/* ================= LIVE PREVIEW MODAL ================= */} + {isPreviewModalOpen && ( +
+
+
+
+ +

Live Site Preview

+
+
+
+ + {Math.round(previewZoom * 100)}% + + +
+ +
+
+
+
+
{art.date_published}
- + + }} style={{ display: 'flex', alignItems: 'center', gap: '4px' }}> Delete