1059 lines
70 KiB
HTML
1059 lines
70 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8"/>
|
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
|
<title>Chart Board | Workspaces</title>
|
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap" rel="stylesheet"/>
|
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
|
<script>
|
|
tailwind.config = {
|
|
darkMode: "class",
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
"primary": "#000000",
|
|
"primary-container": "#131b2e",
|
|
"on-primary": "#ffffff",
|
|
"on-primary-container": "#7c839b",
|
|
"secondary": "#515f74",
|
|
"secondary-container": "#d5e3fc",
|
|
"on-secondary-container": "#57657a",
|
|
"surface": "#f7f9fb",
|
|
"surface-dim": "#d8dadc",
|
|
"surface-bright": "#f7f9fb",
|
|
"surface-container-lowest": "#ffffff",
|
|
"surface-container-low": "#f2f4f6",
|
|
"surface-container": "#eceef0",
|
|
"surface-container-high": "#e6e8ea",
|
|
"surface-container-highest": "#e0e3e5",
|
|
"on-surface": "#191c1e",
|
|
"on-surface-variant": "#45464d",
|
|
"outline": "#76777d",
|
|
"outline-variant": "#c6c6cd",
|
|
"inverse-surface": "#2d3133",
|
|
"inverse-on-surface": "#eff1f3",
|
|
"error": "#ba1a1a",
|
|
"error-container": "#ffdad6",
|
|
"on-error": "#ffffff",
|
|
"on-error-container": "#93000a",
|
|
"tertiary-container": "#271901",
|
|
"on-tertiary-container": "#98805d",
|
|
"background": "#f7f9fb",
|
|
"on-background": "#191c1e",
|
|
},
|
|
fontFamily: { "headline": ["Inter"], "body": ["Inter"], "label": ["Inter"] },
|
|
borderRadius: { "DEFAULT": "0.125rem", "sm": "0.25rem", "md": "0.375rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px" },
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style>
|
|
body { font-family: 'Inter', sans-serif; }
|
|
.material-symbols-outlined { font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
|
|
.material-symbols-outlined.filled { font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
|
|
|
|
/* Status Pillar */
|
|
.status-pillar { width: 3px; border-radius: 9999px; flex-shrink: 0; }
|
|
|
|
/* Glassmorphism */
|
|
.glass { background: rgba(255,255,255,0.82); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); }
|
|
|
|
/* Modal backdrop */
|
|
.modal-backdrop { background: rgba(19,27,46,0.35); backdrop-filter: blur(4px); }
|
|
|
|
/* Smooth transitions */
|
|
* { transition-property: background-color, border-color, color, opacity, transform; transition-timing-function: cubic-bezier(.4,0,.2,1); transition-duration: 150ms; }
|
|
|
|
/* Sidebar active */
|
|
.nav-active { background: #e6e8ea; color: #000; font-weight: 700; }
|
|
.nav-active .material-symbols-outlined { font-variation-settings: 'FILL' 1, 'wght' 600, 'GRAD' 0, 'opsz' 24; }
|
|
|
|
/* Tab underline active */
|
|
.tab-active { border-bottom: 2px solid #000; color: #000; font-weight: 700; }
|
|
|
|
/* Workspace card hover */
|
|
.ws-card:hover { transform: translateY(-2px); box-shadow: 0 8px 32px rgba(19,28,30,0.08); }
|
|
|
|
/* Role badge */
|
|
.role-admin { background: #131b2e; color: #fff; }
|
|
.role-editor { background: #d5e3fc; color: #57657a; }
|
|
.role-viewer { background: #e0e3e5; color: #45464d; }
|
|
|
|
/* Skeleton shimmer */
|
|
@keyframes shimmer { 0%{background-position:-400px 0} 100%{background-position:400px 0} }
|
|
.shimmer { background: linear-gradient(90deg, #e6e8ea 25%, #f2f4f6 50%, #e6e8ea 75%); background-size: 800px 100%; animation: shimmer 1.4s infinite; }
|
|
|
|
/* Toast slide-in */
|
|
@keyframes slideInRight { from{transform:translateX(100%);opacity:0} to{transform:translateX(0);opacity:1} }
|
|
.toast-enter { animation: slideInRight 0.3s ease forwards; }
|
|
|
|
/* Page fade-in */
|
|
@keyframes fadeUp { from{opacity:0;transform:translateY(12px)} to{opacity:1;transform:translateY(0)} }
|
|
.fade-up { animation: fadeUp 0.4s ease forwards; }
|
|
.fade-up-delay-1 { animation: fadeUp 0.4s 0.05s ease both; }
|
|
.fade-up-delay-2 { animation: fadeUp 0.4s 0.1s ease both; }
|
|
.fade-up-delay-3 { animation: fadeUp 0.4s 0.15s ease both; }
|
|
.fade-up-delay-4 { animation: fadeUp 0.4s 0.2s ease both; }
|
|
|
|
/* Ghost border fallback */
|
|
.ghost-border { border: 1px solid rgba(198,198,205,0.15); }
|
|
|
|
/* View toggle buttons */
|
|
.view-btn { background: transparent; }
|
|
.view-btn.active { background: #000; color: #fff; }
|
|
|
|
/* Dropdown */
|
|
.dropdown-menu { min-width: 180px; box-shadow: 0 8px 32px rgba(19,28,30,0.12); }
|
|
|
|
/* Invite badge color (pending) */
|
|
.badge-pending { background: rgba(255,218,0,0.12); color: #8a7000; }
|
|
.badge-accepted { background: rgba(0,150,80,0.10); color: #006838; }
|
|
.badge-expired { background: rgba(186,26,26,0.10); color: #ba1a1a; }
|
|
|
|
/* Progress bar */
|
|
.usage-bar { height: 4px; border-radius: 9999px; background: #e6e8ea; overflow: hidden; }
|
|
.usage-bar-fill { height: 100%; border-radius: 9999px; background: #000; }
|
|
|
|
/* Pill toggle */
|
|
.pill-toggle { display: flex; background: #e6e8ea; border-radius: 9999px; padding: 3px; }
|
|
.pill-toggle button { border-radius: 9999px; padding: 4px 16px; font-size: 12px; font-weight: 600; color: #45464d; border: none; cursor: pointer; background: transparent; }
|
|
.pill-toggle button.active { background: #000; color: #fff; }
|
|
|
|
/* Empty state */
|
|
.empty-icon { font-size: 3rem; color: #c6c6cd; }
|
|
|
|
/* Member row hover */
|
|
.member-row:hover { background: #f2f4f6; }
|
|
|
|
/* Danger section */
|
|
.danger-section { border: 1px solid rgba(186,26,26,0.12); }
|
|
</style>
|
|
</head>
|
|
<body class="bg-surface text-on-surface antialiased">
|
|
|
|
<!-- ═══════════════════════════════════════ TOPBAR ═══════════════════════════════════════ -->
|
|
<header class="fixed top-0 w-full z-50 glass shadow-[0_1px_0_rgba(198,198,205,0.4)] flex items-center justify-between px-6 h-14">
|
|
<div class="flex items-center gap-8">
|
|
<div class="flex items-center gap-2">
|
|
<div class="w-7 h-7 bg-primary rounded-sm flex items-center justify-center">
|
|
<span class="material-symbols-outlined text-on-primary text-sm" style="font-size:16px">bar_chart</span>
|
|
</div>
|
|
<span class="text-sm font-black tracking-tighter text-primary uppercase select-none">Chart Board</span>
|
|
</div>
|
|
<nav class="hidden md:flex items-center gap-1">
|
|
<a href="#" onclick="showTab('workspaces')" class="px-3 py-1.5 text-sm text-primary font-bold border-b-2 border-primary">Workspaces</a>
|
|
<a href="#" class="px-3 py-1.5 text-sm text-on-surface-variant hover:text-on-surface">Members</a>
|
|
<a href="#" class="px-3 py-1.5 text-sm text-on-surface-variant hover:text-on-surface">Settings</a>
|
|
</nav>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<!-- Toast trigger (demo) -->
|
|
<button onclick="showToast('success','Workspace synced successfully')" class="p-2 hover:bg-surface-container-high rounded-lg">
|
|
<span class="material-symbols-outlined text-on-surface-variant" style="font-size:20px">notifications</span>
|
|
</button>
|
|
<button class="p-2 hover:bg-surface-container-high rounded-lg">
|
|
<span class="material-symbols-outlined text-on-surface-variant" style="font-size:20px">help_outline</span>
|
|
</button>
|
|
<div class="w-7 h-7 rounded-full bg-primary-container flex items-center justify-center ml-1">
|
|
<span class="text-[10px] font-bold text-white">JD</span>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- ═══════════════════════════════════════ SIDEBAR ═══════════════════════════════════════ -->
|
|
<aside class="fixed left-0 top-14 h-[calc(100vh-3.5rem)] w-56 bg-surface-container-low flex flex-col py-4 gap-1 z-40">
|
|
<!-- Workspace switcher -->
|
|
<div class="px-3 mb-3">
|
|
<button onclick="toggleDropdown()" class="w-full flex items-center gap-2.5 p-2.5 hover:bg-surface-container-high rounded-lg group relative">
|
|
<div class="w-7 h-7 rounded-sm bg-primary flex items-center justify-center flex-shrink-0">
|
|
<span class="material-symbols-outlined text-on-primary" style="font-size:15px">account_tree</span>
|
|
</div>
|
|
<div class="text-left flex-1 min-w-0">
|
|
<p class="text-xs font-bold text-on-surface truncate">Project Alpha</p>
|
|
<p class="text-[10px] text-on-surface-variant">Main Workspace</p>
|
|
</div>
|
|
<span class="material-symbols-outlined text-on-surface-variant" style="font-size:16px">unfold_more</span>
|
|
</button>
|
|
<!-- Workspace dropdown -->
|
|
<div id="ws-dropdown" class="hidden absolute left-3 mt-1 w-48 bg-surface-container-lowest rounded-lg shadow-xl border border-outline-variant/30 z-50 overflow-hidden dropdown-menu">
|
|
<div class="p-2 border-b border-outline-variant/20">
|
|
<p class="text-[10px] text-on-surface-variant font-semibold uppercase tracking-wider px-2 mb-1">Your Workspaces</p>
|
|
<button onclick="switchWorkspace('Project Alpha')" class="w-full text-left px-2 py-2 text-xs font-semibold text-on-surface hover:bg-surface-container-high rounded flex items-center gap-2">
|
|
<div class="w-4 h-4 rounded-sm bg-primary flex items-center justify-center"><span class="material-symbols-outlined text-white" style="font-size:10px">check</span></div>
|
|
Project Alpha
|
|
</button>
|
|
<button onclick="switchWorkspace('Design Studio')" class="w-full text-left px-2 py-2 text-xs font-medium text-on-surface-variant hover:bg-surface-container-high rounded flex items-center gap-2">
|
|
<div class="w-4 h-4 rounded-sm bg-secondary-container flex items-center justify-center"><span class="material-symbols-outlined" style="font-size:10px;color:#57657a">palette</span></div>
|
|
Design Studio
|
|
</button>
|
|
<button onclick="switchWorkspace('Data Ops')" class="w-full text-left px-2 py-2 text-xs font-medium text-on-surface-variant hover:bg-surface-container-high rounded flex items-center gap-2">
|
|
<div class="w-4 h-4 rounded-sm bg-surface-container-high flex items-center justify-center"><span class="material-symbols-outlined" style="font-size:10px;color:#45464d">storage</span></div>
|
|
Data Ops
|
|
</button>
|
|
</div>
|
|
<div class="p-2">
|
|
<button onclick="openCreateModal()" class="w-full text-left px-2 py-2 text-xs font-semibold text-primary hover:bg-surface-container-high rounded flex items-center gap-2">
|
|
<span class="material-symbols-outlined" style="font-size:14px">add_circle</span>
|
|
New Workspace
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="flex-1 space-y-0.5 px-2">
|
|
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-xs font-semibold rounded-lg text-on-surface-variant hover:bg-surface-container-high">
|
|
<span class="material-symbols-outlined" style="font-size:18px">dashboard</span> Dashboard
|
|
</a>
|
|
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-xs font-semibold rounded-lg text-on-surface-variant hover:bg-surface-container-high">
|
|
<span class="material-symbols-outlined" style="font-size:18px">insights</span> Analytics
|
|
</a>
|
|
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-xs font-semibold rounded-lg text-on-surface-variant hover:bg-surface-container-high">
|
|
<span class="material-symbols-outlined" style="font-size:18px">database</span> Data Sources
|
|
</a>
|
|
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-xs font-semibold rounded-lg nav-active">
|
|
<span class="material-symbols-outlined" style="font-size:18px">workspaces</span> Workspaces
|
|
<span class="ml-auto text-[10px] bg-primary text-on-primary rounded-full px-1.5 py-0.5 font-bold">3</span>
|
|
</a>
|
|
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-xs font-semibold rounded-lg text-on-surface-variant hover:bg-surface-container-high">
|
|
<span class="material-symbols-outlined" style="font-size:18px">groups</span> Members
|
|
</a>
|
|
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-xs font-semibold rounded-lg text-on-surface-variant hover:bg-surface-container-high">
|
|
<span class="material-symbols-outlined" style="font-size:18px">assignment</span> Audit Logs
|
|
</a>
|
|
</nav>
|
|
|
|
<div class="px-2 mt-auto border-t border-outline-variant/20 pt-3 space-y-0.5">
|
|
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-xs font-semibold rounded-lg text-on-surface-variant hover:bg-surface-container-high">
|
|
<span class="material-symbols-outlined" style="font-size:18px">contact_support</span> Support
|
|
</a>
|
|
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-xs font-semibold rounded-lg text-on-surface-variant hover:bg-surface-container-high">
|
|
<span class="material-symbols-outlined" style="font-size:18px">logout</span> Sign Out
|
|
</a>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- ═══════════════════════════════════════ MAIN CONTENT ═══════════════════════════════════════ -->
|
|
<main class="ml-56 pt-14 min-h-screen bg-surface">
|
|
|
|
<!-- ─── TAB: WORKSPACES LIST ─── -->
|
|
<div id="view-workspaces" class="max-w-5xl mx-auto px-10 py-10">
|
|
<!-- Editorial Header -->
|
|
<header class="mb-10 fade-up flex items-end justify-between">
|
|
<div>
|
|
<p class="text-xs font-bold tracking-widest uppercase text-on-surface-variant mb-2">Organization</p>
|
|
<h1 class="text-[2.75rem] font-black tracking-[-0.025em] text-primary leading-none font-headline">Workspaces</h1>
|
|
<p class="text-on-surface-variant text-sm mt-2 max-w-xl">Organize your data assets, dashboards, and team access across isolated workspace environments.</p>
|
|
</div>
|
|
<button onclick="openCreateModal()" class="flex items-center gap-2 px-5 py-2.5 bg-primary text-on-primary text-sm font-bold rounded-md hover:bg-primary-container transition-all active:scale-95 shadow-sm flex-shrink-0">
|
|
<span class="material-symbols-outlined" style="font-size:18px">add</span>
|
|
New Workspace
|
|
</button>
|
|
</header>
|
|
|
|
<!-- Search + Filter Bar -->
|
|
<div class="fade-up-delay-1 flex items-center gap-3 mb-6">
|
|
<div class="flex-1 relative">
|
|
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-on-surface-variant" style="font-size:18px">search</span>
|
|
<input type="text" placeholder="Search workspaces…" oninput="filterWorkspaces(this.value)"
|
|
class="w-full bg-surface-container-highest border-none focus:ring-0 rounded-md pl-9 pr-4 py-2.5 text-sm text-on-surface placeholder-on-surface-variant focus:bg-surface-container-lowest focus:shadow-[0_0_0_1px_#000]"/>
|
|
</div>
|
|
<div class="pill-toggle">
|
|
<button class="active" onclick="setView('grid',this)">Grid</button>
|
|
<button onclick="setView('list',this)">List</button>
|
|
</div>
|
|
<div class="relative">
|
|
<button class="flex items-center gap-1.5 px-3 py-2.5 bg-surface-container-highest hover:bg-surface-container-high rounded-md text-sm font-semibold text-on-surface-variant">
|
|
<span class="material-symbols-outlined" style="font-size:16px">sort</span> Sort
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stats bar -->
|
|
<div class="fade-up-delay-1 grid grid-cols-4 gap-4 mb-8">
|
|
<div class="bg-surface-container-lowest p-4 rounded-lg ghost-border">
|
|
<p class="text-[10px] font-bold text-on-surface-variant uppercase tracking-wider">Total Workspaces</p>
|
|
<p class="text-2xl font-black text-primary mt-1">3</p>
|
|
</div>
|
|
<div class="bg-surface-container-lowest p-4 rounded-lg ghost-border">
|
|
<p class="text-[10px] font-bold text-on-surface-variant uppercase tracking-wider">Total Members</p>
|
|
<p class="text-2xl font-black text-primary mt-1">14</p>
|
|
</div>
|
|
<div class="bg-surface-container-lowest p-4 rounded-lg ghost-border">
|
|
<p class="text-[10px] font-bold text-on-surface-variant uppercase tracking-wider">Data Sources</p>
|
|
<p class="text-2xl font-black text-primary mt-1">7</p>
|
|
</div>
|
|
<div class="bg-surface-container-lowest p-4 rounded-lg ghost-border">
|
|
<p class="text-[10px] font-bold text-on-surface-variant uppercase tracking-wider">Dashboards</p>
|
|
<p class="text-2xl font-black text-primary mt-1">22</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Grid View -->
|
|
<div id="grid-view" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5" id="workspace-grid">
|
|
|
|
<!-- Workspace Card 1 — Active -->
|
|
<div class="ws-card bg-surface-container-lowest rounded-xl ghost-border overflow-hidden cursor-pointer fade-up-delay-2 group relative" onclick="openWorkspaceDetail('Project Alpha')">
|
|
<!-- Color accent top strip -->
|
|
<div class="h-1 bg-gradient-to-r from-primary to-primary-container w-full"></div>
|
|
<div class="p-5">
|
|
<div class="flex items-start justify-between mb-4">
|
|
<div class="w-10 h-10 rounded-lg bg-primary flex items-center justify-center flex-shrink-0">
|
|
<span class="material-symbols-outlined text-on-primary" style="font-size:20px">account_tree</span>
|
|
</div>
|
|
<div class="flex items-center gap-1.5">
|
|
<span class="inline-flex items-center gap-1 text-[10px] font-bold px-2 py-1 rounded-full bg-[rgba(0,150,80,0.10)] text-[#006838]">
|
|
<span class="w-1.5 h-1.5 rounded-full bg-[#006838] inline-block"></span> Active
|
|
</span>
|
|
<button onclick="event.stopPropagation(); showContextMenu(event,'ws1')" class="p-1 hover:bg-surface-container-high rounded opacity-0 group-hover:opacity-100">
|
|
<span class="material-symbols-outlined text-on-surface-variant" style="font-size:16px">more_vert</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<h3 class="font-bold text-sm text-on-surface mb-0.5">Project Alpha</h3>
|
|
<p class="text-[11px] text-on-surface-variant font-mono mb-3">chartboard.io/project-alpha</p>
|
|
<p class="text-xs text-on-surface-variant leading-relaxed mb-4 line-clamp-2">Strategic management workspace for high-level infrastructure planning and asset tracking.</p>
|
|
<div class="usage-bar mb-1.5">
|
|
<div class="usage-bar-fill" style="width: 68%"></div>
|
|
</div>
|
|
<p class="text-[10px] text-on-surface-variant mb-4">68% storage used · 3.4 GB / 5 GB</p>
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex -space-x-2">
|
|
<div class="w-6 h-6 rounded-full bg-primary border-2 border-white flex items-center justify-center"><span class="text-[8px] font-bold text-white">JD</span></div>
|
|
<div class="w-6 h-6 rounded-full bg-secondary border-2 border-white flex items-center justify-center"><span class="text-[8px] font-bold text-white">SR</span></div>
|
|
<div class="w-6 h-6 rounded-full bg-surface-container-high border-2 border-white flex items-center justify-center"><span class="text-[8px] font-bold text-on-surface-variant">+5</span></div>
|
|
</div>
|
|
<div class="flex items-center gap-3 text-[10px] text-on-surface-variant">
|
|
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined" style="font-size:12px">database</span> 3 sources</span>
|
|
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined" style="font-size:12px">bar_chart</span> 12 charts</span>
|
|
</div>
|
|
</div>
|
|
<div class="mt-3 pt-3 border-t border-outline-variant/20 flex items-center justify-between">
|
|
<span class="text-[10px] text-on-surface-variant">EST · Refresh 5m</span>
|
|
<span class="role-admin text-[10px] font-bold px-2 py-0.5 rounded-full">Admin</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Workspace Card 2 -->
|
|
<div class="ws-card bg-surface-container-lowest rounded-xl ghost-border overflow-hidden cursor-pointer fade-up-delay-3 group relative" onclick="openWorkspaceDetail('Design Studio')">
|
|
<div class="h-1 bg-gradient-to-r from-secondary to-secondary-container w-full"></div>
|
|
<div class="p-5">
|
|
<div class="flex items-start justify-between mb-4">
|
|
<div class="w-10 h-10 rounded-lg bg-secondary-container flex items-center justify-center flex-shrink-0">
|
|
<span class="material-symbols-outlined" style="font-size:20px;color:#57657a">palette</span>
|
|
</div>
|
|
<div class="flex items-center gap-1.5">
|
|
<span class="inline-flex items-center gap-1 text-[10px] font-bold px-2 py-1 rounded-full bg-[rgba(0,150,80,0.10)] text-[#006838]">
|
|
<span class="w-1.5 h-1.5 rounded-full bg-[#006838] inline-block"></span> Active
|
|
</span>
|
|
<button onclick="event.stopPropagation(); showContextMenu(event,'ws2')" class="p-1 hover:bg-surface-container-high rounded opacity-0 group-hover:opacity-100">
|
|
<span class="material-symbols-outlined text-on-surface-variant" style="font-size:16px">more_vert</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<h3 class="font-bold text-sm text-on-surface mb-0.5">Design Studio</h3>
|
|
<p class="text-[11px] text-on-surface-variant font-mono mb-3">chartboard.io/design-studio</p>
|
|
<p class="text-xs text-on-surface-variant leading-relaxed mb-4 line-clamp-2">Creative analytics for the UX/design team — tracking engagement metrics and user flows.</p>
|
|
<div class="usage-bar mb-1.5">
|
|
<div class="usage-bar-fill" style="width: 31%"></div>
|
|
</div>
|
|
<p class="text-[10px] text-on-surface-variant mb-4">31% storage used · 1.5 GB / 5 GB</p>
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex -space-x-2">
|
|
<div class="w-6 h-6 rounded-full bg-secondary border-2 border-white flex items-center justify-center"><span class="text-[8px] font-bold text-white">RL</span></div>
|
|
<div class="w-6 h-6 rounded-full bg-primary-container border-2 border-white flex items-center justify-center"><span class="text-[8px] font-bold text-white">KP</span></div>
|
|
<div class="w-6 h-6 rounded-full bg-surface-container-high border-2 border-white flex items-center justify-center"><span class="text-[8px] font-bold text-on-surface-variant">+2</span></div>
|
|
</div>
|
|
<div class="flex items-center gap-3 text-[10px] text-on-surface-variant">
|
|
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined" style="font-size:12px">database</span> 2 sources</span>
|
|
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined" style="font-size:12px">bar_chart</span> 7 charts</span>
|
|
</div>
|
|
</div>
|
|
<div class="mt-3 pt-3 border-t border-outline-variant/20 flex items-center justify-between">
|
|
<span class="text-[10px] text-on-surface-variant">PST · Refresh 15m</span>
|
|
<span class="role-editor text-[10px] font-bold px-2 py-0.5 rounded-full">Editor</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Workspace Card 3 — Archived state -->
|
|
<div class="ws-card bg-surface-container-lowest rounded-xl ghost-border overflow-hidden cursor-pointer fade-up-delay-4 group relative opacity-70" onclick="openWorkspaceDetail('Data Ops')">
|
|
<div class="h-1 bg-gradient-to-r from-surface-container-high to-surface-container w-full"></div>
|
|
<div class="p-5">
|
|
<div class="flex items-start justify-between mb-4">
|
|
<div class="w-10 h-10 rounded-lg bg-surface-container-high flex items-center justify-center flex-shrink-0">
|
|
<span class="material-symbols-outlined text-on-surface-variant" style="font-size:20px">storage</span>
|
|
</div>
|
|
<div class="flex items-center gap-1.5">
|
|
<span class="inline-flex items-center gap-1 text-[10px] font-bold px-2 py-1 rounded-full bg-surface-container-high text-on-surface-variant">
|
|
<span class="w-1.5 h-1.5 rounded-full bg-on-surface-variant inline-block"></span> Archived
|
|
</span>
|
|
<button onclick="event.stopPropagation(); showContextMenu(event,'ws3')" class="p-1 hover:bg-surface-container-high rounded opacity-0 group-hover:opacity-100">
|
|
<span class="material-symbols-outlined text-on-surface-variant" style="font-size:16px">more_vert</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<h3 class="font-bold text-sm text-on-surface mb-0.5">Data Ops</h3>
|
|
<p class="text-[11px] text-on-surface-variant font-mono mb-3">chartboard.io/data-ops</p>
|
|
<p class="text-xs text-on-surface-variant leading-relaxed mb-4 line-clamp-2">Legacy ETL pipeline monitoring. Archived — data retained for 30 days.</p>
|
|
<div class="usage-bar mb-1.5">
|
|
<div class="usage-bar-fill" style="width: 100%; background: #ba1a1a;"></div>
|
|
</div>
|
|
<p class="text-[10px] text-error mb-4">Purge in 12 days · Data retained</p>
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex -space-x-2">
|
|
<div class="w-6 h-6 rounded-full bg-surface-container-highest border-2 border-white flex items-center justify-center"><span class="text-[8px] font-bold text-on-surface-variant">MT</span></div>
|
|
</div>
|
|
<div class="flex items-center gap-3 text-[10px] text-on-surface-variant">
|
|
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined" style="font-size:12px">database</span> 2 sources</span>
|
|
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined" style="font-size:12px">bar_chart</span> 3 charts</span>
|
|
</div>
|
|
</div>
|
|
<div class="mt-3 pt-3 border-t border-outline-variant/20 flex items-center justify-between">
|
|
<span class="text-[10px] text-on-surface-variant">UTC · Archived</span>
|
|
<span class="role-viewer text-[10px] font-bold px-2 py-0.5 rounded-full">Viewer</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Create New Workspace — Empty CTA card -->
|
|
<div class="ws-card bg-surface-container-low rounded-xl border border-dashed border-outline-variant cursor-pointer fade-up-delay-4 flex flex-col items-center justify-center p-8 text-center hover:border-primary hover:bg-surface-container group" onclick="openCreateModal()">
|
|
<div class="w-12 h-12 rounded-full bg-surface-container-high flex items-center justify-center mb-3 group-hover:bg-primary transition-colors">
|
|
<span class="material-symbols-outlined text-on-surface-variant group-hover:text-on-primary" style="font-size:22px">add</span>
|
|
</div>
|
|
<p class="text-sm font-bold text-on-surface-variant group-hover:text-primary">New Workspace</p>
|
|
<p class="text-xs text-on-surface-variant mt-1">Isolate a new team or project</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- List View (hidden by default) -->
|
|
<div id="list-view" class="hidden space-y-2">
|
|
<!-- Header row -->
|
|
<div class="grid grid-cols-12 gap-4 px-4 py-2 text-[10px] font-bold text-on-surface-variant uppercase tracking-wider">
|
|
<div class="col-span-4">Workspace</div>
|
|
<div class="col-span-2">Status</div>
|
|
<div class="col-span-2">Members</div>
|
|
<div class="col-span-2">Role</div>
|
|
<div class="col-span-2 text-right">Actions</div>
|
|
</div>
|
|
<!-- Row 1 -->
|
|
<div class="member-row grid grid-cols-12 gap-4 px-4 py-3 bg-surface-container-lowest rounded-lg ghost-border items-center cursor-pointer" onclick="openWorkspaceDetail('Project Alpha')">
|
|
<div class="col-span-4 flex items-center gap-3">
|
|
<div class="status-pillar h-8 bg-[#006838]"></div>
|
|
<div class="w-8 h-8 rounded-sm bg-primary flex items-center justify-center"><span class="material-symbols-outlined text-on-primary" style="font-size:16px">account_tree</span></div>
|
|
<div>
|
|
<p class="text-sm font-bold text-on-surface">Project Alpha</p>
|
|
<p class="text-[10px] text-on-surface-variant font-mono">project-alpha</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-span-2"><span class="inline-flex items-center gap-1 text-[10px] font-bold px-2 py-1 rounded-full bg-[rgba(0,150,80,0.10)] text-[#006838]"><span class="w-1.5 h-1.5 rounded-full bg-[#006838] inline-block"></span>Active</span></div>
|
|
<div class="col-span-2 text-xs text-on-surface-variant font-semibold">7 members</div>
|
|
<div class="col-span-2"><span class="role-admin text-[10px] font-bold px-2 py-1 rounded-full">Admin</span></div>
|
|
<div class="col-span-2 flex justify-end gap-1">
|
|
<button onclick="event.stopPropagation();openWorkspaceDetail('Project Alpha')" class="p-1.5 hover:bg-surface-container-high rounded text-on-surface-variant"><span class="material-symbols-outlined" style="font-size:16px">settings</span></button>
|
|
<button onclick="event.stopPropagation();" class="p-1.5 hover:bg-surface-container-high rounded text-on-surface-variant"><span class="material-symbols-outlined" style="font-size:16px">more_vert</span></button>
|
|
</div>
|
|
</div>
|
|
<!-- Row 2 -->
|
|
<div class="member-row grid grid-cols-12 gap-4 px-4 py-3 bg-surface-container-lowest rounded-lg ghost-border items-center cursor-pointer" onclick="openWorkspaceDetail('Design Studio')">
|
|
<div class="col-span-4 flex items-center gap-3">
|
|
<div class="status-pillar h-8 bg-[#006838]"></div>
|
|
<div class="w-8 h-8 rounded-sm bg-secondary-container flex items-center justify-center"><span class="material-symbols-outlined" style="font-size:16px;color:#57657a">palette</span></div>
|
|
<div>
|
|
<p class="text-sm font-bold text-on-surface">Design Studio</p>
|
|
<p class="text-[10px] text-on-surface-variant font-mono">design-studio</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-span-2"><span class="inline-flex items-center gap-1 text-[10px] font-bold px-2 py-1 rounded-full bg-[rgba(0,150,80,0.10)] text-[#006838]"><span class="w-1.5 h-1.5 rounded-full bg-[#006838] inline-block"></span>Active</span></div>
|
|
<div class="col-span-2 text-xs text-on-surface-variant font-semibold">4 members</div>
|
|
<div class="col-span-2"><span class="role-editor text-[10px] font-bold px-2 py-1 rounded-full">Editor</span></div>
|
|
<div class="col-span-2 flex justify-end gap-1">
|
|
<button onclick="event.stopPropagation();openWorkspaceDetail('Design Studio')" class="p-1.5 hover:bg-surface-container-high rounded text-on-surface-variant"><span class="material-symbols-outlined" style="font-size:16px">settings</span></button>
|
|
<button onclick="event.stopPropagation();" class="p-1.5 hover:bg-surface-container-high rounded text-on-surface-variant"><span class="material-symbols-outlined" style="font-size:16px">more_vert</span></button>
|
|
</div>
|
|
</div>
|
|
<!-- Row 3 -->
|
|
<div class="member-row grid grid-cols-12 gap-4 px-4 py-3 bg-surface-container-lowest rounded-lg ghost-border items-center cursor-pointer opacity-60" onclick="openWorkspaceDetail('Data Ops')">
|
|
<div class="col-span-4 flex items-center gap-3">
|
|
<div class="status-pillar h-8 bg-on-surface-variant"></div>
|
|
<div class="w-8 h-8 rounded-sm bg-surface-container-high flex items-center justify-center"><span class="material-symbols-outlined text-on-surface-variant" style="font-size:16px">storage</span></div>
|
|
<div>
|
|
<p class="text-sm font-bold text-on-surface">Data Ops</p>
|
|
<p class="text-[10px] text-on-surface-variant font-mono">data-ops</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-span-2"><span class="inline-flex items-center gap-1 text-[10px] font-bold px-2 py-1 rounded-full bg-surface-container-high text-on-surface-variant"><span class="w-1.5 h-1.5 rounded-full bg-on-surface-variant inline-block"></span>Archived</span></div>
|
|
<div class="col-span-2 text-xs text-on-surface-variant font-semibold">1 member</div>
|
|
<div class="col-span-2"><span class="role-viewer text-[10px] font-bold px-2 py-1 rounded-full">Viewer</span></div>
|
|
<div class="col-span-2 flex justify-end gap-1">
|
|
<button class="p-1.5 hover:bg-surface-container-high rounded text-on-surface-variant"><span class="material-symbols-outlined" style="font-size:16px">settings</span></button>
|
|
<button class="p-1.5 hover:bg-surface-container-high rounded text-on-surface-variant"><span class="material-symbols-outlined" style="font-size:16px">more_vert</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- ═══════════════════════════════════════ WORKSPACE DETAIL DRAWER ═══════════════════════════════════════ -->
|
|
<div id="detail-drawer" class="fixed inset-0 z-50 hidden">
|
|
<div class="modal-backdrop absolute inset-0" onclick="closeDetailDrawer()"></div>
|
|
<div class="absolute right-0 top-0 h-full w-[680px] bg-surface flex flex-col shadow-2xl overflow-hidden">
|
|
<!-- Drawer header -->
|
|
<div class="flex items-center justify-between px-8 py-5 border-b border-outline-variant/20 flex-shrink-0">
|
|
<div class="flex items-center gap-3">
|
|
<div class="w-9 h-9 rounded-lg bg-primary flex items-center justify-center">
|
|
<span class="material-symbols-outlined text-on-primary" style="font-size:18px">account_tree</span>
|
|
</div>
|
|
<div>
|
|
<h2 id="drawer-title" class="text-lg font-black text-primary tracking-tight">Project Alpha</h2>
|
|
<p class="text-[11px] text-on-surface-variant font-mono">chartboard.io/project-alpha</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<button onclick="openCreateModal()" class="px-3 py-1.5 bg-surface-container-high hover:bg-surface-container rounded-md text-xs font-bold text-on-surface">Edit Settings</button>
|
|
<button onclick="closeDetailDrawer()" class="p-2 hover:bg-surface-container-high rounded-lg">
|
|
<span class="material-symbols-outlined text-on-surface-variant" style="font-size:20px">close</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tabs -->
|
|
<div class="flex items-center gap-0 px-8 border-b border-outline-variant/20 flex-shrink-0">
|
|
<button onclick="switchDrawerTab('overview')" id="dtab-overview" class="px-4 py-3 text-xs font-semibold tab-active">Overview</button>
|
|
<button onclick="switchDrawerTab('members')" id="dtab-members" class="px-4 py-3 text-xs font-semibold text-on-surface-variant hover:text-on-surface border-b-2 border-transparent">Members</button>
|
|
<button onclick="switchDrawerTab('invitations')" id="dtab-invitations" class="px-4 py-3 text-xs font-semibold text-on-surface-variant hover:text-on-surface border-b-2 border-transparent">Invitations <span class="ml-1 bg-secondary-container text-on-secondary-container text-[9px] font-bold px-1.5 py-0.5 rounded-full">2</span></button>
|
|
<button onclick="switchDrawerTab('danger')" id="dtab-danger" class="px-4 py-3 text-xs font-semibold text-error hover:text-error border-b-2 border-transparent">Danger Zone</button>
|
|
</div>
|
|
|
|
<!-- Drawer body -->
|
|
<div class="flex-1 overflow-y-auto">
|
|
|
|
<!-- ── Tab: Overview ── -->
|
|
<div id="dpanel-overview" class="p-8 space-y-6">
|
|
<!-- Quick stats -->
|
|
<div class="grid grid-cols-3 gap-4">
|
|
<div class="bg-surface-container-low p-4 rounded-lg">
|
|
<p class="text-[10px] font-bold text-on-surface-variant uppercase tracking-wider">Data Sources</p>
|
|
<p class="text-2xl font-black text-primary mt-1">3</p>
|
|
<p class="text-[10px] text-on-surface-variant mt-0.5">MySQL, PostgreSQL, REST</p>
|
|
</div>
|
|
<div class="bg-surface-container-low p-4 rounded-lg">
|
|
<p class="text-[10px] font-bold text-on-surface-variant uppercase tracking-wider">Dashboards</p>
|
|
<p class="text-2xl font-black text-primary mt-1">8</p>
|
|
<p class="text-[10px] text-on-surface-variant mt-0.5">3 shared publicly</p>
|
|
</div>
|
|
<div class="bg-surface-container-low p-4 rounded-lg">
|
|
<p class="text-[10px] font-bold text-on-surface-variant uppercase tracking-wider">Alerts Active</p>
|
|
<p class="text-2xl font-black text-error mt-1">2</p>
|
|
<p class="text-[10px] text-on-surface-variant mt-0.5">1 triggered today</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- General settings form -->
|
|
<div>
|
|
<h3 class="text-xs font-black uppercase tracking-wider text-on-surface-variant mb-4">General Identity</h3>
|
|
<div class="bg-surface-container-low rounded-xl p-6 space-y-5">
|
|
<div class="space-y-1.5">
|
|
<label class="block text-[10px] font-bold uppercase tracking-wider text-on-surface-variant">Workspace Name</label>
|
|
<input type="text" value="Project Alpha" class="w-full bg-surface-container-highest border-none focus:ring-0 rounded-md py-2.5 px-3 text-sm text-on-surface font-medium focus:bg-surface-container-lowest focus:shadow-[0_0_0_1px_#000]"/>
|
|
</div>
|
|
<div class="space-y-1.5">
|
|
<label class="block text-[10px] font-bold uppercase tracking-wider text-on-surface-variant">Workspace Slug</label>
|
|
<div class="flex items-center bg-surface-container-highest rounded-md overflow-hidden focus-within:bg-surface-container-lowest focus-within:shadow-[0_0_0_1px_#000]">
|
|
<span class="pl-3 text-xs text-on-surface-variant select-none">chartboard.io/</span>
|
|
<input type="text" value="project-alpha" class="flex-1 bg-transparent border-none focus:ring-0 py-2.5 px-1 text-sm text-on-surface font-medium"/>
|
|
</div>
|
|
<p class="text-[10px] text-on-surface-variant">Used in public share links and API endpoints.</p>
|
|
</div>
|
|
<div class="space-y-1.5">
|
|
<label class="block text-[10px] font-bold uppercase tracking-wider text-on-surface-variant">Description</label>
|
|
<textarea rows="2" class="w-full bg-surface-container-highest border-none focus:ring-0 rounded-md py-2.5 px-3 text-sm text-on-surface font-medium focus:bg-surface-container-lowest focus:shadow-[0_0_0_1px_#000]">Strategic management workspace for high-level infrastructure planning and asset tracking.</textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Operations -->
|
|
<div>
|
|
<h3 class="text-xs font-black uppercase tracking-wider text-on-surface-variant mb-4">Operations</h3>
|
|
<div class="bg-surface-container-low rounded-xl p-6 space-y-5">
|
|
<div class="space-y-1.5">
|
|
<label class="block text-[10px] font-bold uppercase tracking-wider text-on-surface-variant">System Timezone</label>
|
|
<div class="relative">
|
|
<select class="w-full appearance-none bg-surface-container-highest border-none focus:ring-0 rounded-md py-2.5 px-3 text-sm text-on-surface font-medium cursor-pointer">
|
|
<option>UTC (Coordinated Universal Time)</option>
|
|
<option selected>EST (Eastern Standard Time)</option>
|
|
<option>PST (Pacific Standard Time)</option>
|
|
<option>CET (Central European Time)</option>
|
|
<option>IST (India Standard Time)</option>
|
|
</select>
|
|
<span class="material-symbols-outlined absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none text-on-surface-variant" style="font-size:18px">expand_more</span>
|
|
</div>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-[10px] font-bold uppercase tracking-wider text-on-surface-variant">Default Refresh Rate</label>
|
|
<div class="grid grid-cols-4 gap-2">
|
|
<label class="relative flex items-center justify-center py-3 bg-surface-container-highest rounded-md cursor-pointer hover:bg-surface-container-high text-sm font-bold">
|
|
<input type="radio" name="refresh2" class="sr-only peer"/>
|
|
<div class="peer-checked:bg-primary absolute inset-0 rounded-md transition-colors"></div>
|
|
<span class="relative peer-checked:text-on-primary">1m</span>
|
|
</label>
|
|
<label class="relative flex items-center justify-center py-3 bg-surface-container-highest rounded-md cursor-pointer hover:bg-surface-container-high text-sm font-bold">
|
|
<input type="radio" name="refresh2" checked class="sr-only peer"/>
|
|
<div class="peer-checked:bg-primary absolute inset-0 rounded-md transition-colors"></div>
|
|
<span class="relative peer-checked:text-on-primary">5m</span>
|
|
</label>
|
|
<label class="relative flex items-center justify-center py-3 bg-surface-container-highest rounded-md cursor-pointer hover:bg-surface-container-high text-sm font-bold">
|
|
<input type="radio" name="refresh2" class="sr-only peer"/>
|
|
<div class="peer-checked:bg-primary absolute inset-0 rounded-md transition-colors"></div>
|
|
<span class="relative peer-checked:text-on-primary">15m</span>
|
|
</label>
|
|
<label class="relative flex items-center justify-center py-3 bg-surface-container-highest rounded-md cursor-pointer hover:bg-surface-container-high text-sm font-bold">
|
|
<input type="radio" name="refresh2" class="sr-only peer"/>
|
|
<div class="peer-checked:bg-primary absolute inset-0 rounded-md transition-colors"></div>
|
|
<span class="relative peer-checked:text-on-primary">1h</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Save -->
|
|
<div class="flex justify-end gap-3 pt-2">
|
|
<button class="px-6 py-2.5 text-sm font-bold text-on-surface-variant hover:bg-surface-container-high rounded-md">Discard</button>
|
|
<button onclick="showToast('success','Workspace settings saved')" class="px-7 py-2.5 bg-primary text-on-primary text-sm font-bold rounded-md active:scale-95">Save Changes</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Tab: Members ── -->
|
|
<div id="dpanel-members" class="hidden p-8 space-y-6">
|
|
<!-- Invite bar -->
|
|
<div class="bg-surface-container-low rounded-xl p-5 space-y-3">
|
|
<h3 class="text-xs font-black uppercase tracking-wider text-on-surface-variant">Invite Member</h3>
|
|
<div class="flex gap-3">
|
|
<input type="email" placeholder="colleague@company.com" class="flex-1 bg-surface-container-highest border-none focus:ring-0 rounded-md py-2.5 px-3 text-sm focus:bg-surface-container-lowest focus:shadow-[0_0_0_1px_#000]"/>
|
|
<div class="relative">
|
|
<select class="appearance-none bg-surface-container-highest border-none focus:ring-0 rounded-md py-2.5 pl-3 pr-8 text-sm font-medium cursor-pointer">
|
|
<option>Admin</option>
|
|
<option selected>Editor</option>
|
|
<option>Viewer</option>
|
|
</select>
|
|
<span class="material-symbols-outlined absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none text-on-surface-variant" style="font-size:16px">expand_more</span>
|
|
</div>
|
|
<button onclick="showToast('success','Invitation sent!')" class="px-4 py-2.5 bg-primary text-on-primary text-sm font-bold rounded-md active:scale-95 flex-shrink-0">Invite</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Members list -->
|
|
<div>
|
|
<div class="flex items-center justify-between mb-3">
|
|
<h3 class="text-xs font-black uppercase tracking-wider text-on-surface-variant">Members (7)</h3>
|
|
<input type="text" placeholder="Filter members…" class="bg-surface-container-highest border-none focus:ring-0 rounded-md py-1.5 px-3 text-xs w-40"/>
|
|
</div>
|
|
<div class="space-y-1">
|
|
<!-- Member row template -->
|
|
<div class="member-row flex items-center gap-4 px-3 py-3 rounded-lg">
|
|
<div class="w-8 h-8 rounded-full bg-primary flex items-center justify-center flex-shrink-0"><span class="text-[10px] font-bold text-white">JD</span></div>
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-semibold text-on-surface">John Doe <span class="text-[10px] text-on-surface-variant font-normal">(you)</span></p>
|
|
<p class="text-[10px] text-on-surface-variant">john@acme.com · Joined Mar 2025</p>
|
|
</div>
|
|
<span class="role-admin text-[10px] font-bold px-2 py-1 rounded-full">Admin</span>
|
|
<button class="p-1 hover:bg-surface-container-high rounded text-on-surface-variant opacity-40 cursor-not-allowed"><span class="material-symbols-outlined" style="font-size:16px">more_vert</span></button>
|
|
</div>
|
|
<div class="member-row flex items-center gap-4 px-3 py-3 rounded-lg">
|
|
<div class="w-8 h-8 rounded-full bg-secondary flex items-center justify-center flex-shrink-0"><span class="text-[10px] font-bold text-white">SR</span></div>
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-semibold text-on-surface">Sarah Robinson</p>
|
|
<p class="text-[10px] text-on-surface-variant">sarah@acme.com · Joined Jan 2025</p>
|
|
</div>
|
|
<div class="relative">
|
|
<select class="appearance-none bg-surface-container-highest border-none focus:ring-0 rounded-md py-1 pl-2 pr-6 text-[10px] font-bold cursor-pointer" style="color:#57657a;background:#d5e3fc">
|
|
<option>Admin</option>
|
|
<option selected>Editor</option>
|
|
<option>Viewer</option>
|
|
</select>
|
|
<span class="material-symbols-outlined absolute right-1 top-1/2 -translate-y-1/2 pointer-events-none" style="font-size:12px;color:#57657a">expand_more</span>
|
|
</div>
|
|
<button onclick="showToast('error','Member removed from workspace')" class="p-1 hover:bg-error-container rounded text-on-surface-variant hover:text-error"><span class="material-symbols-outlined" style="font-size:16px">person_remove</span></button>
|
|
</div>
|
|
<div class="member-row flex items-center gap-4 px-3 py-3 rounded-lg">
|
|
<div class="w-8 h-8 rounded-full bg-primary-container flex items-center justify-center flex-shrink-0"><span class="text-[10px] font-bold text-white">KP</span></div>
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-semibold text-on-surface">Kevin Park</p>
|
|
<p class="text-[10px] text-on-surface-variant">kp@acme.com · Joined Feb 2025</p>
|
|
</div>
|
|
<div class="relative">
|
|
<select class="appearance-none border-none focus:ring-0 rounded-md py-1 pl-2 pr-6 text-[10px] font-bold cursor-pointer" style="color:#45464d;background:#e0e3e5">
|
|
<option>Admin</option>
|
|
<option>Editor</option>
|
|
<option selected>Viewer</option>
|
|
</select>
|
|
<span class="material-symbols-outlined absolute right-1 top-1/2 -translate-y-1/2 pointer-events-none" style="font-size:12px;color:#45464d">expand_more</span>
|
|
</div>
|
|
<button onclick="showToast('error','Member removed from workspace')" class="p-1 hover:bg-error-container rounded text-on-surface-variant hover:text-error"><span class="material-symbols-outlined" style="font-size:16px">person_remove</span></button>
|
|
</div>
|
|
<div class="member-row flex items-center gap-4 px-3 py-3 rounded-lg">
|
|
<div class="w-8 h-8 rounded-full bg-surface-container-highest flex items-center justify-center flex-shrink-0"><span class="text-[10px] font-bold text-on-surface-variant">MT</span></div>
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-semibold text-on-surface">Maya Torres</p>
|
|
<p class="text-[10px] text-on-surface-variant">maya@acme.com · Joined Apr 2025</p>
|
|
</div>
|
|
<div class="relative">
|
|
<select class="appearance-none border-none focus:ring-0 rounded-md py-1 pl-2 pr-6 text-[10px] font-bold cursor-pointer" style="color:#57657a;background:#d5e3fc">
|
|
<option>Admin</option>
|
|
<option selected>Editor</option>
|
|
<option>Viewer</option>
|
|
</select>
|
|
<span class="material-symbols-outlined absolute right-1 top-1/2 -translate-y-1/2 pointer-events-none" style="font-size:12px;color:#57657a">expand_more</span>
|
|
</div>
|
|
<button onclick="showToast('error','Member removed from workspace')" class="p-1 hover:bg-error-container rounded text-on-surface-variant hover:text-error"><span class="material-symbols-outlined" style="font-size:16px">person_remove</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Tab: Invitations ── -->
|
|
<div id="dpanel-invitations" class="hidden p-8 space-y-4">
|
|
<h3 class="text-xs font-black uppercase tracking-wider text-on-surface-variant">Pending Invitations (2)</h3>
|
|
<div class="space-y-2">
|
|
<!-- Pending invite -->
|
|
<div class="flex items-center gap-4 px-4 py-3.5 bg-surface-container-lowest rounded-lg ghost-border">
|
|
<div class="status-pillar h-8 bg-[#8a7000]"></div>
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-semibold text-on-surface">alex.nguyen@acme.com</p>
|
|
<p class="text-[10px] text-on-surface-variant">Invited by John Doe · Expires in 36h</p>
|
|
</div>
|
|
<span class="role-editor text-[10px] font-bold px-2 py-1 rounded-full">Editor</span>
|
|
<span class="badge-pending text-[10px] font-bold px-2 py-1 rounded-full">Pending</span>
|
|
<button onclick="showToast('success','Invitation cancelled')" class="p-1 hover:bg-error-container rounded text-on-surface-variant hover:text-error"><span class="material-symbols-outlined" style="font-size:16px">cancel</span></button>
|
|
</div>
|
|
<!-- Another pending -->
|
|
<div class="flex items-center gap-4 px-4 py-3.5 bg-surface-container-lowest rounded-lg ghost-border">
|
|
<div class="status-pillar h-8 bg-[#8a7000]"></div>
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-semibold text-on-surface">priya.m@contractor.io</p>
|
|
<p class="text-[10px] text-on-surface-variant">Invited by Sarah Robinson · Expires in 12h</p>
|
|
</div>
|
|
<span class="role-viewer text-[10px] font-bold px-2 py-1 rounded-full">Viewer</span>
|
|
<span class="badge-pending text-[10px] font-bold px-2 py-1 rounded-full">Pending</span>
|
|
<button onclick="showToast('success','Invitation cancelled')" class="p-1 hover:bg-error-container rounded text-on-surface-variant hover:text-error"><span class="material-symbols-outlined" style="font-size:16px">cancel</span></button>
|
|
</div>
|
|
<!-- Accepted (historical) -->
|
|
<div class="flex items-center gap-4 px-4 py-3.5 bg-surface-container-lowest rounded-lg ghost-border opacity-60">
|
|
<div class="status-pillar h-8 bg-[#006838]"></div>
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-semibold text-on-surface">kevin@acme.com</p>
|
|
<p class="text-[10px] text-on-surface-variant">Accepted 2 days ago</p>
|
|
</div>
|
|
<span class="role-viewer text-[10px] font-bold px-2 py-1 rounded-full">Viewer</span>
|
|
<span class="badge-accepted text-[10px] font-bold px-2 py-1 rounded-full">Accepted</span>
|
|
<div class="w-6"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Tab: Danger Zone ── -->
|
|
<div id="dpanel-danger" class="hidden p-8 space-y-4">
|
|
<div class="bg-inverse-surface rounded-xl p-5 flex items-start gap-4">
|
|
<span class="material-symbols-outlined text-error flex-shrink-0" style="font-size:22px">warning</span>
|
|
<div>
|
|
<p class="text-sm font-bold text-inverse-on-surface">Danger Zone — Irreversible Actions</p>
|
|
<p class="text-xs text-inverse-on-surface/70 mt-0.5">These actions affect the lifecycle of your workspace. They cannot be undone. Proceed with extreme caution.</p>
|
|
</div>
|
|
</div>
|
|
<!-- Archive -->
|
|
<div class="danger-section rounded-xl p-6 bg-error-container/10 space-y-2">
|
|
<div class="flex items-start justify-between gap-6">
|
|
<div>
|
|
<h3 class="text-sm font-bold text-on-surface">Archive Workspace</h3>
|
|
<p class="text-xs text-on-surface-variant mt-1 leading-relaxed">Stops all billing and background sync jobs. All data is retained in a read-only state for 30 days before permanent deletion. Users will lose write access immediately.</p>
|
|
<p class="text-[10px] text-on-surface-variant mt-2 font-mono bg-surface-container-highest px-2 py-1 rounded inline-block">Soft-delete: workspace.status = 'archived'</p>
|
|
</div>
|
|
<button onclick="showToast('error','Workspace archived. All jobs stopped.')" class="flex-shrink-0 px-5 py-2 bg-error text-on-error text-xs font-bold uppercase tracking-widest rounded-md hover:brightness-110 active:scale-95">Archive</button>
|
|
</div>
|
|
</div>
|
|
<!-- Transfer ownership -->
|
|
<div class="danger-section rounded-xl p-6 bg-surface-container-low space-y-4">
|
|
<div>
|
|
<h3 class="text-sm font-bold text-on-surface">Transfer Ownership</h3>
|
|
<p class="text-xs text-on-surface-variant mt-1 leading-relaxed">Transfer full admin ownership to another workspace admin. You will be downgraded to Editor.</p>
|
|
</div>
|
|
<div class="flex gap-3">
|
|
<div class="relative flex-1">
|
|
<select class="w-full appearance-none bg-surface-container-highest border-none focus:ring-0 rounded-md py-2.5 px-3 text-sm cursor-pointer">
|
|
<option>Select new owner…</option>
|
|
<option>Sarah Robinson (Editor)</option>
|
|
<option>Kevin Park (Viewer)</option>
|
|
</select>
|
|
<span class="material-symbols-outlined absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none text-on-surface-variant" style="font-size:18px">expand_more</span>
|
|
</div>
|
|
<button onclick="showToast('success','Ownership transfer request sent.')" class="px-5 py-2.5 border border-primary text-primary text-xs font-bold rounded-md hover:bg-surface-container-high active:scale-95">Transfer</button>
|
|
</div>
|
|
</div>
|
|
<!-- Delete permanently -->
|
|
<div class="danger-section rounded-xl p-6 bg-error-container/20 space-y-2">
|
|
<div class="flex items-start justify-between gap-6">
|
|
<div>
|
|
<h3 class="text-sm font-bold text-error">Delete Workspace Permanently</h3>
|
|
<p class="text-xs text-on-surface-variant mt-1 leading-relaxed">Immediately and permanently delete this workspace, all data sources, charts, dashboards, and member associations. <strong>This cannot be undone.</strong></p>
|
|
</div>
|
|
<button onclick="confirmDelete()" class="flex-shrink-0 px-5 py-2 border border-error text-error text-xs font-bold uppercase tracking-widest rounded-md hover:bg-error hover:text-on-error active:scale-95">Delete</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══════════════════════════════════════ CREATE WORKSPACE MODAL ═══════════════════════════════════════ -->
|
|
<div id="create-modal" class="fixed inset-0 z-50 hidden flex items-center justify-center">
|
|
<div class="modal-backdrop absolute inset-0" onclick="closeCreateModal()"></div>
|
|
<div class="relative glass rounded-2xl shadow-2xl w-full max-w-lg mx-4 overflow-hidden">
|
|
<!-- Modal header -->
|
|
<div class="flex items-center justify-between px-7 py-5 border-b border-outline-variant/20">
|
|
<div>
|
|
<h2 class="text-lg font-black text-primary tracking-tight">Create Workspace</h2>
|
|
<p class="text-xs text-on-surface-variant mt-0.5">Set up a new isolated data environment for your team.</p>
|
|
</div>
|
|
<button onclick="closeCreateModal()" class="p-2 hover:bg-surface-container-high rounded-lg">
|
|
<span class="material-symbols-outlined text-on-surface-variant" style="font-size:20px">close</span>
|
|
</button>
|
|
</div>
|
|
<!-- Step indicator -->
|
|
<div class="flex items-center px-7 py-3 bg-surface-container-low gap-0">
|
|
<div class="flex items-center gap-2">
|
|
<div id="step-dot-1" class="w-5 h-5 rounded-full bg-primary flex items-center justify-center"><span class="text-[9px] font-bold text-white">1</span></div>
|
|
<span class="text-[10px] font-bold text-primary">Identity</span>
|
|
</div>
|
|
<div class="flex-1 h-px bg-outline-variant/40 mx-3"></div>
|
|
<div class="flex items-center gap-2">
|
|
<div id="step-dot-2" class="w-5 h-5 rounded-full bg-surface-container-high flex items-center justify-center"><span class="text-[9px] font-semibold text-on-surface-variant">2</span></div>
|
|
<span id="step-label-2" class="text-[10px] font-semibold text-on-surface-variant">Operations</span>
|
|
</div>
|
|
<div class="flex-1 h-px bg-outline-variant/40 mx-3"></div>
|
|
<div class="flex items-center gap-2">
|
|
<div id="step-dot-3" class="w-5 h-5 rounded-full bg-surface-container-high flex items-center justify-center"><span class="text-[9px] font-semibold text-on-surface-variant">3</span></div>
|
|
<span id="step-label-3" class="text-[10px] font-semibold text-on-surface-variant">Invite</span>
|
|
</div>
|
|
</div>
|
|
<!-- Modal body -->
|
|
<div class="px-7 py-6 space-y-5" id="modal-step-1">
|
|
<div class="space-y-1.5">
|
|
<label class="block text-[10px] font-bold uppercase tracking-wider text-on-surface-variant">Workspace Name <span class="text-error">*</span></label>
|
|
<input type="text" placeholder="e.g. Growth Analytics" oninput="autoSlug(this.value)" class="w-full bg-surface-container-highest border-none focus:ring-0 rounded-md py-2.5 px-3 text-sm text-on-surface focus:bg-surface-container-lowest focus:shadow-[0_0_0_1px_#000]"/>
|
|
</div>
|
|
<div class="space-y-1.5">
|
|
<label class="block text-[10px] font-bold uppercase tracking-wider text-on-surface-variant">Slug</label>
|
|
<div class="flex items-center bg-surface-container-highest rounded-md overflow-hidden focus-within:bg-surface-container-lowest focus-within:shadow-[0_0_0_1px_#000]">
|
|
<span class="pl-3 text-xs text-on-surface-variant select-none flex-shrink-0">chartboard.io/</span>
|
|
<input id="slug-input" type="text" placeholder="growth-analytics" class="flex-1 bg-transparent border-none focus:ring-0 py-2.5 px-1 text-sm text-on-surface"/>
|
|
</div>
|
|
</div>
|
|
<div class="space-y-1.5">
|
|
<label class="block text-[10px] font-bold uppercase tracking-wider text-on-surface-variant">Description</label>
|
|
<textarea rows="2" placeholder="What does this workspace track?" class="w-full bg-surface-container-highest border-none focus:ring-0 rounded-md py-2.5 px-3 text-sm text-on-surface focus:bg-surface-container-lowest focus:shadow-[0_0_0_1px_#000]"></textarea>
|
|
</div>
|
|
<div class="space-y-1.5">
|
|
<label class="block text-[10px] font-bold uppercase tracking-wider text-on-surface-variant">Workspace Icon</label>
|
|
<div class="flex items-center gap-3">
|
|
<div class="w-10 h-10 rounded-lg bg-primary flex items-center justify-center cursor-pointer hover:bg-primary-container">
|
|
<span class="material-symbols-outlined text-on-primary" style="font-size:18px">add_photo_alternate</span>
|
|
</div>
|
|
<p class="text-xs text-on-surface-variant">Upload logo or pick from icon set (PNG, SVG, max 512KB)</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Modal footer -->
|
|
<div class="flex items-center justify-between px-7 py-4 border-t border-outline-variant/20 bg-surface-container-low">
|
|
<button onclick="closeCreateModal()" class="px-5 py-2 text-sm font-semibold text-on-surface-variant hover:bg-surface-container-high rounded-md">Cancel</button>
|
|
<div class="flex items-center gap-2">
|
|
<button class="px-5 py-2 text-sm font-semibold text-on-surface-variant hover:bg-surface-container-high rounded-md hidden" id="prev-btn">← Back</button>
|
|
<button onclick="showToast('success','Workspace created successfully!')" class="px-7 py-2 bg-primary text-on-primary text-sm font-bold rounded-md active:scale-95">Create Workspace →</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══════════════════════════════════════ CONFIRM DELETE MODAL ═══════════════════════════════════════ -->
|
|
<div id="confirm-delete-modal" class="fixed inset-0 z-[60] hidden flex items-center justify-center">
|
|
<div class="modal-backdrop absolute inset-0" onclick="document.getElementById('confirm-delete-modal').classList.add('hidden')"></div>
|
|
<div class="relative bg-surface-container-lowest rounded-xl shadow-2xl w-full max-w-md mx-4 p-7">
|
|
<div class="flex items-center gap-3 mb-5">
|
|
<div class="w-10 h-10 rounded-full bg-error-container flex items-center justify-center">
|
|
<span class="material-symbols-outlined text-error" style="font-size:20px">delete_forever</span>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-sm font-black text-on-surface">Delete "Project Alpha"?</h3>
|
|
<p class="text-xs text-on-surface-variant">This action is permanent and cannot be undone.</p>
|
|
</div>
|
|
</div>
|
|
<div class="space-y-1.5 mb-6">
|
|
<label class="block text-[10px] font-bold uppercase tracking-wider text-on-surface-variant">Type the workspace name to confirm</label>
|
|
<input id="delete-confirm-input" type="text" placeholder="Project Alpha" oninput="validateDeleteInput(this.value)" class="w-full bg-surface-container-highest border-none focus:ring-0 rounded-md py-2.5 px-3 text-sm focus:shadow-[0_0_0_1px_#ba1a1a]"/>
|
|
</div>
|
|
<div class="flex gap-3">
|
|
<button onclick="document.getElementById('confirm-delete-modal').classList.add('hidden')" class="flex-1 py-2.5 text-sm font-semibold text-on-surface-variant bg-surface-container-high hover:bg-surface-container rounded-md">Cancel</button>
|
|
<button id="delete-confirm-btn" disabled onclick="executeDelete()" class="flex-1 py-2.5 text-sm font-bold bg-error text-on-error rounded-md opacity-40 cursor-not-allowed">Delete Permanently</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══════════════════════════════════════ TOAST SYSTEM ═══════════════════════════════════════ -->
|
|
<div id="toast-container" class="fixed bottom-6 right-6 z-[100] space-y-2 pointer-events-none"></div>
|
|
|
|
<!-- ═══════════════════════════════════════ CONTEXT MENU ═══════════════════════════════════════ -->
|
|
<div id="context-menu" class="fixed z-[90] hidden bg-surface-container-lowest rounded-lg shadow-xl border border-outline-variant/30 py-1 min-w-[160px]">
|
|
<button onclick="hideContextMenu(); openWorkspaceDetail('Project Alpha')" class="w-full text-left px-4 py-2 text-xs font-semibold text-on-surface hover:bg-surface-container-high flex items-center gap-2">
|
|
<span class="material-symbols-outlined" style="font-size:14px">settings</span> Settings
|
|
</button>
|
|
<button onclick="hideContextMenu(); showToast('success','Copied workspace link!')" class="w-full text-left px-4 py-2 text-xs font-semibold text-on-surface hover:bg-surface-container-high flex items-center gap-2">
|
|
<span class="material-symbols-outlined" style="font-size:14px">link</span> Copy Link
|
|
</button>
|
|
<button onclick="hideContextMenu(); switchWorkspace('Project Alpha')" class="w-full text-left px-4 py-2 text-xs font-semibold text-on-surface hover:bg-surface-container-high flex items-center gap-2">
|
|
<span class="material-symbols-outlined" style="font-size:14px">swap_horiz</span> Switch To
|
|
</button>
|
|
<div class="h-px bg-outline-variant/20 my-1"></div>
|
|
<button onclick="hideContextMenu(); showToast('error','Workspace archived')" class="w-full text-left px-4 py-2 text-xs font-semibold text-error hover:bg-error-container flex items-center gap-2">
|
|
<span class="material-symbols-outlined" style="font-size:14px">archive</span> Archive
|
|
</button>
|
|
</div>
|
|
|
|
<script>
|
|
// ─── Workspace Switcher Dropdown ───
|
|
function toggleDropdown() {
|
|
const el = document.getElementById('ws-dropdown');
|
|
el.classList.toggle('hidden');
|
|
}
|
|
document.addEventListener('click', (e) => {
|
|
if (!e.target.closest('#ws-dropdown') && !e.target.closest('button[onclick="toggleDropdown()"]')) {
|
|
document.getElementById('ws-dropdown').classList.add('hidden');
|
|
}
|
|
document.getElementById('context-menu').classList.add('hidden');
|
|
});
|
|
|
|
function switchWorkspace(name) {
|
|
document.getElementById('ws-dropdown').classList.add('hidden');
|
|
showToast('success', `Switched to "${name}"`);
|
|
}
|
|
|
|
// ─── View Toggle ───
|
|
function setView(view, btn) {
|
|
document.querySelectorAll('.pill-toggle button').forEach(b => b.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
document.getElementById('grid-view').classList.toggle('hidden', view === 'list');
|
|
document.getElementById('list-view').classList.toggle('hidden', view === 'grid');
|
|
}
|
|
|
|
// ─── Workspace Detail Drawer ───
|
|
function openWorkspaceDetail(name) {
|
|
document.getElementById('drawer-title').textContent = name;
|
|
document.getElementById('detail-drawer').classList.remove('hidden');
|
|
switchDrawerTab('overview');
|
|
}
|
|
function closeDetailDrawer() {
|
|
document.getElementById('detail-drawer').classList.add('hidden');
|
|
}
|
|
|
|
function switchDrawerTab(tab) {
|
|
['overview','members','invitations','danger'].forEach(t => {
|
|
document.getElementById('dpanel-' + t).classList.toggle('hidden', t !== tab);
|
|
const btn = document.getElementById('dtab-' + t);
|
|
if (t === tab) {
|
|
btn.classList.add('tab-active');
|
|
btn.classList.remove('text-on-surface-variant', 'border-transparent');
|
|
} else {
|
|
btn.classList.remove('tab-active');
|
|
btn.classList.add('text-on-surface-variant', 'border-transparent');
|
|
}
|
|
});
|
|
}
|
|
|
|
// ─── Create Modal ───
|
|
function openCreateModal() {
|
|
document.getElementById('create-modal').classList.remove('hidden');
|
|
document.getElementById('create-modal').classList.add('flex');
|
|
document.getElementById('ws-dropdown').classList.add('hidden');
|
|
}
|
|
function closeCreateModal() {
|
|
document.getElementById('create-modal').classList.add('hidden');
|
|
document.getElementById('create-modal').classList.remove('flex');
|
|
}
|
|
|
|
function autoSlug(val) {
|
|
document.getElementById('slug-input').value = val.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
|
}
|
|
|
|
// ─── Search/Filter ───
|
|
function filterWorkspaces(query) {
|
|
const q = query.toLowerCase();
|
|
document.querySelectorAll('.ws-card').forEach(card => {
|
|
const name = card.querySelector('h3')?.textContent.toLowerCase() || '';
|
|
card.style.opacity = (name.includes(q) || q === '') ? '1' : '0.3';
|
|
});
|
|
}
|
|
|
|
// ─── Delete Flow ───
|
|
function confirmDelete() {
|
|
document.getElementById('confirm-delete-modal').classList.remove('hidden');
|
|
document.getElementById('confirm-delete-modal').classList.add('flex');
|
|
document.getElementById('delete-confirm-input').value = '';
|
|
document.getElementById('delete-confirm-btn').disabled = true;
|
|
document.getElementById('delete-confirm-btn').classList.add('opacity-40','cursor-not-allowed');
|
|
}
|
|
|
|
function validateDeleteInput(val) {
|
|
const btn = document.getElementById('delete-confirm-btn');
|
|
if (val === 'Project Alpha') {
|
|
btn.disabled = false;
|
|
btn.classList.remove('opacity-40','cursor-not-allowed');
|
|
} else {
|
|
btn.disabled = true;
|
|
btn.classList.add('opacity-40','cursor-not-allowed');
|
|
}
|
|
}
|
|
|
|
function executeDelete() {
|
|
document.getElementById('confirm-delete-modal').classList.add('hidden');
|
|
document.getElementById('detail-drawer').classList.add('hidden');
|
|
showToast('error','Workspace permanently deleted.');
|
|
}
|
|
|
|
// ─── Context Menu ───
|
|
function showContextMenu(e, id) {
|
|
e.preventDefault();
|
|
const menu = document.getElementById('context-menu');
|
|
menu.style.left = e.pageX + 'px';
|
|
menu.style.top = e.pageY + 'px';
|
|
menu.classList.remove('hidden');
|
|
}
|
|
function hideContextMenu() {
|
|
document.getElementById('context-menu').classList.add('hidden');
|
|
}
|
|
|
|
// ─── Toast System ───
|
|
function showToast(type, message) {
|
|
const container = document.getElementById('toast-container');
|
|
const colors = {
|
|
success: { bg: 'bg-inverse-surface', icon: 'check_circle', iconColor: 'text-[#4caf50]' },
|
|
error: { bg: 'bg-error-container', icon: 'error', iconColor: 'text-error' },
|
|
info: { bg: 'bg-primary-container', icon: 'info', iconColor: 'text-inverse-on-surface' }
|
|
};
|
|
const c = colors[type] || colors.info;
|
|
const toast = document.createElement('div');
|
|
toast.className = `toast-enter pointer-events-auto flex items-center gap-3 px-4 py-3 rounded-xl shadow-lg ${c.bg} max-w-xs`;
|
|
toast.innerHTML = `
|
|
<span class="material-symbols-outlined filled ${c.iconColor}" style="font-size:18px">${c.icon}</span>
|
|
<p class="text-sm font-semibold ${type === 'success' ? 'text-inverse-on-surface' : 'text-on-surface'} flex-1">${message}</p>
|
|
<button onclick="this.parentElement.remove()" class="ml-1 opacity-50 hover:opacity-100 ${type === 'success' ? 'text-inverse-on-surface' : 'text-on-surface'}">
|
|
<span class="material-symbols-outlined" style="font-size:16px">close</span>
|
|
</button>`;
|
|
container.appendChild(toast);
|
|
setTimeout(() => toast.remove(), 4000);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|