Files
resolutionflow/docs/mockups/resolutionflow-workspaces-mockup.html
2026-02-15 00:43:41 -05:00

1108 lines
48 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ResolutionFlow — Adaptive Workspaces Mockup</title>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=Inter:wght@400;500;600&family=Outfit:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--gradient-from: #818cf8;
--gradient-to: #a78bfa;
--bg-app: #09090b;
--bg-sidebar: #0c0c0f;
--bg-card: #18181b;
--bg-surface: #111114;
--bg-hover: #1e1e23;
--bg-active: rgba(129,140,248,0.08);
--border: #27272a;
--border-subtle: #1f1f23;
--text-primary: #fafafa;
--text-secondary: #a1a1aa;
--text-muted: #52525b;
--text-dimmed: #3f3f46;
--success: #22c55e;
--warning: #f59e0b;
--error: #ef4444;
--info: #3b82f6;
--sidebar-w: 260px;
}
* { margin:0; padding:0; box-sizing:border-box; }
body {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
background: var(--bg-app);
color: var(--text-primary);
height: 100vh;
overflow: hidden;
}
.app-shell {
display: grid;
grid-template-columns: var(--sidebar-w) 1fr;
grid-template-rows: 56px 1fr;
height: 100vh;
}
/* ── Top Bar ── */
.topbar {
grid-column: 1 / -1;
display: flex;
align-items: center;
padding: 0 20px;
background: var(--bg-sidebar);
border-bottom: 1px solid var(--border);
gap: 16px;
z-index: 100;
}
.topbar-logo {
display: flex;
align-items: center;
gap: 10px;
width: calc(var(--sidebar-w) - 40px);
flex-shrink: 0;
}
.topbar-logo svg { width: 32px; height: 32px; }
.topbar-brand {
font-family: 'Plus Jakarta Sans', sans-serif;
font-size: 1.1rem;
font-weight: 700;
letter-spacing: -0.02em;
}
.topbar-brand .res { color: var(--text-primary); }
.topbar-brand .flow {
background: linear-gradient(90deg, var(--gradient-from), var(--gradient-to));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.topbar-search {
flex: 1;
max-width: 480px;
position: relative;
}
.topbar-search input {
width: 100%;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 8px;
padding: 8px 12px 8px 36px;
color: var(--text-primary);
font-family: inherit;
font-size: 0.8125rem;
outline: none;
transition: border-color 0.15s;
}
.topbar-search input::placeholder { color: var(--text-muted); }
.topbar-search input:focus { border-color: var(--gradient-from); }
.topbar-search .search-icon {
position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
color: var(--text-muted); width: 15px; height: 15px;
}
.topbar-search .search-shortcut {
position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
background: var(--bg-surface); border: 1px solid var(--border); border-radius: 4px;
padding: 1px 6px; font-size: 0.6875rem; color: var(--text-muted); font-family: 'Outfit', sans-serif;
}
.topbar-actions {
display: flex; align-items: center; gap: 6px; margin-left: auto;
}
.topbar-btn {
display: flex; align-items: center; justify-content: center;
width: 36px; height: 36px; border-radius: 8px; border: none;
background: transparent; color: var(--text-secondary); cursor: pointer;
transition: all 0.15s; position: relative;
}
.topbar-btn:hover { background: var(--bg-hover); color: var(--text-primary); }
.topbar-btn svg { width: 18px; height: 18px; }
.notification-badge {
position: absolute; top: 6px; right: 6px; width: 8px; height: 8px;
background: var(--error); border-radius: 50%; border: 2px solid var(--bg-sidebar);
}
.avatar-sm {
width: 32px; height: 32px; border-radius: 50%;
background: linear-gradient(135deg, var(--gradient-from), var(--gradient-to));
display: flex; align-items: center; justify-content: center;
font-family: 'Plus Jakarta Sans', sans-serif; font-size: 0.75rem;
font-weight: 700; color: white; margin-left: 4px; cursor: pointer;
}
/* ── Sidebar ── */
.sidebar {
background: var(--bg-sidebar);
border-right: 1px solid var(--border);
overflow-y: auto;
padding: 16px 12px;
display: flex;
flex-direction: column;
gap: 2px;
}
.sidebar::-webkit-scrollbar { width: 4px; }
.sidebar::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.nav-section { margin-bottom: 16px; }
.nav-section-label {
font-family: 'Outfit', sans-serif;
font-size: 0.6875rem; font-weight: 600;
text-transform: uppercase; letter-spacing: 0.06em;
color: var(--text-muted); padding: 0 12px; margin-bottom: 6px;
}
.nav-item {
display: flex; align-items: center; gap: 10px;
padding: 8px 12px; border-radius: 7px; cursor: pointer;
transition: all 0.12s; font-size: 0.8125rem; font-weight: 500;
color: var(--text-secondary); text-decoration: none; position: relative;
}
.nav-item:hover { background: var(--bg-hover); color: var(--text-primary); }
.nav-item.active { background: var(--bg-active); color: var(--text-primary); }
.nav-item.active::before {
content: ''; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
background: linear-gradient(180deg, var(--gradient-from), var(--gradient-to));
border-radius: 0 3px 3px 0;
}
.nav-item svg { width: 18px; height: 18px; flex-shrink: 0; opacity: 0.7; }
.nav-item.active svg { opacity: 1; }
.nav-item .badge {
margin-left: auto; background: var(--bg-card); border: 1px solid var(--border);
border-radius: 10px; padding: 0 7px; font-size: 0.6875rem;
font-family: 'Outfit', sans-serif; color: var(--text-muted); line-height: 1.7;
}
.nav-item.active .badge {
background: rgba(129,140,248,0.15); border-color: rgba(129,140,248,0.3); color: var(--gradient-from);
}
.nav-divider { height: 1px; background: var(--border-subtle); margin: 10px 12px; }
/* ── Workspace Switcher ── */
.workspace-switcher {
margin-bottom: 16px;
padding: 0 4px;
}
.workspace-current {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 8px;
cursor: pointer;
transition: all 0.15s;
position: relative;
}
.workspace-current:hover {
border-color: var(--gradient-from);
background: var(--bg-hover);
}
.workspace-current.open {
border-color: var(--gradient-from);
border-radius: 8px 8px 0 0;
border-bottom-color: var(--border-subtle);
}
.workspace-icon {
width: 32px; height: 32px; border-radius: 7px;
display: flex; align-items: center; justify-content: center;
font-size: 1rem; flex-shrink: 0;
transition: background 0.2s;
}
.workspace-label {
flex: 1;
}
.workspace-label .ws-name {
font-family: 'Plus Jakarta Sans', sans-serif;
font-size: 0.8125rem; font-weight: 700;
letter-spacing: -0.005em;
transition: color 0.2s;
}
.workspace-label .ws-desc {
font-size: 0.6875rem; color: var(--text-muted);
transition: color 0.2s;
}
.workspace-chevron {
color: var(--text-muted);
transition: transform 0.2s;
flex-shrink: 0;
}
.workspace-current.open .workspace-chevron { transform: rotate(180deg); }
.workspace-chevron svg { width: 14px; height: 14px; }
.workspace-dropdown {
display: none;
background: var(--bg-card);
border: 1px solid var(--gradient-from);
border-top: 1px solid var(--border-subtle);
border-radius: 0 0 8px 8px;
overflow: hidden;
animation: dropIn 0.15s ease;
}
.workspace-dropdown.show { display: block; }
@keyframes dropIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.workspace-option {
display: flex; align-items: center; gap: 10px;
padding: 10px 12px;
cursor: pointer; transition: background 0.1s;
border-bottom: 1px solid var(--border-subtle);
}
.workspace-option:last-child { border-bottom: none; }
.workspace-option:hover { background: var(--bg-hover); }
.workspace-option.active-ws { background: var(--bg-active); }
.workspace-option .ws-opt-icon {
width: 28px; height: 28px; border-radius: 6px;
display: flex; align-items: center; justify-content: center;
font-size: 0.875rem; flex-shrink: 0;
}
.workspace-option .ws-opt-name {
font-family: 'Plus Jakarta Sans', sans-serif;
font-size: 0.8125rem; font-weight: 600;
}
.workspace-option .ws-opt-count {
margin-left: auto; font-family: 'Outfit', sans-serif;
font-size: 0.6875rem; color: var(--text-dimmed);
}
.workspace-add {
display: flex; align-items: center; gap: 8px;
padding: 9px 12px; cursor: pointer;
font-size: 0.75rem; color: var(--text-muted);
transition: all 0.1s;
border-top: 1px solid var(--border-subtle);
}
.workspace-add:hover { background: var(--bg-hover); color: var(--gradient-from); }
.workspace-add svg { width: 14px; height: 14px; }
/* ── Category Tags ── */
.category-tag {
display: flex; align-items: center; gap: 8px;
padding: 6px 12px; border-radius: 6px; cursor: pointer;
transition: all 0.15s; font-size: 0.8125rem; color: var(--text-secondary);
}
.category-tag:hover { background: var(--bg-hover); color: var(--text-primary); }
.cat-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.category-tag .cat-count {
margin-left: auto; font-size: 0.6875rem; color: var(--text-dimmed);
font-family: 'Outfit', sans-serif;
}
.tag-cloud {
display: flex; flex-wrap: wrap; gap: 4px; padding: 0 8px;
}
.filter-chip {
display: inline-flex; align-items: center; gap: 5px;
padding: 3px 8px; background: var(--bg-card); border: 1px solid var(--border);
border-radius: 5px; font-size: 0.6875rem; color: var(--text-secondary);
cursor: pointer; transition: all 0.12s; font-family: 'Outfit', sans-serif;
}
.filter-chip:hover { border-color: var(--text-muted); color: var(--text-primary); }
.sidebar-footer {
margin-top: auto; padding-top: 12px; border-top: 1px solid var(--border-subtle);
}
/* ── Animated content transitions ── */
.sidebar-content { transition: opacity 0.2s; }
.sidebar-content.switching { opacity: 0; }
/* ── Main Content ── */
.main {
overflow-y: auto; padding: 24px 28px; background: var(--bg-app);
}
.main::-webkit-scrollbar { width: 6px; }
.main::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.page-header {
display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px;
}
.page-header h1 {
font-family: 'Plus Jakarta Sans', sans-serif;
font-size: 1.375rem; font-weight: 700; letter-spacing: -0.01em;
}
.page-header-actions { display: flex; align-items: center; gap: 8px; }
.btn {
display: inline-flex; align-items: center; gap: 6px;
padding: 8px 16px; border-radius: 8px; border: none;
font-family: inherit; font-size: 0.8125rem; font-weight: 600;
cursor: pointer; transition: all 0.15s;
}
.btn svg { width: 16px; height: 16px; }
.btn-primary {
background: linear-gradient(135deg, var(--gradient-from), var(--gradient-to));
color: white; box-shadow: 0 2px 12px rgba(129,140,248,0.25);
}
.btn-primary:hover { box-shadow: 0 4px 20px rgba(129,140,248,0.35); transform: translateY(-1px); }
.btn-secondary {
background: var(--bg-card); border: 1px solid var(--border); color: var(--text-secondary);
}
.btn-secondary:hover { border-color: var(--text-muted); color: var(--text-primary); }
/* ── Quick Stats ── */
.quick-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 24px; }
.stat-card {
background: var(--bg-card); border: 1px solid var(--border-subtle);
border-radius: 10px; padding: 16px 18px; transition: border-color 0.15s;
}
.stat-card:hover { border-color: var(--border); }
.stat-label {
font-family: 'Outfit', sans-serif; font-size: 0.6875rem;
text-transform: uppercase; letter-spacing: 0.05em;
color: var(--text-muted); margin-bottom: 6px;
}
.stat-value {
font-family: 'Plus Jakarta Sans', sans-serif;
font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em;
}
.stat-meta { font-size: 0.6875rem; color: var(--text-dimmed); margin-top: 4px; }
.stat-value.gradient {
background: linear-gradient(90deg, var(--gradient-from), var(--gradient-to));
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
/* ── Filters Bar ── */
.filters-bar {
display: flex; align-items: center; gap: 8px; margin-bottom: 20px; flex-wrap: wrap;
}
.main-filter-chip {
display: inline-flex; align-items: center; gap: 6px;
padding: 6px 12px; background: var(--bg-card); border: 1px solid var(--border);
border-radius: 6px; font-size: 0.75rem; color: var(--text-secondary);
cursor: pointer; transition: all 0.12s; font-family: 'Outfit', sans-serif;
}
.main-filter-chip:hover { border-color: var(--text-muted); color: var(--text-primary); }
.main-filter-chip.active {
background: rgba(129,140,248,0.1); border-color: rgba(129,140,248,0.3); color: var(--gradient-from);
}
.main-filter-chip svg { width: 14px; height: 14px; }
.filter-divider { width: 1px; height: 24px; background: var(--border); }
/* ── Section Groups ── */
.section-group { margin-bottom: 28px; }
.section-header {
display: flex; align-items: center; gap: 10px; margin-bottom: 12px;
padding-bottom: 10px; border-bottom: 1px solid var(--border-subtle);
}
.section-icon { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.section-title {
font-family: 'Plus Jakarta Sans', sans-serif; font-size: 0.8125rem;
font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
}
.section-count {
font-family: 'Outfit', sans-serif; font-size: 0.6875rem; color: var(--text-muted);
background: var(--bg-surface); border-radius: 10px; padding: 1px 8px;
}
/* ── Tree / Flow Items ── */
.tree-list { display: flex; flex-direction: column; gap: 4px; }
.tree-list-header {
display: grid; grid-template-columns: 40px 1fr 130px 80px 100px 40px;
align-items: center; gap: 12px; padding: 0 16px 8px;
font-family: 'Outfit', sans-serif; font-size: 0.6875rem;
text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-dimmed);
}
.tree-item {
display: grid; grid-template-columns: 40px 1fr 130px 80px 100px 40px;
align-items: center; gap: 12px; padding: 12px 16px;
background: var(--bg-card); border: 1px solid transparent;
border-radius: 8px; cursor: pointer; transition: all 0.12s;
}
.tree-item:hover { border-color: var(--border); background: var(--bg-hover); }
.tree-icon-box {
width: 36px; height: 36px; border-radius: 8px;
display: flex; align-items: center; justify-content: center; font-size: 1rem;
}
.tree-info h3 {
font-family: 'Plus Jakarta Sans', sans-serif;
font-size: 0.875rem; font-weight: 600; margin-bottom: 3px;
}
.tree-meta {
display: flex; align-items: center; gap: 8px;
font-size: 0.6875rem; color: var(--text-muted);
}
.tree-meta .tag {
background: var(--bg-surface); border: 1px solid var(--border-subtle);
border-radius: 4px; padding: 1px 6px; font-family: 'Outfit', sans-serif;
font-size: 0.625rem; color: var(--text-muted);
}
.tree-category {
font-family: 'Outfit', sans-serif; font-size: 0.75rem; color: var(--text-secondary);
display: flex; align-items: center; gap: 6px;
}
.cat-indicator { width: 6px; height: 6px; border-radius: 50%; }
.tree-usage {
font-family: 'Outfit', sans-serif; font-size: 0.75rem; color: var(--text-muted); text-align: center;
}
.tree-updated { font-size: 0.6875rem; color: var(--text-dimmed); text-align: right; }
.tree-actions { display: flex; align-items: center; justify-content: center; }
.tree-actions button {
background: none; border: none; color: var(--text-muted); cursor: pointer;
padding: 4px; border-radius: 4px; display: flex; opacity: 0; transition: all 0.12s;
}
.tree-item:hover .tree-actions button { opacity: 1; }
/* ── Sessions Panel ── */
.sessions-panel {
background: var(--bg-card); border: 1px solid var(--border-subtle);
border-radius: 10px; overflow: hidden;
}
.sessions-panel-header {
display: flex; align-items: center; justify-content: space-between;
padding: 14px 18px; border-bottom: 1px solid var(--border-subtle);
}
.sessions-panel-header h2 {
font-family: 'Plus Jakarta Sans', sans-serif; font-size: 0.875rem; font-weight: 700;
}
.session-row {
display: grid; grid-template-columns: 8px 1fr 140px 80px 100px;
align-items: center; gap: 12px; padding: 11px 18px;
border-bottom: 1px solid var(--border-subtle); font-size: 0.8125rem;
transition: background 0.1s; cursor: pointer;
}
.session-row:last-child { border-bottom: none; }
.session-row:hover { background: var(--bg-hover); }
.session-status-dot { width: 8px; height: 8px; border-radius: 50%; }
.session-name { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.session-tree { font-size: 0.6875rem; color: var(--text-muted); font-family: 'Outfit', sans-serif; }
.session-ticket { font-size: 0.6875rem; color: var(--text-muted); font-family: monospace; }
.session-time { font-size: 0.6875rem; color: var(--text-dimmed); text-align: right; }
.bg-success { background: var(--success); }
.bg-warning { background: var(--warning); }
.bg-gradient { background: linear-gradient(135deg, var(--gradient-from), var(--gradient-to)); }
/* ── Workspace color accents ── */
.ws-accent-troubleshooting { --ws-color: #ef4444; }
.ws-accent-procedures { --ws-color: #3b82f6; }
.ws-accent-policies { --ws-color: #8b5cf6; }
.ws-accent-finance { --ws-color: #22c55e; }
/* ── Content transition ── */
.main-content { transition: opacity 0.2s ease; }
.main-content.switching { opacity: 0; }
/* ── Toast notification ── */
.toast {
position: fixed; bottom: 60px; left: 50%; transform: translateX(-50%) translateY(20px);
background: var(--bg-card); border: 1px solid var(--gradient-from);
border-radius: 10px; padding: 12px 20px;
font-size: 0.8125rem; color: var(--text-primary);
display: flex; align-items: center; gap: 10px;
box-shadow: 0 8px 32px rgba(0,0,0,0.5);
opacity: 0; transition: all 0.3s ease; z-index: 1000;
pointer-events: none;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast-icon { font-size: 1rem; }
.toast-text strong { color: var(--gradient-from); }
.fade-in { animation: fadeIn 0.3s ease; }
@keyframes fadeIn { from { opacity:0; transform:translateY(6px); } to { opacity:1; transform:translateY(0); } }
.mockup-label {
position: fixed; bottom: 12px; right: 16px;
background: rgba(129,140,248,0.12); border: 1px solid rgba(129,140,248,0.25);
border-radius: 6px; padding: 4px 10px;
font-family: 'Outfit', sans-serif; font-size: 0.6875rem;
color: var(--gradient-from); z-index: 1000; backdrop-filter: blur(8px);
}
.mockup-hint {
position: fixed; bottom: 12px; left: 50%; transform: translateX(-50%);
background: rgba(129,140,248,0.12); border: 1px solid rgba(129,140,248,0.25);
border-radius: 8px; padding: 6px 14px;
font-family: 'Outfit', sans-serif; font-size: 0.75rem;
color: var(--gradient-from); z-index: 1000; backdrop-filter: blur(8px);
display: flex; align-items: center; gap: 8px;
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 0.8; }
50% { opacity: 1; }
}
.mockup-hint svg { width: 14px; height: 14px; }
</style>
</head>
<body>
<div class="app-shell">
<!-- ═══════════════ TOP BAR ═══════════════ -->
<header class="topbar">
<div class="topbar-logo">
<svg viewBox="0 0 80 80" fill="none">
<defs>
<linearGradient id="logo-g" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a78bfa"/>
</linearGradient>
</defs>
<circle cx="10" cy="14" r="5" fill="url(#logo-g)" opacity="0.25"/>
<circle cx="10" cy="30" r="5.5" fill="url(#logo-g)" opacity="0.4"/>
<circle cx="10" cy="50" r="5.5" fill="url(#logo-g)" opacity="0.4"/>
<circle cx="10" cy="66" r="5" fill="url(#logo-g)" opacity="0.25"/>
<path d="M15 14L28 34" stroke="url(#logo-g)" stroke-width="2" stroke-linecap="round" stroke-dasharray="2 3" opacity="0.35"/>
<path d="M15.5 30L28 38" stroke="url(#logo-g)" stroke-width="2" stroke-linecap="round" opacity="0.5"/>
<path d="M15.5 50L28 42" stroke="url(#logo-g)" stroke-width="2" stroke-linecap="round" opacity="0.5"/>
<path d="M15 66L28 46" stroke="url(#logo-g)" stroke-width="2" stroke-linecap="round" stroke-dasharray="2 3" opacity="0.35"/>
<circle cx="36" cy="40" r="10" fill="url(#logo-g)" opacity="0.12"/>
<circle cx="36" cy="40" r="7" fill="url(#logo-g)" opacity="0.9"/>
<path d="M43 40H70M70 40L60 30M70 40L60 50" stroke="url(#logo-g)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="topbar-brand"><span class="res">Resolution</span><span class="flow">Flow</span></span>
</div>
<div class="topbar-search">
<svg class="search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
<input type="text" placeholder="Search trees, sessions, tags…" id="searchInput" />
<span class="search-shortcut">⌘K</span>
</div>
<div class="topbar-actions">
<button class="topbar-btn" title="Quick launch">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
</button>
<button class="topbar-btn" title="Notifications">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
<span class="notification-badge"></span>
</button>
<div class="avatar-sm" title="Michael C.">MC</div>
</div>
</header>
<!-- ═══════════════ SIDEBAR ═══════════════ -->
<nav class="sidebar">
<!-- Workspace Switcher -->
<div class="workspace-switcher">
<div class="workspace-current" id="wsCurrent" onclick="toggleDropdown()">
<div class="workspace-icon" id="wsIcon" style="background: rgba(239,68,68,0.12);">
<span id="wsEmoji">🔧</span>
</div>
<div class="workspace-label">
<div class="ws-name" id="wsName">Troubleshooting</div>
<div class="ws-desc" id="wsDesc">Break/fix decision trees</div>
</div>
<div class="workspace-chevron">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
</div>
</div>
<div class="workspace-dropdown" id="wsDropdown">
<div class="workspace-option active-ws" data-ws="troubleshooting" onclick="switchWorkspace('troubleshooting')">
<div class="ws-opt-icon" style="background: rgba(239,68,68,0.12);">🔧</div>
<span class="ws-opt-name">Troubleshooting</span>
<span class="ws-opt-count">42 trees</span>
</div>
<div class="workspace-option" data-ws="procedures" onclick="switchWorkspace('procedures')">
<div class="ws-opt-icon" style="background: rgba(59,130,246,0.12);">📋</div>
<span class="ws-opt-name">Procedures</span>
<span class="ws-opt-count">18 flows</span>
</div>
<div class="workspace-option" data-ws="policies" onclick="switchWorkspace('policies')">
<div class="ws-opt-icon" style="background: rgba(139,92,246,0.12);">📜</div>
<span class="ws-opt-name">Policies</span>
<span class="ws-opt-count">7 flows</span>
</div>
<div class="workspace-option" data-ws="finance" onclick="switchWorkspace('finance')">
<div class="ws-opt-icon" style="background: rgba(34,197,94,0.12);">💰</div>
<span class="ws-opt-name">Finance</span>
<span class="ws-opt-count">4 flows</span>
</div>
<div class="workspace-add">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Add workspace…
</div>
</div>
</div>
<!-- Main Nav -->
<div class="nav-section">
<a class="nav-item active" href="#">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
Dashboard
</a>
<a class="nav-item" href="#" id="navAllFlows">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg>
<span id="navAllLabel">All Trees</span>
<span class="badge" id="navAllCount">42</span>
</a>
<a class="nav-item" href="#">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
<span id="navEditorLabel">Tree Editor</span>
</a>
<a class="nav-item" href="#">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
Sessions
<span class="badge">3</span>
</a>
<a class="nav-item" href="#">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
Exports
</a>
<a class="nav-item" href="#">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
Step Library
</a>
</div>
<div class="nav-divider"></div>
<!-- Dynamic Categories -->
<div class="sidebar-content" id="sidebarContent">
<div class="nav-section">
<div class="nav-section-label">Categories</div>
<div id="categoriesContainer"></div>
</div>
<div class="nav-divider"></div>
<div class="nav-section">
<div class="nav-section-label">Popular Tags</div>
<div class="tag-cloud" id="tagsContainer"></div>
</div>
</div>
<!-- Footer -->
<div class="sidebar-footer">
<a class="nav-item" href="#">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>
Team
</a>
<a class="nav-item" href="#">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
Settings
</a>
</div>
</nav>
<!-- ═══════════════ MAIN CONTENT ═══════════════ -->
<main class="main">
<div class="main-content" id="mainContent">
<div class="page-header fade-in">
<h1 id="pageTitle">Troubleshooting Dashboard</h1>
<div class="page-header-actions">
<button class="btn btn-secondary">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
Import
</button>
<button class="btn btn-primary" id="newBtn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
<span id="newBtnLabel">New Tree</span>
</button>
</div>
</div>
<!-- Stats -->
<div class="quick-stats fade-in" id="statsRow"></div>
<!-- Filters -->
<div class="filters-bar fade-in" id="filtersRow"></div>
<!-- Tree/Flow Items -->
<div class="section-group fade-in" id="mainSection"></div>
<!-- Recent Sessions -->
<div class="section-group fade-in" id="sessionsSection"></div>
</div>
</main>
</div>
<div class="toast" id="toast">
<span class="toast-icon" id="toastIcon"></span>
<span class="toast-text" id="toastText"></span>
</div>
<div class="mockup-hint">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
Click the workspace switcher in the sidebar to see it adapt
</div>
<div class="mockup-label">ResolutionFlow — Adaptive Workspaces Mockup</div>
<script>
// ═══════════════════════════════════════════════════════
// WORKSPACE DATA — each workspace defines its own context
// ═══════════════════════════════════════════════════════
const workspaces = {
troubleshooting: {
name: 'Troubleshooting',
desc: 'Break/fix decision trees',
emoji: '🔧',
color: '#ef4444',
bgColor: 'rgba(239,68,68,0.12)',
allLabel: 'All Trees',
allCount: '42',
editorLabel: 'Tree Editor',
newLabel: 'New Tree',
pageTitle: 'Troubleshooting Dashboard',
searchPlaceholder: 'Search trees, sessions, tags…',
categories: [
{ name: 'Networking', color: '#3b82f6', count: 12 },
{ name: 'Active Directory', color: '#22c55e', count: 8 },
{ name: 'Email / Exchange', color: '#f59e0b', count: 6 },
{ name: 'Server Issues', color: '#ef4444', count: 5 },
{ name: 'Citrix / RDS', color: '#8b5cf6', count: 4 },
{ name: 'VPN / Remote', color: '#06b6d4', count: 4 },
{ name: 'Printers / Peripherals', color: '#ec4899', count: 3 },
],
tags: ['tier-1', 'tier-2', 'tier-3', 'dns', 'o365', 'vpn', 'backup', 'critical'],
stats: [
{ label: 'Active Trees', value: '42', meta: '+3 this week' },
{ label: 'Sessions Today', value: '12', gradient: true, meta: '↑ 20% from yesterday' },
{ label: 'Open Sessions', value: '3', color: '#f59e0b', meta: 'Awaiting completion' },
{ label: 'Docs Generated', value: '847', meta: 'All time' },
],
filters: ['All', 'Recently Used', 'My Trees', 'Team Trees', 'Defaults'],
sectionTitle: 'Frequently Used',
sectionCount: 5,
items: [
{ icon: '🌐', iconBg: 'rgba(59,130,246,0.12)', iconColor: '#3b82f6', name: 'DNS Resolution Failure', tags: ['tier-1', 'dns'], steps: '12 steps · 4 solutions', cat: 'Networking', catColor: '#3b82f6', uses: 284, updated: '2 days ago' },
{ icon: '🔒', iconBg: 'rgba(34,197,94,0.12)', iconColor: '#22c55e', name: 'Account Lockout Investigation', tags: ['tier-2', 'security'], steps: '18 steps · 6 solutions', cat: 'Active Directory', catColor: '#22c55e', uses: 216, updated: '1 week ago' },
{ icon: '📧', iconBg: 'rgba(245,158,11,0.12)', iconColor: '#f59e0b', name: 'Mail Flow Troubleshooting', tags: ['tier-2', 'o365'], steps: '15 steps · 5 solutions', cat: 'Email / Exchange', catColor: '#f59e0b', uses: 189, updated: '3 days ago' },
{ icon: '🔌', iconBg: 'rgba(6,182,212,0.12)', iconColor: '#06b6d4', name: 'VPN Connection Failure', tags: ['tier-1', 'vpn'], steps: '10 steps · 3 solutions', cat: 'VPN / Remote', catColor: '#06b6d4', uses: 172, updated: '5 days ago' },
{ icon: '🖥️', iconBg: 'rgba(239,68,68,0.12)', iconColor: '#ef4444', name: 'Server Unresponsive', tags: ['tier-3', 'critical'], steps: '22 steps · 8 solutions', cat: 'Server Issues', catColor: '#ef4444', uses: 145, updated: '1 day ago' },
],
sessions: [
{ status: 'warning', name: 'DNS Resolution Failure', progress: '→ Checked DNS config · step 4/12', ticket: 'TKT-4821', time: '12 min ago' },
{ status: 'warning', name: 'Account Lockout Investigation', progress: '→ Reviewing event logs · step 6/18', ticket: 'TKT-4819', time: '45 min ago' },
{ status: 'success', name: 'Mail Flow Troubleshooting', progress: '✓ Resolved · MX record corrected', ticket: 'TKT-4815', time: 'Yesterday' },
]
},
procedures: {
name: 'Procedures',
desc: 'Step-by-step operational flows',
emoji: '📋',
color: '#3b82f6',
bgColor: 'rgba(59,130,246,0.12)',
allLabel: 'All Procedures',
allCount: '18',
editorLabel: 'Flow Editor',
newLabel: 'New Procedure',
pageTitle: 'Procedures Dashboard',
searchPlaceholder: 'Search procedures, runbooks, checklists…',
categories: [
{ name: 'Server Builds', color: '#3b82f6', count: 5 },
{ name: 'Onboarding', color: '#22c55e', count: 4 },
{ name: 'Offboarding', color: '#ef4444', count: 3 },
{ name: 'Backup & DR', color: '#f59e0b', count: 3 },
{ name: 'Patch Management', color: '#8b5cf6', count: 2 },
{ name: 'Security Audit', color: '#06b6d4', count: 1 },
],
tags: ['windows-server', 'hyper-v', 'new-hire', 'quarterly', 'azure', 'compliance', 'm365-setup'],
stats: [
{ label: 'Active Procedures', value: '18', meta: '+2 this month' },
{ label: 'Runs This Week', value: '8', gradient: true, meta: '↑ 33% from last week' },
{ label: 'In Progress', value: '2', color: '#3b82f6', meta: 'Being executed' },
{ label: 'Avg Completion', value: '94%', meta: 'Last 30 days' },
],
filters: ['All', 'Recently Run', 'My Procedures', 'Team', 'Templates'],
sectionTitle: 'Most Used Procedures',
sectionCount: 4,
items: [
{ icon: '🖥️', iconBg: 'rgba(59,130,246,0.12)', iconColor: '#3b82f6', name: 'Windows Server 2022 Build', tags: ['windows-server', 'hyper-v'], steps: '34 steps · 6 checkpoints', cat: 'Server Builds', catColor: '#3b82f6', uses: 89, updated: '1 week ago' },
{ icon: '👤', iconBg: 'rgba(34,197,94,0.12)', iconColor: '#22c55e', name: 'New Employee Onboarding', tags: ['new-hire', 'm365-setup'], steps: '28 steps · 4 checkpoints', cat: 'Onboarding', catColor: '#22c55e', uses: 67, updated: '3 days ago' },
{ icon: '🔄', iconBg: 'rgba(245,158,11,0.12)', iconColor: '#f59e0b', name: 'Monthly Backup Verification', tags: ['quarterly', 'compliance'], steps: '16 steps · 3 checkpoints', cat: 'Backup & DR', catColor: '#f59e0b', uses: 52, updated: '2 days ago' },
{ icon: '🚪', iconBg: 'rgba(239,68,68,0.12)', iconColor: '#ef4444', name: 'Employee Offboarding', tags: ['compliance', 'security'], steps: '22 steps · 5 checkpoints', cat: 'Offboarding', catColor: '#ef4444', uses: 41, updated: '5 days ago' },
],
sessions: [
{ status: 'warning', name: 'Windows Server 2022 Build', progress: '→ Installing roles · step 12/34', ticket: 'PRJ-102', time: '30 min ago' },
{ status: 'warning', name: 'New Employee Onboarding', progress: '→ M365 license assignment · step 8/28', ticket: 'HR-445', time: '2 hours ago' },
{ status: 'success', name: 'Monthly Backup Verification', progress: '✓ Complete · All systems verified', ticket: 'OPS-891', time: 'Yesterday' },
]
},
policies: {
name: 'Policies',
desc: 'Compliance & policy builders',
emoji: '📜',
color: '#8b5cf6',
bgColor: 'rgba(139,92,246,0.12)',
allLabel: 'All Policies',
allCount: '7',
editorLabel: 'Policy Editor',
newLabel: 'New Policy',
pageTitle: 'Policies Dashboard',
searchPlaceholder: 'Search policies, compliance, frameworks…',
categories: [
{ name: 'Security Policies', color: '#ef4444', count: 3 },
{ name: 'Acceptable Use', color: '#3b82f6', count: 2 },
{ name: 'Data Governance', color: '#8b5cf6', count: 1 },
{ name: 'Incident Response', color: '#f59e0b', count: 1 },
],
tags: ['nist', 'hipaa', 'soc2', 'gdpr', 'internal', 'client-facing', 'annual-review'],
stats: [
{ label: 'Active Policies', value: '7', meta: '+1 this quarter' },
{ label: 'Pending Review', value: '2', gradient: true, meta: 'Due this month' },
{ label: 'Compliance Score', value: '91%', color: '#22c55e', meta: 'Across frameworks' },
{ label: 'Last Audit', value: '14d', meta: 'Days since last review' },
],
filters: ['All', 'Needs Review', 'Active', 'Draft', 'Archived'],
sectionTitle: 'Policy Documents',
sectionCount: 4,
items: [
{ icon: '🔐', iconBg: 'rgba(239,68,68,0.12)', iconColor: '#ef4444', name: 'Password & Authentication Policy', tags: ['nist', 'soc2'], steps: '12 sections · NIST aligned', cat: 'Security Policies', catColor: '#ef4444', uses: 34, updated: '2 weeks ago' },
{ icon: '💻', iconBg: 'rgba(59,130,246,0.12)', iconColor: '#3b82f6', name: 'Acceptable Use Policy', tags: ['internal', 'client-facing'], steps: '8 sections · Template', cat: 'Acceptable Use', catColor: '#3b82f6', uses: 28, updated: '1 month ago' },
{ icon: '🚨', iconBg: 'rgba(245,158,11,0.12)', iconColor: '#f59e0b', name: 'Incident Response Plan', tags: ['nist', 'compliance'], steps: '15 sections · Runbook', cat: 'Incident Response', catColor: '#f59e0b', uses: 19, updated: '3 weeks ago' },
{ icon: '📊', iconBg: 'rgba(139,92,246,0.12)', iconColor: '#8b5cf6', name: 'Data Classification Standard', tags: ['gdpr', 'hipaa'], steps: '6 sections · Framework', cat: 'Data Governance', catColor: '#8b5cf6', uses: 12, updated: '1 month ago' },
],
sessions: [
{ status: 'warning', name: 'Password Policy Update', progress: '→ Review MFA requirements · section 4/12', ticket: 'POL-23', time: '1 day ago' },
{ status: 'success', name: 'Acceptable Use Policy', progress: '✓ Approved · v2.1 published', ticket: 'POL-21', time: '2 weeks ago' },
]
},
finance: {
name: 'Finance',
desc: 'Billing & procurement flows',
emoji: '💰',
color: '#22c55e',
bgColor: 'rgba(34,197,94,0.12)',
allLabel: 'All Finance Flows',
allCount: '4',
editorLabel: 'Flow Editor',
newLabel: 'New Flow',
pageTitle: 'Finance Dashboard',
searchPlaceholder: 'Search billing, procurement, approvals…',
categories: [
{ name: 'License Management', color: '#3b82f6', count: 2 },
{ name: 'Procurement', color: '#22c55e', count: 1 },
{ name: 'Billing Reviews', color: '#f59e0b', count: 1 },
],
tags: ['monthly', 'approval-required', 'vendor', 'license-audit', 'cost-savings'],
stats: [
{ label: 'Active Flows', value: '4', meta: 'All operational' },
{ label: 'Runs This Month', value: '6', gradient: true, meta: 'On schedule' },
{ label: 'Cost Saved', value: '$4.2K', color: '#22c55e', meta: 'From license audits' },
{ label: 'Pending Approvals', value: '1', meta: 'Awaiting sign-off' },
],
filters: ['All', 'Pending Approval', 'Recurring', 'One-time'],
sectionTitle: 'Finance Flows',
sectionCount: 3,
items: [
{ icon: '🔑', iconBg: 'rgba(59,130,246,0.12)', iconColor: '#3b82f6', name: 'M365 License Audit', tags: ['monthly', 'license-audit'], steps: '8 steps · 2 approvals', cat: 'License Management', catColor: '#3b82f6', uses: 24, updated: '1 week ago' },
{ icon: '🛒', iconBg: 'rgba(34,197,94,0.12)', iconColor: '#22c55e', name: 'Hardware Procurement', tags: ['approval-required', 'vendor'], steps: '12 steps · 3 approvals', cat: 'Procurement', catColor: '#22c55e', uses: 18, updated: '2 weeks ago' },
{ icon: '📄', iconBg: 'rgba(245,158,11,0.12)', iconColor: '#f59e0b', name: 'Quarterly Billing Review', tags: ['quarterly', 'cost-savings'], steps: '10 steps · Report', cat: 'Billing Reviews', catColor: '#f59e0b', uses: 12, updated: '1 month ago' },
],
sessions: [
{ status: 'warning', name: 'M365 License Audit', progress: '→ Reviewing unused licenses · step 5/8', ticket: 'FIN-67', time: '3 hours ago' },
{ status: 'success', name: 'Hardware Procurement', progress: '✓ Approved · PO submitted', ticket: 'FIN-64', time: 'Yesterday' },
]
}
};
// ═══════════════════════════════
// RENDER FUNCTIONS
// ═══════════════════════════════
let currentWs = 'troubleshooting';
let dropdownOpen = false;
function toggleDropdown() {
dropdownOpen = !dropdownOpen;
const dd = document.getElementById('wsDropdown');
const cur = document.getElementById('wsCurrent');
if (dropdownOpen) {
dd.classList.add('show');
cur.classList.add('open');
} else {
dd.classList.remove('show');
cur.classList.remove('open');
}
}
function switchWorkspace(wsKey) {
if (wsKey === currentWs) { toggleDropdown(); return; }
const ws = workspaces[wsKey];
currentWs = wsKey;
// Close dropdown
dropdownOpen = false;
document.getElementById('wsDropdown').classList.remove('show');
document.getElementById('wsCurrent').classList.remove('open');
// Update dropdown active states
document.querySelectorAll('.workspace-option').forEach(el => {
el.classList.toggle('active-ws', el.dataset.ws === wsKey);
});
// Animate out
document.getElementById('sidebarContent').classList.add('switching');
document.getElementById('mainContent').classList.add('switching');
setTimeout(() => {
// Update workspace switcher
document.getElementById('wsIcon').style.background = ws.bgColor;
document.getElementById('wsEmoji').textContent = ws.emoji;
document.getElementById('wsName').textContent = ws.name;
document.getElementById('wsDesc').textContent = ws.desc;
// Update nav
document.getElementById('navAllLabel').textContent = ws.allLabel;
document.getElementById('navAllCount').textContent = ws.allCount;
document.getElementById('navEditorLabel').textContent = ws.editorLabel;
document.getElementById('searchInput').placeholder = ws.searchPlaceholder;
// Update main content
document.getElementById('pageTitle').textContent = ws.pageTitle;
document.getElementById('newBtnLabel').textContent = ws.newLabel;
// Render categories
renderCategories(ws.categories);
renderTags(ws.tags);
renderStats(ws.stats);
renderFilters(ws.filters);
renderItems(ws);
renderSessions(ws.sessions);
// Animate in
document.getElementById('sidebarContent').classList.remove('switching');
document.getElementById('mainContent').classList.remove('switching');
// Show toast
showToast(ws.emoji, `Switched to <strong>${ws.name}</strong>`);
}, 200);
}
function renderCategories(cats) {
document.getElementById('categoriesContainer').innerHTML = cats.map(c => `
<div class="category-tag">
<span class="cat-dot" style="background: ${c.color};"></span>
${c.name}
<span class="cat-count">${c.count}</span>
</div>
`).join('');
}
function renderTags(tags) {
document.getElementById('tagsContainer').innerHTML = tags.map(t => `
<span class="filter-chip">${t}</span>
`).join('');
}
function renderStats(stats) {
document.getElementById('statsRow').innerHTML = stats.map(s => `
<div class="stat-card">
<div class="stat-label">${s.label}</div>
<div class="stat-value${s.gradient ? ' gradient' : ''}" ${s.color ? `style="color:${s.color}"` : ''}>${s.value}</div>
<div class="stat-meta">${s.meta}</div>
</div>
`).join('');
}
function renderFilters(filters) {
document.getElementById('filtersRow').innerHTML = filters.map((f, i) => `
<span class="main-filter-chip${i === 0 ? ' active' : ''}">${f}</span>
`).join('') + `
<div class="filter-divider"></div>
<span class="main-filter-chip">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px;"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>
More Filters
</span>
`;
}
function renderItems(ws) {
const dots = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg>';
const header = `
<div class="section-header">
<span class="section-icon bg-gradient"></span>
<span class="section-title">${ws.sectionTitle}</span>
<span class="section-count">${ws.sectionCount || ws.items.length}</span>
</div>
<div class="tree-list-header">
<span></span><span>Name</span><span>Category</span><span style="text-align:center;">Uses</span><span style="text-align:right;">Updated</span><span></span>
</div>
`;
const items = ws.items.map(item => `
<div class="tree-item">
<div class="tree-icon-box" style="background:${item.iconBg};"><span style="color:${item.iconColor};">${item.icon}</span></div>
<div class="tree-info">
<h3>${item.name}</h3>
<div class="tree-meta">
${item.tags.map(t => `<span class="tag">${t}</span>`).join('')}
<span>${item.steps}</span>
</div>
</div>
<div class="tree-category"><span class="cat-indicator" style="background:${item.catColor};"></span> ${item.cat}</div>
<div class="tree-usage">${item.uses}</div>
<div class="tree-updated">${item.updated}</div>
<div class="tree-actions"><button>${dots}</button></div>
</div>
`).join('');
document.getElementById('mainSection').innerHTML = header + `<div class="tree-list">${items}</div>`;
}
function renderSessions(sessions) {
const rows = sessions.map(s => `
<div class="session-row">
<span class="session-status-dot bg-${s.status}"></span>
<span class="session-name">${s.name}</span>
<span class="session-tree">${s.progress}</span>
<span class="session-ticket">${s.ticket}</span>
<span class="session-time">${s.time}</span>
</div>
`).join('');
document.getElementById('sessionsSection').innerHTML = `
<div class="sessions-panel">
<div class="sessions-panel-header">
<h2>Recent Sessions</h2>
<button class="btn btn-secondary" style="padding:5px 12px; font-size:0.75rem;">View All</button>
</div>
${rows}
</div>
`;
}
function showToast(icon, html) {
const toast = document.getElementById('toast');
document.getElementById('toastIcon').textContent = icon;
document.getElementById('toastText').innerHTML = html;
toast.classList.add('show');
setTimeout(() => toast.classList.remove('show'), 2000);
}
// ═══════════════════════════════
// INIT
// ═══════════════════════════════
document.addEventListener('DOMContentLoaded', () => {
const ws = workspaces[currentWs];
renderCategories(ws.categories);
renderTags(ws.tags);
renderStats(ws.stats);
renderFilters(ws.filters);
renderItems(ws);
renderSessions(ws.sessions);
});
// Close dropdown on outside click
document.addEventListener('click', (e) => {
if (dropdownOpen && !e.target.closest('.workspace-switcher')) {
toggleDropdown();
}
});
</script>
</body>
</html>