feat: 添加工作空间侧边栏和文件树功能
- 新增工作空间侧边栏组件,支持展开/关闭和拖动调整宽度 - 实现文件树组件,支持文件夹展开/折叠,显示文件大小和修改时间 - 添加文件预览弹窗,支持文本、Office、图片、视频、音频等多种文件类型 - 实现文件右键菜单,提供下载、重命名、删除操作入口 - 使用 react-icons 图标库替代 emoji,提升视觉一致性 - 优化拖动性能,使用 requestAnimationFrame 确保流畅跟手 - 新增工作空间相关规范文档(workspace-sidebar、file-tree、file-preview)
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
@forward 'search-bar';
|
||||
@forward 'stat-card';
|
||||
@forward 'header';
|
||||
@forward 'workspace';
|
||||
|
||||
.page-back-btn {
|
||||
display: inline-flex;
|
||||
|
||||
344
src/styles/components/workspace/_index.scss
Normal file
344
src/styles/components/workspace/_index.scss
Normal file
@@ -0,0 +1,344 @@
|
||||
// 工作空间组件样式
|
||||
|
||||
@use '../../tokens' as *;
|
||||
|
||||
// 工作空间侧边栏
|
||||
.workspace-sidebar {
|
||||
width: 240px;
|
||||
background: var(--color-bg-2);
|
||||
border-left: 1px solid var(--color-border-2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
flex-shrink: 0;
|
||||
transition: width 0.3s ease, opacity 0.3s ease;
|
||||
position: relative;
|
||||
|
||||
&--collapsed {
|
||||
width: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid var(--color-border-2);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: $font-size-base;
|
||||
font-weight: $font-weight-semibold;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
|
||||
&__close {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
color: var(--color-text-3);
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-bg-1);
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
&__resize-handle {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 12px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: ew-resize;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.2s;
|
||||
z-index: 10;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&__resize-lines {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
div {
|
||||
width: 4px;
|
||||
height: 2px;
|
||||
background: var(--color-text-3);
|
||||
border-radius: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
&__resize-handle:hover &__resize-lines div {
|
||||
background: var(--color-text-1);
|
||||
}
|
||||
}
|
||||
|
||||
// 工作空间展开按钮
|
||||
.workspace-toggle-btn {
|
||||
position: fixed;
|
||||
top: calc(var(--header-height) + 16px);
|
||||
right: 16px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-bg-1);
|
||||
border: 1px solid var(--color-border-3);
|
||||
border-radius: var(--radius-md);
|
||||
cursor: pointer;
|
||||
color: var(--color-text-2);
|
||||
transition: all 0.2s;
|
||||
z-index: 150;
|
||||
box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
|
||||
|
||||
&:hover {
|
||||
background: var(--color-bg-2);
|
||||
color: var(--color-text-1);
|
||||
border-color: var(--color-border-3);
|
||||
}
|
||||
}
|
||||
|
||||
// 文件树
|
||||
.file-tree {
|
||||
&__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
border-radius: var(--radius-sm);
|
||||
margin-bottom: 1px;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-bg-1);
|
||||
}
|
||||
|
||||
&--folder {
|
||||
font-weight: $font-weight-medium;
|
||||
}
|
||||
|
||||
&--file {
|
||||
padding-left: 28px; // 文件缩进
|
||||
}
|
||||
}
|
||||
|
||||
&__toggle {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 2px;
|
||||
color: var(--color-text-3);
|
||||
transition: transform 0.2s;
|
||||
flex-shrink: 0;
|
||||
|
||||
&--expanded {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 6px;
|
||||
flex-shrink: 0;
|
||||
color: var(--color-text-2);
|
||||
}
|
||||
|
||||
&__name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 13px;
|
||||
color: var(--color-text-1);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__size {
|
||||
width: 50px;
|
||||
text-align: right;
|
||||
font-size: 11px;
|
||||
color: var(--color-text-3);
|
||||
margin-left: 6px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__time {
|
||||
width: 40px;
|
||||
font-size: 11px;
|
||||
color: var(--color-text-3);
|
||||
margin-left: 6px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
width: auto;
|
||||
height: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2px 6px;
|
||||
margin-left: 4px;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
color: var(--color-text-3);
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
transition: all 0.2s;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-bg-2);
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
}
|
||||
|
||||
&__children {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 文件预览弹窗
|
||||
.file-preview-modal {
|
||||
&__info {
|
||||
margin-bottom: 16px;
|
||||
padding: 12px;
|
||||
background: var(--color-bg-2);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
&__info-item {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
font-size: $font-size-sm;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__info-label {
|
||||
width: 80px;
|
||||
color: var(--color-text-3);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__info-value {
|
||||
flex: 1;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
|
||||
&__content {
|
||||
margin-bottom: 16px;
|
||||
padding: 16px;
|
||||
background: var(--color-bg-2);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border-2);
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
&__placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 48px 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__placeholder-icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
&__placeholder-text {
|
||||
font-size: $font-size-sm;
|
||||
color: var(--color-text-2);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&__code {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
color: var(--color-text-1);
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
// 文件右键菜单
|
||||
.file-context-menu {
|
||||
position: absolute;
|
||||
background: var(--color-bg-1);
|
||||
border: 1px solid var(--color-border-3);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: 0 4px 16px rgba(15, 23, 42, 0.16);
|
||||
z-index: $z-index-modal;
|
||||
min-width: 140px;
|
||||
padding: 4px 0;
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
font-size: $font-size-sm;
|
||||
color: var(--color-text-1);
|
||||
transition: background 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-bg-2);
|
||||
}
|
||||
|
||||
&--danger {
|
||||
color: var(--color-danger);
|
||||
|
||||
&:hover {
|
||||
background: var(--color-danger-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,14 @@
|
||||
background: var(--color-bg-1);
|
||||
}
|
||||
|
||||
// 聊天主区域(包含内容区和右侧工作空间侧边栏)
|
||||
.chat-main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
// 聊天顶部栏
|
||||
.chat-layout__header,
|
||||
.chat-header {
|
||||
|
||||
Reference in New Issue
Block a user