557 lines
39 KiB
HTML
557 lines
39 KiB
HTML
<!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>
|