agent-Specialization/docs/sidebar_workspace_demo.html

557 lines
39 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Sidebar + Workspace Demo</title>
<style>
:root {
color-scheme: light;
--bg: #ffffff;
--panel-bg: #fbfbfb;
--text: #111111;
--muted: #8f8f8f;
--border: rgba(0, 0, 0, 0.09);
--hover: rgba(0, 0, 0, 0.055);
--hover-strong: rgba(0, 0, 0, 0.095);
--menu-bg: #ffffff;
--menu-shadow: 0 12px 28px rgba(0, 0, 0, 0.14);
--collapsed-width: 52px;
--expanded-width: 306px;
--workspace-width: calc(var(--expanded-width) - var(--collapsed-width));
--icon-cell: 40px;
--row-height: 40px;
--row-radius: 12px;
--anim: 320ms cubic-bezier(0.22, 1, 0.36, 1);
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
:root[data-theme="dark"] {
color-scheme: dark;
--bg: #1a1a1a;
--panel-bg: #0f0f0f;
--text: #f4f4f4;
--muted: #8f8f8f;
--border: rgba(255, 255, 255, 0.105);
--hover: rgba(255, 255, 255, 0.078);
--hover-strong: rgba(255, 255, 255, 0.13);
--menu-bg: #202020;
--menu-shadow: 0 18px 36px rgba(0, 0, 0, 0.42);
}
* { box-sizing: border-box; }
body { margin: 0; height: 100vh; background: var(--bg); color: var(--text); overflow: hidden; }
button, input { font: inherit; }
button { -webkit-tap-highlight-color: transparent; }
.icon {
display: inline-block;
width: var(--icon-size, 20px);
height: var(--icon-size, 20px);
background: currentColor;
mask: var(--icon-url) center / contain no-repeat;
-webkit-mask: var(--icon-url) center / contain no-repeat;
flex: 0 0 auto;
}
.icon-chat { --icon-url: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2032%2032%22%20fill=%22none%22%20stroke=%22currentColor%22%20stroke-width=%222.2%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22%3E%0A%20%20%3Cpath%20d=%22M6%207c0-2%201.6-3.6%203.6-3.6h13c2%200%203.6%201.6%203.6%203.6v10c0%202-1.6%203.6-3.6%203.6h-6.2L12.4%2025l0.7-4.4H9.6c-2%200-3.6-1.6-3.6-3.6V7Z%22%20/%3E%0A%20%20%3Cpath%20d=%22M10.4%2011h11.2%22%20/%3E%0A%20%20%3Cpath%20d=%22M10.4%2015h7.2%22%20/%3E%0A%3C/svg%3E"); --icon-size: 29px; }
.icon-pencil { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M21.174%206.812a1%201%200%200%200-3.986-3.987L3.842%2016.174a2%202%200%200%200-.5.83l-1.321%204.352a.5.5%200%200%200%20.623.622l4.353-1.32a2%202%200%200%200%20.83-.497z%22%20/%3E%0A%20%20%3Cpath%20d=%22m15%205%204%204%22%20/%3E%0A%3C/svg%3E"); --icon-size: 22px; }
.icon-layers { --icon-url: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2024%2024%22%20width=%2248%22%20height=%2248%22%20fill=%22none%22%20stroke=%22#000000%22%20stroke-width=%222%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22%20style=%22opacity:1;%22%3E%3Cpath%20d=%22M12.83%202.18a2%202%200%200%200-1.66%200L2.6%206.08a1%201%200%200%200%200%201.83l8.58%203.91a2%202%200%200%200%201.66%200l8.58-3.9a1%201%200%200%200%200-1.83z%22/%3E%3Cpath%20d=%22M2%2012a1%201%200%200%200%20.58.91l8.6%203.91a2%202%200%200%200%201.65%200l8.58-3.9A1%201%200%200%200%2022%2012%22/%3E%3Cpath%20d=%22M2%2017a1%201%200%200%200%20.58.91l8.6%203.91a2%202%200%200%200%201.65%200l8.58-3.9A1%201%200%200%200%2022%2017%22/%3E%3C/svg%3E"); --icon-size: 23px; }
.icon-monitor { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Crect%20width=%2220%22%20height=%2214%22%20x=%222%22%20y=%223%22%20rx=%222%22%20/%3E%0A%20%20%3Cline%20x1=%228%22%20x2=%2216%22%20y1=%2221%22%20y2=%2221%22%20/%3E%0A%20%20%3Cline%20x1=%2212%22%20x2=%2212%22%20y1=%2217%22%20y2=%2221%22%20/%3E%0A%3C/svg%3E"); --icon-size: 23px; }
.icon-search { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22m21%2021-4.34-4.34%22%20/%3E%0A%20%20%3Ccircle%20cx=%2211%22%20cy=%2211%22%20r=%228%22%20/%3E%0A%3C/svg%3E"); --icon-size: 22px; }
.icon-user { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M19%2021v-2a4%204%200%200%200-4-4H9a4%204%200%200%200-4%204v2%22%20/%3E%0A%20%20%3Ccircle%20cx=%2212%22%20cy=%227%22%20r=%224%22%20/%3E%0A%3C/svg%3E"); --icon-size: 22px; }
.icon-folder { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M20%2020a2%202%200%200%200%202-2V8a2%202%200%200%200-2-2h-7.9a2%202%200%200%201-1.69-.9L9.6%203.9A2%202%200%200%200%207.93%203H4a2%202%200%200%200-2%202v13a2%202%200%200%200%202%202Z%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
.icon-folder-open { --icon-url: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2024%2024%22%20width=%2248%22%20height=%2248%22%20fill=%22none%22%20stroke=%22#000000%22%20stroke-width=%222%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22%20style=%22opacity:1;%22%3E%3Cpath%20%20%20%20%20%20d=%22m6%2014l1.5-2.9A2%202%200%200%201%209.24%2010H20a2%202%200%200%201%201.94%202.5l-1.54%206a2%202%200%200%201-1.95%201.5H4a2%202%200%200%201-2-2V5a2%202%200%200%201%202-2h3.9a2%202%200%200%201%201.69.9l.81%201.2a2%202%200%200%200%201.67.9H18a2%202%200%200%201%202%202v2%22/%3E%3C/svg%3E"); --icon-size: 18px; }
.icon-file { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M6%2022a2%202%200%200%201-2-2V4a2%202%200%200%201%202-2h8a2.4%202.4%200%200%201%201.704.706l3.588%203.588A2.4%202.4%200%200%201%2020%208v12a2%202%200%200%201-2%202z%22%20/%3E%0A%20%20%3Cpath%20d=%22M14%202v5a1%201%200%200%200%201%201h5%22%20/%3E%0A%3C/svg%3E"); --icon-size: 17px; }
.icon-bot { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M12%208V4H8%22%20/%3E%0A%20%20%3Crect%20width=%2216%22%20height=%2212%22%20x=%224%22%20y=%228%22%20rx=%222%22%20/%3E%0A%20%20%3Cpath%20d=%22M2%2014h2%22%20/%3E%0A%20%20%3Cpath%20d=%22M20%2014h2%22%20/%3E%0A%20%20%3Cpath%20d=%22M15%2013v2%22%20/%3E%0A%20%20%3Cpath%20d=%22M9%2013v2%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
.icon-terminal { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M12%2019h8%22%20/%3E%0A%20%20%3Cpath%20d=%22m4%2017%206-6-6-6%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
.icon-sticky { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M21%209a2.4%202.4%200%200%200-.706-1.706l-3.588-3.588A2.4%202.4%200%200%200%2015%203H5a2%202%200%200%200-2%202v14a2%202%200%200%200%202%202h14a2%202%200%200%200%202-2z%22%20/%3E%0A%20%20%3Cpath%20d=%22M15%203v5a1%201%200%200%200%201%201h5%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
.icon-check { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M20%206%209%2017l-5-5%22%20/%3E%0A%3C/svg%3E"); --icon-size: 17px; }
.icon-clock { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Ccircle%20cx=%2212%22%20cy=%2212%22%20r=%229%22%20/%3E%0A%20%20%3Cpath%20d=%22M12%207v5l3%203%22%20/%3E%0A%3C/svg%3E"); --icon-size: 17px; }
.icon-laptop { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M18%205a2%202%200%200%201%202%202v8.526a2%202%200%200%200%20.212.897l1.068%202.127a1%201%200%200%201-.9%201.45H3.62a1%201%200%200%201-.9-1.45l1.068-2.127A2%202%200%200%200%204%2015.526V7a2%202%200%200%201%202-2z%22%20/%3E%0A%20%20%3Cpath%20d=%22M20.054%2015.987H3.946%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
.icon-settings { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M9.671%204.136a2.34%202.34%200%200%201%204.659%200%202.34%202.34%200%200%200%203.319%201.915%202.34%202.34%200%200%201%202.33%204.033%202.34%202.34%200%200%200%200%203.831%202.34%202.34%200%200%201-2.33%204.033%202.34%202.34%200%200%200-3.319%201.915%202.34%202.34%200%200%201-4.659%200%202.34%202.34%200%200%200-3.32-1.915%202.34%202.34%200%200%201-2.33-4.033%202.34%202.34%200%200%200%200-3.831A2.34%202.34%200%200%201%206.35%206.051a2.34%202.34%200%200%200%203.319-1.915%22%20/%3E%0A%20%20%3Ccircle%20cx=%2212%22%20cy=%2212%22%20r=%223%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
.icon-trash { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M19%206v14a2%202%200%200%201-2%202H7a2%202%200%200%201-2-2V6%22%20/%3E%0A%20%20%3Cpath%20d=%22M3%206h18%22%20/%3E%0A%20%20%3Cpath%20d=%22M8%206V4a2%202%200%200%201%202-2h4a2%202%200%200%201%202%202v2%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
.icon-copy { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Crect%20width=%228%22%20height=%224%22%20x=%228%22%20y=%222%22%20rx=%221%22%20ry=%221%22%20/%3E%0A%20%20%3Cpath%20d=%22M16%204h2a2%202%200%200%201%202%202v14a2%202%200%200%201-2%202H6a2%202%200%200%201-2-2V6a2%202%200%200%201%202-2h2%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
.icon-sun { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M11.017%202.814a1%201%200%200%201%201.966%200l1.051%205.558a2%202%200%200%200%201.594%201.594l5.558%201.051a1%201%200%200%201%200%201.966l-5.558%201.051a2%202%200%200%200-1.594%201.594l-1.051%205.558a1%201%200%200%201-1.966%200l-1.051-5.558a2%202%200%200%200-1.594-1.594l-5.558-1.051a1%201%200%200%201%200-1.966l5.558-1.051a2%202%200%200%200%201.594-1.594z%22%20/%3E%0A%20%20%3Cpath%20d=%22M20%202v4%22%20/%3E%0A%20%20%3Cpath%20d=%22M22%204h-4%22%20/%3E%0A%20%20%3Ccircle%20cx=%224%22%20cy=%2220%22%20r=%222%22%20/%3E%0A%3C/svg%3E"); --icon-size: 22px; }
.app { position: relative; height: 100vh; background: var(--bg); }
.main { min-width: 0; height: 100vh; margin-left: var(--expanded-width); display: flex; align-items: flex-start; justify-content: center; padding: 28px 32px; }
.main-title { margin: 0; font-size: 34px; line-height: 1.1; font-weight: 620; letter-spacing: -0.04em; }
.main-title span { color: var(--muted); font-weight: 430; }
/* 工作区:窄、扁平、无大卡片嵌套。展开的对话栏会完整盖住它。 */
.workspace-panel {
position: fixed;
left: var(--collapsed-width);
top: 0;
z-index: 20;
width: var(--workspace-width);
height: 100vh;
background: var(--panel-bg);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
padding: 18px 10px 14px;
overflow: hidden;
transition: background 160ms ease, border-color 160ms ease;
}
.workspace-title {
height: 40px;
margin: 0;
display: flex;
align-items: center;
padding: 0 0 0 16px;
font-size: 18px;
font-weight: 660;
letter-spacing: -0.035em;
white-space: nowrap;
}
.workspace-controls {
display: grid;
grid-template-columns: minmax(0, 1fr) 40px;
gap: 4px;
margin: 4px 0 10px;
}
.workspace-switch,
.workspace-manage {
height: 40px;
border: 0;
border-radius: 12px;
background: transparent;
color: var(--text);
cursor: pointer;
transition: background 140ms ease, color 140ms ease;
}
.workspace-switch:hover,
.workspace-manage:hover { background: var(--hover); }
.workspace-switch {
min-width: 0;
display: grid;
grid-template-columns: 32px minmax(0, 1fr) 18px;
align-items: center;
padding: 0 10px 0 8px;
text-align: left;
font-size: 14px;
letter-spacing: -0.012em;
}
.workspace-switch .icon { justify-self: center; color: var(--text); }
.workspace-switch-label { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chevron { width: 8px; height: 8px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg) translateY(-2px); opacity: .55; justify-self: center; }
.workspace-manage { display: grid; place-items: center; color: var(--text); }
.workspace-body { min-height: 0; flex: 1 1 auto; overflow: hidden; display: flex; flex-direction: column; }
.workspace-view { display: none; min-height: 0; flex: 1 1 auto; overflow-y: auto; scrollbar-width: thin; padding-top: 2px; }
.workspace-view.active { display: block; }
.content-row {
width: 100%;
height: 36px;
border-radius: 10px;
display: grid;
align-items: center;
color: var(--text);
font-size: 13px;
letter-spacing: -0.01em;
overflow: hidden;
}
.content-row + .content-row { margin-top: 1px; }
.content-main { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.content-meta { color: var(--muted); font-size: 12px; white-space: nowrap; }
/* 文件树是真实可操作树:保留文件/文件夹图标和 hover其他内容区不做按钮感。 */
.file-row {
grid-template-columns: 20px 20px minmax(0, 1fr) auto;
gap: 4px;
padding: 0 8px 0 2px;
cursor: pointer;
transition: background 140ms ease;
}
.file-row:hover { background: var(--hover); }
.file-row .icon { color: var(--muted); justify-self: center; }
.file-arrow { width: 16px; text-align: center; color: var(--muted); font-size: 11px; }
.file-row.depth-1 { padding-left: 16px; }
.file-row.depth-2 { padding-left: 30px; }
.plain-row {
grid-template-columns: minmax(0, 1fr) auto;
gap: 8px;
padding: 0 10px;
cursor: default;
}
.option-row {
height: 44px;
grid-template-columns: 20px minmax(0, 1fr) auto;
gap: 8px;
padding: 0 10px 0 8px;
cursor: pointer;
transition: background 140ms ease, color 140ms ease;
}
.option-row:hover { background: var(--hover); }
.option-row.selected { background: var(--hover); }
.option-marker {
width: 13px;
height: 13px;
border-radius: 999px;
border: 1.5px solid var(--muted);
justify-self: center;
position: relative;
opacity: .85;
}
.option-row.selected .option-marker {
border-color: var(--text);
opacity: 1;
}
.option-row.selected .option-marker::after {
content: '';
position: absolute;
inset: 3px;
border-radius: inherit;
background: var(--text);
}
.host-copy { min-width: 0; display: grid; grid-template-rows: 18px 16px; }
.host-label { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 13px; font-weight: 560; }
.host-path { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--muted); font-size: 12px; }
.host-badges { display: inline-flex; gap: 4px; align-items: center; }
.host-badge { color: var(--muted); font-size: 11px; }
.todo-instruction {
margin-top: 8px;
padding: 0 10px;
color: var(--muted);
font-size: 12px;
line-height: 1.35;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.empty-row {
height: 36px;
display: flex;
align-items: center;
padding: 0 10px;
color: var(--muted);
font-size: 13px;
}
/* 侧边栏:同一张完整侧边栏被裁切暴露。 */
.sidebar-frame {
position: fixed;
left: 0;
top: 0;
z-index: 50;
width: var(--collapsed-width);
height: 100vh;
overflow: hidden;
background: var(--panel-bg);
border-right: 1px solid var(--border);
transition: width var(--anim), background 160ms ease, border-color 160ms ease;
will-change: width;
}
.sidebar-frame.open { width: var(--expanded-width); }
.sidebar-content { width: var(--expanded-width); height: 100%; background: var(--panel-bg); display: flex; flex-direction: column; padding: 18px 8px 14px 6px; transition: background 160ms ease; }
.sidebar-top { display: flex; flex-direction: column; gap: 2px; flex: 0 0 auto; }
.sidebar-bottom { margin-top: 8px; flex: 0 0 auto; }
.side-row,
.search-shell,
.conversation-row { width: 100%; min-height: var(--row-height); border: 0; border-radius: var(--row-radius); background: transparent; color: var(--text); display: grid; grid-template-columns: var(--icon-cell) minmax(0, 1fr); align-items: center; padding: 0; text-align: left; }
.side-row,
.conversation-row { cursor: pointer; transition: background 140ms ease, color 140ms ease; }
.side-row:hover,
.conversation-row:hover { background: transparent; }
.side-icon { width: var(--icon-cell); height: var(--row-height); border-radius: var(--row-radius); display: grid; place-items: center; color: currentColor; flex: 0 0 auto; transition: background 140ms ease; }
.sidebar-frame:not(.open) .side-row:hover .side-icon,
.sidebar-frame:not(.open) .theme-toggle:hover .side-icon { background: var(--hover); }
.sidebar-frame.open .side-row:hover,
.sidebar-frame.open .side-row.active,
.sidebar-frame.open .conversation-row:hover,
.sidebar-frame.open .conversation-row.menu-open { background: var(--hover); }
.side-label,
.search-area,
.conversation-list,
.conversation-title,
.conversation-more { opacity: 0; transition: opacity 220ms ease; transition-delay: 0ms; }
.sidebar-frame.open .side-label,
.sidebar-frame.open .search-area,
.sidebar-frame.open .conversation-list,
.sidebar-frame.open .conversation-title,
.sidebar-frame.open .conversation-more { opacity: 1; transition-delay: 80ms; }
.side-label { min-width: 0; padding-left: 8px; padding-right: 12px; font-size: 15px; line-height: 1; letter-spacing: -0.015em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.search-area { flex: 0 0 auto; margin-top: 10px; }
.search-shell { height: var(--row-height); overflow: hidden; transition: background 140ms ease; }
.search-shell:focus-within,
.search-shell:hover { background: var(--hover); }
.search-input { min-width: 0; width: calc(var(--expanded-width) - var(--icon-cell) - 22px); height: var(--row-height); border: 0; outline: 0; padding: 0 12px 0 8px; background: transparent; color: var(--text); font-size: 14px; letter-spacing: -0.01em; }
.search-input::placeholder { color: var(--muted); }
.conversation-list { min-height: 0; flex: 1 1 auto; overflow-y: auto; padding-top: 12px; padding-right: 0; scrollbar-width: thin; }
.conversation-row { position: relative; grid-template-columns: minmax(0, 1fr) 40px; min-height: var(--row-height); margin: 0; }
.conversation-title { min-width: 0; padding-left: 12px; padding-right: 4px; color: var(--text); font-size: 14px; line-height: 1.25; letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.conversation-more { width: 30px; height: 30px; border: 0; border-radius: 9px; background: transparent; color: var(--muted); display: grid; place-items: center; cursor: pointer; justify-self: start; visibility: hidden; transition: color 140ms ease, opacity 160ms ease; }
.conversation-row:hover .conversation-more,
.conversation-row.menu-open .conversation-more { visibility: visible; }
.conversation-more:hover,
.conversation-row.menu-open .conversation-more { background: transparent; color: var(--text); }
.more-dots {
position: relative;
display: inline-block;
width: 22px;
height: 22px;
}
.more-dots::before {
content: '';
position: absolute;
left: 4px;
top: 10px;
width: 3.5px;
height: 3.5px;
border-radius: 999px;
background: currentColor;
box-shadow: 5.5px 0 0 currentColor, 11px 0 0 currentColor;
}
.floating-menu {
position: fixed;
z-index: 80;
width: max-content;
min-width: 92px;
padding: 6px;
border: 1px solid var(--border);
border-radius: 14px;
background: var(--menu-bg);
box-shadow: var(--menu-shadow);
opacity: 0;
transform: translateY(-4px) scale(0.98);
pointer-events: none;
transition: opacity 120ms ease, transform 150ms cubic-bezier(0.22, 1, 0.36, 1), background 160ms ease, border-color 160ms ease;
}
.floating-menu.open { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
.menu-button { width: max-content; min-width: 80px; height: 36px; border: 0; border-radius: 10px; background: transparent; color: var(--text); display: grid; grid-template-columns: 24px auto; gap: 4px; align-items: center; padding: 0 10px 0 8px; text-align: left; cursor: pointer; font-size: 14px; letter-spacing: -0.01em; transition: background 140ms ease; }
.menu-button:hover { background: var(--hover); }
.menu-button.danger { color: #d6483b; }
:root[data-theme="dark"] .menu-button.danger { color: #ff7b72; }
.demo-hint { position: fixed; left: calc(var(--expanded-width) + 20px); bottom: 18px; color: var(--muted); font-size: 13px; pointer-events: none; }
</style>
</head>
<body>
<div class="app">
<aside class="workspace-panel" aria-label="工作区">
<h2 class="workspace-title" id="workspaceTitle">工作区</h2>
<div class="workspace-controls">
<button class="workspace-switch" id="workspaceSwitch" type="button" aria-haspopup="menu" aria-expanded="false">
<span class="icon icon-folder-open" id="workspaceSwitchIcon" aria-hidden="true"></span>
<span class="workspace-switch-label" id="workspaceSwitchLabel">工作区文件</span>
<span class="chevron" aria-hidden="true"></span>
</button>
<button class="workspace-manage" type="button" aria-label="管理工作区">
<span class="icon icon-folder" aria-hidden="true"></span>
</button>
</div>
<div class="workspace-body">
<div class="workspace-view active" data-view="files">
<div class="content-row file-row"><span class="file-arrow"></span><span class="icon icon-folder-open"></span><span class="content-main">static</span><span class="content-meta"></span></div>
<div class="content-row file-row depth-1"><span class="file-arrow"></span><span class="icon icon-file"></span><span class="content-main">App.vue</span><span class="content-meta"></span></div>
<div class="content-row file-row depth-1"><span class="file-arrow"></span><span class="icon icon-folder-open"></span><span class="content-main">components</span><span class="content-meta"></span></div>
<div class="content-row file-row depth-2"><span class="file-arrow"></span><span class="icon icon-file"></span><span class="content-main">ConversationSidebar.vue</span><span class="content-meta"></span></div>
<div class="content-row file-row depth-2"><span class="file-arrow"></span><span class="icon icon-file"></span><span class="content-main">LeftPanel.vue</span><span class="content-meta"></span></div>
<div class="content-row file-row"><span class="file-arrow"></span><span class="icon icon-folder"></span><span class="content-main">server</span><span class="content-meta"></span></div>
<div class="content-row file-row"><span class="file-arrow"></span><span class="icon icon-file"></span><span class="content-main">main.py</span><span class="content-meta"></span></div>
</div>
<div class="workspace-view" data-view="host">
<div class="content-row option-row selected"><span class="option-marker" aria-hidden="true"></span><span class="host-copy"><span class="host-label">agents</span><span class="host-path">/Users/jojo/Desktop/agents/正在修复中/agents</span></span><span class="host-badges"><span class="host-badge">默认</span><span class="host-badge">当前</span></span></div>
<div class="content-row option-row"><span class="option-marker" aria-hidden="true"></span><span class="host-copy"><span class="host-label">前端工作区</span><span class="host-path">/Users/jojo/Desktop/frontend</span></span><span class="host-badges"></span></div>
<div class="content-row option-row"><span class="option-marker" aria-hidden="true"></span><span class="host-copy"><span class="host-label">未配置路径</span><span class="host-path">(未配置路径)</span></span><span class="host-badges"></span></div>
</div>
<div class="workspace-view" data-view="agents">
<div class="content-row plain-row"><span class="content-main">#1 正在整理侧边栏与工作区样式</span><span class="content-meta">running</span></div>
<div class="content-row plain-row"><span class="content-main">#2 等待下一轮验证</span><span class="content-meta">idle</span></div>
<div class="content-row plain-row"><span class="content-main">当前read_file</span><span class="content-meta"></span></div>
</div>
<div class="workspace-view" data-view="commands">
<div class="content-row plain-row"><span class="content-main">npm --prefix cli run typecheck</span><span class="content-meta">completed</span></div>
<div class="content-row plain-row"><span class="content-main">python -m unittest test.test_server_refactor_smoke</span><span class="content-meta">running</span></div>
<div class="content-row plain-row"><span class="content-main">状态码:--</span><span class="content-meta"></span></div>
</div>
<div class="workspace-view" data-view="todos">
<div class="content-row plain-row"><span class="content-main">task1确定侧边栏动画模型</span><span class="content-meta">完成</span></div>
<div class="content-row plain-row"><span class="content-main">task2工作区视觉改造</span><span class="content-meta">未完成</span></div>
<div class="content-row plain-row"><span class="content-main">task3代码块精致化</span><span class="content-meta">未完成</span></div>
<div class="todo-instruction">指令:按真实数据结构设计显示区域,不添加额外说明卡片。</div>
</div>
</div>
</aside>
<aside class="sidebar-frame" id="sidebar" aria-label="对话侧边栏">
<div class="sidebar-content">
<div class="sidebar-top">
<button class="side-row" id="toggleSidebar" type="button" aria-label="展开对话记录" aria-expanded="false">
<span class="side-icon"><span class="icon icon-chat" aria-hidden="true"></span></span>
<span class="side-label">对话记录</span>
</button>
<button class="side-row" type="button" aria-label="新建对话"><span class="side-icon"><span class="icon icon-pencil"></span></span><span class="side-label">新建对话</span></button>
<button class="side-row" type="button" aria-label="工作区"><span class="side-icon"><span class="icon icon-layers"></span></span><span class="side-label">工作区</span></button>
<button class="side-row" type="button" aria-label="虚拟显示器"><span class="side-icon"><span class="icon icon-monitor"></span></span><span class="side-label">虚拟显示器</span></button>
</div>
<div class="search-area" aria-label="搜索对话"><label class="search-shell"><span class="side-icon"><span class="icon icon-search"></span></span><input class="search-input" type="search" placeholder="搜索对话" /></label></div>
<div class="conversation-list" aria-label="对话记录">
<div class="conversation-row"><span class="conversation-title">随意的 py 代码块</span><button class="conversation-more" type="button" aria-label="更多操作"><span class="more-dots" aria-hidden="true"></span></button></div>
<div class="conversation-row"><span class="conversation-title">前端现代化设计讨论</span><button class="conversation-more" type="button" aria-label="更多操作"><span class="more-dots" aria-hidden="true"></span></button></div>
<div class="conversation-row"><span class="conversation-title">审批面板覆盖窗口方案</span><button class="conversation-more" type="button" aria-label="更多操作"><span class="more-dots" aria-hidden="true"></span></button></div>
<div class="conversation-row"><span class="conversation-title">CLI 显示层细节修复</span><button class="conversation-more" type="button" aria-label="更多操作"><span class="more-dots" aria-hidden="true"></span></button></div>
<div class="conversation-row"><span class="conversation-title">个人空间设置页重设计</span><button class="conversation-more" type="button" aria-label="更多操作"><span class="more-dots" aria-hidden="true"></span></button></div>
</div>
<div class="sidebar-bottom">
<button class="side-row theme-toggle" id="themeToggle" type="button" aria-label="切换深色模式"><span class="side-icon"><span class="icon icon-sun"></span></span><span class="side-label">浅色模式</span></button>
<button class="side-row" type="button" aria-label="个人空间"><span class="side-icon"><span class="icon icon-user"></span></span><span class="side-label">个人空间</span></button>
</div>
</div>
</aside>
<main class="main"><h1 class="main-title">AI Agent <span>Auto</span></h1></main>
<div class="floating-menu" id="conversationMenu" role="menu" aria-hidden="true">
<button class="menu-button" type="button" role="menuitem"><span class="icon icon-copy"></span><span>复制</span></button>
<button class="menu-button danger" type="button" role="menuitem"><span class="icon icon-trash"></span><span>删除</span></button>
</div>
<div class="floating-menu" id="workspaceMenu" role="menu" aria-hidden="true">
<button class="menu-button" type="button" data-view-target="files"><span class="icon icon-folder-open"></span><span>工作区文件</span></button>
<button class="menu-button" type="button" data-view-target="host"><span class="icon icon-laptop"></span><span>宿主机工作区</span></button>
<button class="menu-button" type="button" data-view-target="agents"><span class="icon icon-bot"></span><span>子智能体</span></button>
<button class="menu-button" type="button" data-view-target="commands"><span class="icon icon-terminal"></span><span>后台指令</span></button>
<button class="menu-button" type="button" data-view-target="todos"><span class="icon icon-sticky"></span><span>待办事项</span></button>
</div>
</div>
<div class="demo-hint">工作区为扁平窄面板;展开侧边栏会完整盖住工作区。</div>
<script>
const sidebar = document.getElementById('sidebar');
const toggle = document.getElementById('toggleSidebar');
const themeToggle = document.getElementById('themeToggle');
const conversationMenu = document.getElementById('conversationMenu');
const workspaceMenu = document.getElementById('workspaceMenu');
const workspaceSwitch = document.getElementById('workspaceSwitch');
const workspaceTitle = document.getElementById('workspaceTitle');
const workspaceSwitchLabel = document.getElementById('workspaceSwitchLabel');
const workspaceSwitchIcon = document.getElementById('workspaceSwitchIcon');
let conversationOwner = null;
const viewMeta = {
files: { title: '工作区', label: '工作区文件', icon: 'icon-folder-open' },
host: { title: '宿主机工作区', label: '宿主机工作区', icon: 'icon-laptop' },
agents: { title: '子智能体', label: '子智能体', icon: 'icon-bot' },
commands: { title: '后台指令', label: '后台指令', icon: 'icon-terminal' },
todos: { title: '待办事项', label: '待办事项', icon: 'icon-sticky' }
};
toggle.addEventListener('click', () => {
const isOpen = sidebar.classList.toggle('open');
toggle.setAttribute('aria-expanded', String(isOpen));
toggle.setAttribute('aria-label', isOpen ? '收起对话记录' : '展开对话记录');
if (!isOpen) closeConversationMenu();
});
themeToggle.addEventListener('click', () => {
const root = document.documentElement;
const next = root.dataset.theme === 'dark' ? 'light' : 'dark';
root.dataset.theme = next;
themeToggle.querySelector('.side-label').textContent = next === 'dark' ? '深色模式' : '浅色模式';
});
function positionMenu(menu, anchor) {
const rect = anchor.getBoundingClientRect();
menu.style.left = '0px';
menu.style.top = `${rect.bottom + 6}px`;
menu.classList.add('open');
menu.setAttribute('aria-hidden', 'false');
const width = menu.offsetWidth;
menu.style.left = `${Math.min(rect.right - width, window.innerWidth - width - 12)}px`;
}
function closeConversationMenu() {
conversationMenu.classList.remove('open');
conversationMenu.setAttribute('aria-hidden', 'true');
if (conversationOwner) conversationOwner.classList.remove('menu-open');
conversationOwner = null;
}
function closeWorkspaceMenu() {
workspaceMenu.classList.remove('open');
workspaceMenu.setAttribute('aria-hidden', 'true');
workspaceSwitch.setAttribute('aria-expanded', 'false');
}
document.querySelectorAll('.conversation-more').forEach((button) => {
button.addEventListener('click', (event) => {
event.stopPropagation();
closeWorkspaceMenu();
const row = button.closest('.conversation-row');
if (conversationOwner === row && conversationMenu.classList.contains('open')) {
closeConversationMenu();
return;
}
closeConversationMenu();
conversationOwner = row;
row.classList.add('menu-open');
positionMenu(conversationMenu, button);
});
});
workspaceSwitch.addEventListener('click', (event) => {
event.stopPropagation();
closeConversationMenu();
if (workspaceMenu.classList.contains('open')) {
closeWorkspaceMenu();
} else {
workspaceSwitch.setAttribute('aria-expanded', 'true');
positionMenu(workspaceMenu, workspaceSwitch);
}
});
workspaceMenu.querySelectorAll('[data-view-target]').forEach((button) => {
button.addEventListener('click', () => {
const view = button.dataset.viewTarget;
document.querySelectorAll('.workspace-view').forEach((node) => node.classList.toggle('active', node.dataset.view === view));
const meta = viewMeta[view];
workspaceTitle.textContent = meta.title;
workspaceSwitchLabel.textContent = meta.label;
workspaceSwitchIcon.className = `icon ${meta.icon}`;
closeWorkspaceMenu();
});
});
document.addEventListener('click', (event) => {
if (!conversationMenu.contains(event.target)) closeConversationMenu();
if (!workspaceMenu.contains(event.target) && !workspaceSwitch.contains(event.target)) closeWorkspaceMenu();
});
window.addEventListener('resize', () => {
closeConversationMenu();
closeWorkspaceMenu();
});
</script>
</body>
</html>