Files
ez-api/docs/feat/admin-panel-dashboard-feat/code.html
zenfun 8a52d58674 docs(admin): add dashboard feature design and mockup assets
Organize admin panel feature documentation into a dedicated directory
and include an interactive HTML mockup along with a reference
screenshot for the EZ-API Control Plane Dashboard.
2026-01-03 17:11:02 +08:00

466 lines
24 KiB
HTML

<!DOCTYPE html>
<html lang="en"><head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>EZ-API Control Plane Dashboard</title>
<script src="https://cdn.tailwindcss.com?plugins=forms,typography"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
tailwind.config = {
darkMode: "class",
theme: {
extend: {
colors: {
primary: "#3b82f6", // Bright blue for primary actions
"primary-dark": "#1d4ed8",
"accent": "#6366f1", // Indigo accent
"background-light": "#f3f4f6",
"background-dark": "#0f172a", // Very dark slate/blue
"surface-light": "#ffffff",
"surface-dark": "#1e293b", // Lighter slate for cards
"surface-darker": "#020617", // Almost black for sidebar
},
fontFamily: {
display: ["Inter", "sans-serif"],
body: ["Inter", "sans-serif"],
},
borderRadius: {
DEFAULT: "0.5rem",
'xl': '1rem',
'2xl': '1.5rem',
},
},
},
};
</script>
<style>
body {
font-family: 'Inter', sans-serif;
}::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #0f172a;
}
::-webkit-scrollbar-thumb {
background: #334155;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #475569;
}
.glass-effect {
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.05);
}
</style>
</head>
<body class="bg-background-light dark:bg-background-dark text-slate-800 dark:text-slate-200 transition-colors duration-300 dark h-screen flex overflow-hidden">
<aside class="w-64 bg-white dark:bg-surface-darker border-r border-slate-200 dark:border-slate-800 flex flex-col justify-between flex-shrink-0 z-20">
<div>
<div class="h-16 flex items-center px-6 border-b border-slate-200 dark:border-slate-800">
<div class="w-8 h-8 rounded bg-primary flex items-center justify-center mr-3 shadow-lg shadow-blue-500/30">
<span class="material-icons text-white text-sm">hub</span>
</div>
<div>
<h1 class="font-bold text-sm text-slate-900 dark:text-white leading-tight">EZ-API</h1>
<p class="text-xs text-slate-500 dark:text-slate-400">Control Plane</p>
</div>
</div>
<nav class="p-4 space-y-1">
<a class="flex items-center px-4 py-3 bg-primary/10 text-primary rounded-lg group transition-all" href="#">
<span class="material-icons mr-3 text-xl">dashboard</span>
<span class="font-medium text-sm">Dashboard</span>
</a>
<a class="flex items-center px-4 py-3 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-white rounded-lg group transition-all" href="#">
<span class="material-icons mr-3 text-xl group-hover:text-primary transition-colors">vpn_key</span>
<span class="font-medium text-sm">API Keys</span>
</a>
<a class="flex items-center px-4 py-3 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-white rounded-lg group transition-all" href="#">
<span class="material-icons mr-3 text-xl group-hover:text-primary transition-colors">bar_chart</span>
<span class="font-medium text-sm">Analytics</span>
</a>
<a class="flex items-center px-4 py-3 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-white rounded-lg group transition-all" href="#">
<span class="material-icons mr-3 text-xl group-hover:text-primary transition-colors">tune</span>
<span class="font-medium text-sm">Gateway Settings</span>
</a>
<a class="flex items-center px-4 py-3 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-white rounded-lg group transition-all" href="#">
<span class="material-icons mr-3 text-xl group-hover:text-primary transition-colors">terminal</span>
<span class="font-medium text-sm">Logs</span>
</a>
<a class="flex items-center px-4 py-3 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-white rounded-lg group transition-all" href="#">
<span class="material-icons mr-3 text-xl group-hover:text-primary transition-colors">credit_card</span>
<span class="font-medium text-sm">Billing</span>
</a>
</nav>
</div>
<div class="p-4 border-t border-slate-200 dark:border-slate-800 space-y-1">
<a class="flex items-center px-4 py-2 text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white text-sm transition-colors" href="#">
<span class="material-icons mr-3 text-lg">description</span>
Documentation
</a>
<a class="flex items-center px-4 py-2 text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white text-sm transition-colors mb-4" href="#">
<span class="material-icons mr-3 text-lg">headset_mic</span>
Support
</a>
<div class="flex items-center p-3 bg-slate-100 dark:bg-slate-800/50 rounded-xl border border-slate-200 dark:border-slate-700 mt-4">
<div class="relative">
<img alt="User Avatar" class="w-9 h-9 rounded-full object-cover border border-slate-300 dark:border-slate-600" src="https://lh3.googleusercontent.com/aida-public/AB6AXuDtjVsB0qfW3oChJxs05sru_BK-FSqC1sZwvdso3DjLfnr-iB_pgcmyOz4SwpGMOX_zCgSfdvamkjiU-5FUnUTdZqAFJQIrQClxRJ_OHrKDt33pe_ugSjHOI8_8drUr84EbXuQ7rBz_U9z-qEt9QnUOJ3D8Q4E1yBFA0LAv4RUzx0CAzTiOTxwjT00DLIPQb0VPJIofgFDdMIGxD7hc9JRWilp_rJD0xzWzMdtYH6gjv8crqZGaQvuymzNEgJa7PrUwi8yolMMNXcbk"/>
<div class="absolute bottom-0 right-0 w-2.5 h-2.5 bg-green-500 rounded-full border-2 border-white dark:border-slate-800"></div>
</div>
<div class="ml-3 flex-1 min-w-0">
<p class="text-xs font-medium text-slate-900 dark:text-white truncate">Admin User</p>
<p class="text-[10px] text-slate-500 dark:text-slate-400 truncate">admin@ez-api.io</p>
</div>
<button class="text-slate-400 hover:text-slate-600 dark:hover:text-white transition-colors">
<span class="material-icons text-sm">logout</span>
</button>
</div>
</div>
</aside>
<main class="flex-1 flex flex-col min-w-0 overflow-hidden bg-background-light dark:bg-background-dark relative">
<div class="absolute inset-0 z-0 opacity-[0.03] dark:opacity-[0.05] pointer-events-none" style="background-image: linear-gradient(#6366f1 1px, transparent 1px), linear-gradient(90deg, #6366f1 1px, transparent 1px); background-size: 40px 40px;">
</div>
<header class="h-16 flex items-center justify-between px-8 border-b border-slate-200 dark:border-slate-800 bg-white/80 dark:bg-background-dark/80 backdrop-blur-md z-10">
<div class="flex items-center">
<div class="inline-flex items-center px-3 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-600 dark:text-emerald-400 text-xs font-medium">
<span class="w-1.5 h-1.5 rounded-full bg-emerald-500 mr-2 animate-pulse"></span>
SYSTEM STATUS: NOMINAL
</div>
</div>
<div class="flex items-center space-x-6">
<div class="relative w-64">
<span class="material-icons absolute left-3 top-2.5 text-slate-400 text-sm">search</span>
<input class="w-full bg-slate-100 dark:bg-slate-800 border-none rounded-lg py-2 pl-10 pr-4 text-sm text-slate-800 dark:text-slate-200 placeholder-slate-400 focus:ring-2 focus:ring-primary" placeholder="Search resources..." type="text"/>
</div>
<div class="flex items-center space-x-4">
<button class="relative text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-white transition-colors">
<span class="material-icons">notifications</span>
<span class="absolute top-0 right-0 w-2 h-2 bg-red-500 rounded-full border-2 border-white dark:border-background-dark"></span>
</button>
<button class="text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-white transition-colors">
<span class="material-icons">help</span>
</button>
</div>
</div>
</header>
<div class="flex-1 overflow-auto p-8 z-10">
<div class="max-w-7xl mx-auto space-y-6">
<div class="flex items-end justify-between mb-8">
<div>
<h2 class="text-2xl font-bold text-slate-900 dark:text-white tracking-tight">System Performance</h2>
<p class="text-slate-500 dark:text-slate-400 mt-1 text-sm">Real-time metrics from EZ-API Gateway Cluster</p>
</div>
<div class="flex items-center bg-white dark:bg-surface-dark border border-slate-200 dark:border-slate-700 rounded-lg p-1">
<span class="text-xs font-medium text-slate-500 dark:text-slate-400 px-3">Time Range:</span>
<select class="bg-transparent border-none text-sm font-semibold text-slate-900 dark:text-white focus:ring-0 py-1 pl-0 pr-8 cursor-pointer">
<option>24H</option>
<option>7D</option>
<option>30D</option>
</select>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div class="bg-white dark:bg-surface-dark border border-slate-200 dark:border-slate-800 rounded-2xl p-5 shadow-sm hover:shadow-md transition-shadow relative overflow-hidden group">
<div class="absolute -right-6 -top-6 w-24 h-24 bg-blue-500/10 rounded-full group-hover:scale-110 transition-transform duration-500"></div>
<div class="flex justify-between items-start mb-4">
<div class="w-10 h-10 rounded-lg bg-blue-500/10 flex items-center justify-center text-blue-500">
<span class="material-icons">bolt</span>
</div>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-emerald-500/10 text-emerald-600 dark:text-emerald-400">
<span class="material-icons text-[10px] mr-1">trending_up</span> +12%
</span>
</div>
<h3 class="text-slate-500 dark:text-slate-400 text-sm font-medium">Requests Per Minute</h3>
<div class="mt-1 text-3xl font-bold text-slate-900 dark:text-white">747,000</div>
</div>
<div class="bg-white dark:bg-surface-dark border border-slate-200 dark:border-slate-800 rounded-2xl p-5 shadow-sm hover:shadow-md transition-shadow relative overflow-hidden group">
<div class="absolute -right-6 -top-6 w-24 h-24 bg-indigo-500/10 rounded-full group-hover:scale-110 transition-transform duration-500"></div>
<div class="flex justify-between items-start mb-4">
<div class="w-10 h-10 rounded-lg bg-indigo-500/10 flex items-center justify-center text-indigo-500">
<span class="material-icons">vpn_key</span>
</div>
</div>
<h3 class="text-slate-500 dark:text-slate-400 text-sm font-medium">Active Keys</h3>
<div class="mt-1 text-3xl font-bold text-slate-900 dark:text-white">2,350</div>
</div>
<div class="bg-white dark:bg-surface-dark border border-slate-200 dark:border-slate-800 rounded-2xl p-5 shadow-sm hover:shadow-md transition-shadow relative overflow-hidden group">
<div class="absolute -right-6 -top-6 w-24 h-24 bg-amber-500/10 rounded-full group-hover:scale-110 transition-transform duration-500"></div>
<div class="flex justify-between items-start mb-4">
<div class="w-10 h-10 rounded-lg bg-amber-500/10 flex items-center justify-center text-amber-500">
<span class="material-icons">token</span>
</div>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-rose-500/10 text-rose-600 dark:text-rose-400">
<span class="material-icons text-[10px] mr-1">trending_down</span> -1.1%
</span>
</div>
<h3 class="text-slate-500 dark:text-slate-400 text-sm font-medium">Consumed Tokens</h3>
<div class="mt-1 text-3xl font-bold text-slate-900 dark:text-white">892k</div>
</div>
<div class="bg-white dark:bg-surface-dark border border-slate-200 dark:border-slate-800 rounded-2xl p-5 shadow-sm hover:shadow-md transition-shadow relative overflow-hidden group">
<div class="absolute -right-6 -top-6 w-24 h-24 bg-rose-500/10 rounded-full group-hover:scale-110 transition-transform duration-500"></div>
<div class="flex justify-between items-start mb-4">
<div class="w-10 h-10 rounded-lg bg-rose-500/10 flex items-center justify-center text-rose-500">
<span class="material-icons">error_outline</span>
</div>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-emerald-500/10 text-emerald-600 dark:text-emerald-400">
<span class="material-icons text-[10px] mr-1">check</span> Stable
</span>
</div>
<h3 class="text-slate-500 dark:text-slate-400 text-sm font-medium">Error Rate</h3>
<div class="mt-1 text-3xl font-bold text-slate-900 dark:text-white">0.02%</div>
</div>
</div>
<a class="block bg-white dark:bg-surface-dark border border-slate-200 dark:border-slate-800 rounded-2xl p-5 shadow-sm hover:shadow-md hover:border-primary/40 transition-all group" href="#">
<div class="flex flex-col lg:flex-row items-center justify-between gap-4">
<div class="flex items-center space-x-4 w-full lg:w-auto">
<div class="w-10 h-10 rounded-lg bg-rose-500/10 flex items-center justify-center flex-shrink-0 text-rose-500">
<span class="material-icons">notifications_active</span>
</div>
<div>
<h3 class="text-slate-900 dark:text-white font-bold text-sm">Warnings &amp; Alerts</h3>
<p class="text-xs text-slate-500 dark:text-slate-400">2 active events require attention</p>
</div>
</div>
<div class="w-full lg:flex-1 lg:mx-8 grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex items-center space-x-3 bg-slate-50 dark:bg-slate-800/50 rounded-lg px-3 py-2 border border-slate-100 dark:border-slate-700/50">
<div class="w-1.5 h-1.5 rounded-full bg-rose-500 flex-shrink-0 shadow-[0_0_8px_rgba(244,63,94,0.6)] animate-pulse"></div>
<div class="min-w-0 flex-1">
<p class="text-xs font-medium text-slate-800 dark:text-slate-200 truncate">API Key quota exceeded for <span class="text-rose-500 dark:text-rose-400 font-mono">Enterprise_Client_A</span></p>
</div>
<span class="text-[10px] text-slate-400 whitespace-nowrap">42m ago</span>
</div>
<div class="flex items-center space-x-3 bg-slate-50 dark:bg-slate-800/50 rounded-lg px-3 py-2 border border-slate-100 dark:border-slate-700/50">
<div class="w-1.5 h-1.5 rounded-full bg-emerald-500 flex-shrink-0 shadow-[0_0_8px_rgba(16,185,129,0.6)]"></div>
<div class="min-w-0 flex-1">
<p class="text-xs font-medium text-slate-800 dark:text-slate-200 truncate">Database backup completed successfully</p>
</div>
<span class="text-[10px] text-slate-400 whitespace-nowrap">2h ago</span>
</div>
</div>
<div class="hidden lg:flex items-center text-slate-400 group-hover:text-primary transition-colors">
<span class="material-icons">arrow_forward</span>
</div>
</div>
</a>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div class="lg:col-span-2 bg-white dark:bg-surface-dark border border-slate-200 dark:border-slate-800 rounded-2xl p-6 shadow-sm">
<div class="flex items-center justify-between mb-6">
<div>
<h3 class="text-lg font-bold text-slate-900 dark:text-white">Traffic Volume</h3>
<p class="text-sm text-slate-500 dark:text-slate-400">Inbound requests over the last 24 hours</p>
</div>
<div class="text-right">
<div class="text-2xl font-bold text-slate-900 dark:text-white">1.2M</div>
<div class="text-xs font-medium text-emerald-500 flex items-center justify-end">
<span class="material-icons text-[14px] mr-0.5">arrow_upward</span> 8.9%
</div>
</div>
</div>
<div class="h-[350px] w-full relative">
<canvas id="trafficChart"></canvas>
</div>
<div class="mt-4 flex justify-between text-xs text-slate-400 dark:text-slate-500 px-2 font-mono">
<span>00:00</span>
<span>04:00</span>
<span>08:00</span>
<span>12:00</span>
<span>16:00</span>
<span>20:00</span>
<span>23:59</span>
</div>
</div>
<div class="space-y-6 flex flex-col h-full">
<div class="bg-white dark:bg-surface-dark border border-slate-200 dark:border-slate-800 rounded-2xl p-6 shadow-sm flex-1">
<h3 class="text-lg font-bold text-slate-900 dark:text-white mb-6">Top Models</h3>
<div class="space-y-5">
<div>
<div class="flex justify-between text-sm mb-1.5">
<span class="text-slate-700 dark:text-slate-300 font-medium">GPT-4-Turbo</span>
<span class="text-slate-500 dark:text-slate-400">45%</span>
</div>
<div class="w-full bg-slate-100 dark:bg-slate-700/50 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full" style="width: 45%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1.5">
<span class="text-slate-700 dark:text-slate-300 font-medium">Claude 3.5 Sonnet</span>
<span class="text-slate-500 dark:text-slate-400">32%</span>
</div>
<div class="w-full bg-slate-100 dark:bg-slate-700/50 rounded-full h-2">
<div class="bg-indigo-500 h-2 rounded-full" style="width: 32%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1.5">
<span class="text-slate-700 dark:text-slate-300 font-medium">Llama 3 70B</span>
<span class="text-slate-500 dark:text-slate-400">18%</span>
</div>
<div class="w-full bg-slate-100 dark:bg-slate-700/50 rounded-full h-2">
<div class="bg-violet-500 h-2 rounded-full" style="width: 18%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1.5">
<span class="text-slate-700 dark:text-slate-300 font-medium">Mistral Large</span>
<span class="text-slate-500 dark:text-slate-400">5%</span>
</div>
<div class="w-full bg-slate-100 dark:bg-slate-700/50 rounded-full h-2">
<div class="bg-cyan-500 h-2 rounded-full" style="width: 5%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1.5">
<span class="text-slate-700 dark:text-slate-300 font-medium">Gemini Pro</span>
<span class="text-slate-500 dark:text-slate-400">3%</span>
</div>
<div class="w-full bg-slate-100 dark:bg-slate-700/50 rounded-full h-2">
<div class="bg-teal-500 h-2 rounded-full" style="width: 3%"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<script>
document.addEventListener('DOMContentLoaded', function() {
const ctx = document.getElementById('trafficChart').getContext('2d');
// Check for dark mode to adjust chart colors
const isDarkMode = document.documentElement.classList.contains('dark') || true; // Defaulting true for preview
const gridColor = isDarkMode ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.05)';
const textColor = isDarkMode ? '#94a3b8' : '#64748b';
// Data Generation
const labels = ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00'];
// Generating somewhat realistic data patterns
const dataGPT4 = [45, 42, 35, 30, 45, 65, 85, 90, 88, 75, 60, 50];
const dataClaude = [32, 30, 25, 20, 35, 50, 60, 65, 62, 55, 45, 38];
const dataLlama = [18, 15, 12, 10, 20, 25, 30, 35, 32, 28, 22, 19];
const dataMistral = [5, 4, 3, 2, 6, 8, 10, 12, 11, 9, 7, 6];
const dataGemini = [3, 2, 2, 1, 4, 5, 7, 8, 7, 6, 5, 4];
new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [
{
label: 'GPT-4-Turbo',
data: dataGPT4,
backgroundColor: '#3b82f6', // blue-500
borderRadius: 4,
barPercentage: 0.6,
},
{
label: 'Claude 3.5',
data: dataClaude,
backgroundColor: '#6366f1', // indigo-500
borderRadius: 4,
barPercentage: 0.6,
},
{
label: 'Llama 3 70B',
data: dataLlama,
backgroundColor: '#8b5cf6', // violet-500
borderRadius: 4,
barPercentage: 0.6,
},
{
label: 'Mistral Large',
data: dataMistral,
backgroundColor: '#06b6d4', // cyan-500
borderRadius: 4,
barPercentage: 0.6,
},
{
label: 'Gemini Pro',
data: dataGemini,
backgroundColor: '#14b8a6', // teal-500
borderRadius: 4,
barPercentage: 0.6,
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'bottom', // Legend at bottom
labels: {
color: textColor,
usePointStyle: true,
pointStyle: 'circle',
padding: 20,
font: {
family: "'Inter', sans-serif",
size: 11
}
}
},
tooltip: {
mode: 'index',
intersect: false,
backgroundColor: isDarkMode ? '#1e293b' : '#ffffff',
titleColor: isDarkMode ? '#f8fafc' : '#0f172a',
bodyColor: isDarkMode ? '#cbd5e1' : '#475569',
borderColor: isDarkMode ? '#334155' : '#e2e8f0',
borderWidth: 1,
padding: 10,
cornerRadius: 8,
titleFont: { family: "'Inter', sans-serif", weight: '600' },
bodyFont: { family: "'Inter', sans-serif" }
}
},
scales: {
x: {
stacked: true,
grid: {
display: false,
drawBorder: false
},
ticks: {
color: textColor,
font: {
family: "'Inter', sans-serif",
size: 11
}
}
},
y: {
stacked: true,
grid: {
color: gridColor,
borderDash: [4, 4],
drawBorder: false
},
ticks: {
color: textColor,
font: {
family: "'Inter', sans-serif",
size: 11
},
callback: function(value) {
return value + 'k';
}
}
}
},
interaction: {
mode: 'nearest',
axis: 'x',
intersect: false
}
}
});
});
</script>
</body></html>