From 011571e12db66a5e917b45699fa29c2299d7c2ce Mon Sep 17 00:00:00 2001 From: asepharyana Date: Sat, 22 Aug 2026 14:55:19 +0700 Subject: [PATCH] feat(web): overhaul frontend with cyber-intelligence design and interactive topology --- apps/web/app/[section]/[...slug]/page.tsx | 239 ++++++----- apps/web/app/[section]/page.tsx | 127 +++--- apps/web/app/components/CommandMenu.tsx | 200 ++++++--- apps/web/app/components/DocActions.tsx | 50 ++- apps/web/app/components/DocForm.tsx | 271 ++++++++----- apps/web/app/components/Header.tsx | 145 ++++--- .../app/components/InteractiveTopology.tsx | 379 ++++++++++++++++++ apps/web/app/components/Markdown.tsx | 75 +++- apps/web/app/components/McpConfigSnippet.tsx | 142 +++++-- apps/web/app/components/PdfExportView.tsx | 99 ++--- apps/web/app/components/Sidebar.tsx | 92 +++-- apps/web/app/components/TOC.tsx | 32 +- apps/web/app/components/ThemeToggle.tsx | 13 +- apps/web/app/create/page.tsx | 15 +- apps/web/app/export/pdf/page.tsx | 18 +- apps/web/app/globals.css | 312 +++++++------- apps/web/app/layout.tsx | 38 +- apps/web/app/login/page.tsx | 36 +- apps/web/app/page.tsx | 214 ++++++---- apps/web/app/search/page.tsx | 131 +++--- apps/web/package.json | 1 + bun.lock | 3 + 22 files changed, 1763 insertions(+), 869 deletions(-) create mode 100644 apps/web/app/components/InteractiveTopology.tsx diff --git a/apps/web/app/[section]/[...slug]/page.tsx b/apps/web/app/[section]/[...slug]/page.tsx index 87de718..d05cb98 100644 --- a/apps/web/app/[section]/[...slug]/page.tsx +++ b/apps/web/app/[section]/[...slug]/page.tsx @@ -11,6 +11,24 @@ import PdfExportView from "@/components/PdfExportView"; import { classifyPath, extractFoldersForSection } from "@mcpedia/core"; import { getSectionMeta } from "@mcpedia/config"; import type { DocumentMeta } from "@mcpedia/core"; +import { + Folder, + FileText, + Clock, + User, + Tag, + History, + FileDown, + ArrowLeft, + BookOpen, + Sparkles, + ShieldCheck, + CheckCircle2, + XCircle, + Target, + Trophy, + Zap, +} from "lucide-react"; export const dynamic = "force-dynamic"; @@ -45,48 +63,45 @@ function CustomFieldBadges({ if (customEntries.length === 0) return null; return ( -
+
{customEntries.map(([key, value]) => { const label = key.charAt(0).toUpperCase() + key.slice(1).replace(/_/g, " "); let colorClass = "bg-[var(--bg-elevated)] border-[var(--border-color)] text-[var(--text-secondary)]"; - let icon = "๐Ÿท๏ธ"; let displayValue: string; + let IconComponent = Tag; if (typeof value === "number") { colorClass = "bg-[var(--brand)]/10 border-[var(--brand)]/30 text-[var(--brand)] dark:text-[var(--accent)]"; - icon = "๐ŸŽฏ"; + IconComponent = Target; displayValue = `${value} pts`; } else if (typeof value === "boolean") { colorClass = value ? "bg-emerald-500/10 border-emerald-500/30 text-emerald-600 dark:text-emerald-400" : "bg-rose-500/10 border-rose-500/30 text-rose-600 dark:text-rose-400"; - icon = value ? "โœ“" : "โœ•"; + IconComponent = value ? CheckCircle2 : XCircle; displayValue = value ? "Solved" : "Pending"; } else if (Array.isArray(value)) { colorClass = "bg-[var(--brand)]/10 border-[var(--brand)]/30 text-[var(--brand)] dark:text-[var(--accent)]"; - icon = "๐Ÿ—‚๏ธ"; + IconComponent = Folder; displayValue = value.join(", "); } else { const v = String(value).toLowerCase(); if (/^(easy|simple|beginner)/i.test(v)) { colorClass = "bg-emerald-500/10 border-emerald-500/30 text-emerald-600 dark:text-emerald-400"; - icon = "๐ŸŸข"; displayValue = "Easy"; } else if (/^(medium|intermediate)/i.test(v)) { colorClass = "bg-amber-500/10 border-amber-500/30 text-amber-600 dark:text-amber-400"; - icon = "๐ŸŸก"; displayValue = "Medium"; } else if (/^(hard|expert|advanced)/i.test(v)) { colorClass = "bg-rose-500/10 border-rose-500/30 text-rose-600 dark:text-rose-400"; - icon = "๐Ÿ”ด"; displayValue = "Hard"; } else if (/^(pwn|web|crypto|misc|forensic|reverse|binary)/i.test(v)) { colorClass = "bg-indigo-500/10 border-indigo-500/30 text-indigo-600 dark:text-indigo-300"; - icon = "โšก"; + IconComponent = Zap; displayValue = v.toUpperCase(); } else if (/ctf|def.?con|event/i.test(v)) { colorClass = "bg-[var(--brand)]/10 border-[var(--brand)]/30 text-[var(--brand)] dark:text-[var(--accent)]"; - icon = "๐Ÿ†"; + IconComponent = Trophy; displayValue = String(value); } else { displayValue = String(value); @@ -96,11 +111,11 @@ function CustomFieldBadges({ return ( - {icon} + {label}: - {displayValue} + {displayValue} ); })} @@ -146,9 +161,9 @@ function FolderIndexPage({ const folderName = slug.split("/").pop()!.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" "); return ( -
- {/* Breadcrumb */} -