diff --git a/apps/admin/package.json b/apps/admin/package.json new file mode 100644 index 00000000..1354655f --- /dev/null +++ b/apps/admin/package.json @@ -0,0 +1,28 @@ +{ + "name": "@fused-gaming/admin", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "next dev -p 3001", + "build": "next build", + "start": "next start -p 3001", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "next": "14.2.5", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "framer-motion": "^11.3.8", + "zustand": "^4.5.4", + "clsx": "^2.1.1" + }, + "devDependencies": { + "@types/node": "^20.14.10", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "autoprefixer": "^10.4.19", + "postcss": "^8.4.39", + "tailwindcss": "^3.4.6", + "typescript": "^5.5.3" + } +} diff --git a/apps/admin/src/app/globals.css b/apps/admin/src/app/globals.css new file mode 100644 index 00000000..a34630a0 --- /dev/null +++ b/apps/admin/src/app/globals.css @@ -0,0 +1,39 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --admin-bg: #0a0a0a; + --admin-surface: #111111; + --admin-surface2: #1a1a1a; + --admin-border: #222222; + --admin-primary: #dc2626; + --admin-text: #f3f4f6; + --admin-muted: #9ca3af; + --admin-faint: #4b5563; + --admin-success: #22c55e; + --admin-warning: #f59e0b; + --admin-error: #ef4444; +} + +body { + background: var(--admin-bg); + color: var(--admin-text); + font-family: 'Inter', system-ui, sans-serif; +} + +/* Live preview iframe isolation */ +.brand-preview-frame { + border: 1px solid var(--admin-border); + border-radius: 12px; + overflow: hidden; +} + +/* Token color swatch */ +.color-swatch { + width: 32px; + height: 32px; + border-radius: 6px; + border: 1px solid rgba(255,255,255,0.1); + flex-shrink: 0; +} diff --git a/apps/admin/src/app/layout.tsx b/apps/admin/src/app/layout.tsx new file mode 100644 index 00000000..a55739bf --- /dev/null +++ b/apps/admin/src/app/layout.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; +import "./globals.css"; + +const inter = Inter({ subsets: ["latin"], variable: "--font-inter" }); + +export const metadata: Metadata = { + title: "Fused Gaming โ€” Admin", + description: "Brand management and deployment console", + robots: "noindex, nofollow", +}; + +export default function AdminLayout({ children }: { children: React.ReactNode }) { + return ( + + + {children} + + + ); +} diff --git a/apps/admin/src/app/page.tsx b/apps/admin/src/app/page.tsx new file mode 100644 index 00000000..0362c3ed --- /dev/null +++ b/apps/admin/src/app/page.tsx @@ -0,0 +1,5 @@ +import AdminDashboard from "@/components/AdminDashboard"; + +export default function AdminPage() { + return ; +} diff --git a/apps/admin/src/components/AdminDashboard.tsx b/apps/admin/src/components/AdminDashboard.tsx new file mode 100644 index 00000000..6d86c066 --- /dev/null +++ b/apps/admin/src/components/AdminDashboard.tsx @@ -0,0 +1,119 @@ +"use client"; + +import { useState } from "react"; +import BrandFormPanel from "@/components/panels/BrandFormPanel"; +import TokenPanel from "@/components/panels/TokenPanel"; +import DeployPanel from "@/components/panels/DeployPanel"; +import PreviewPanel from "@/components/panels/PreviewPanel"; + +type Tab = "form" | "tokens" | "preview" | "deploy" | "status"; + +const TABS: { id: Tab; label: string; icon: string }[] = [ + { id: "form", label: "Brand", icon: "โœฆ" }, + { id: "tokens", label: "Tokens", icon: "โฌก" }, + { id: "preview", label: "Preview", icon: "โ—ˆ" }, + { id: "deploy", label: "Deploy", icon: "๐Ÿš€" }, + { id: "status", label: "Status", icon: "โ—‰" }, +]; + +export default function AdminDashboard() { + const [activeTab, setActiveTab] = useState("form"); + const [sidebarOpen, setSidebarOpen] = useState(true); + + return ( +
+ {/* Sidebar */} + + + {/* Main content */} +
+ {/* Top bar */} +
+
+

+ {TABS.find((t) => t.id === activeTab)?.label} +

+

+ {activeTab === "form" && "Define brand identity and copy"} + {activeTab === "tokens" && "Customize design tokens and CSS variables"} + {activeTab === "preview"&& "Live component preview across breakpoints"} + {activeTab === "deploy" && "Build and deploy to any target"} + {activeTab === "status" && "System health across all domains"} +

+
+ + โ—‰ /status + +
+ + {/* Panel content */} +
+ {activeTab === "form" && } + {activeTab === "tokens" && } + {activeTab === "preview" && } + {activeTab === "deploy" && } + {activeTab === "status" && ( +
+

Status dashboard โ€” see /apps/web/src/app/status/page.tsx

+
+ )} +
+
+
+ ); +} diff --git a/apps/admin/src/components/panels/BrandFormPanel.tsx b/apps/admin/src/components/panels/BrandFormPanel.tsx new file mode 100644 index 00000000..f399716f --- /dev/null +++ b/apps/admin/src/components/panels/BrandFormPanel.tsx @@ -0,0 +1,172 @@ +"use client"; + +import { useAdminStore } from "@/lib/brandStore"; + +const COPY_VARIANTS = ["urgency", "exclusivity", "authority", "rebellion", "data"]; +const ANIMATION_PRESETS = ["smooth", "fast", "glitch", "static"] as const; + +export default function BrandFormPanel() { + const { draft, setDraftField } = useAdminStore(); + + return ( +
+
+ Brand Identity +
+ + {/* ID */} + + setDraftField("id", e.target.value)} + placeholder="stakeclaimbot" + className="admin-input" + /> + + + {/* Name */} + + setDraftField("name", e.target.value)} + placeholder="StakeClaimBot" + className="admin-input" + /> + + + {/* Domain */} + + setDraftField("domain", e.target.value)} + placeholder="stakeclaimbot.com" + className="admin-input" + /> + + + {/* Tagline */} + + setDraftField("tagline", e.target.value)} + placeholder="Automate Your Stake Claims" + className="admin-input" + /> + + + {/* Sub tagline */} + +