style: balance floating toolbar spacing and groups
This commit is contained in:
@@ -102,3 +102,5 @@ API 测试使用本机临时后端和独立前端进程,检查会话 Cookie、
|
||||
## 图谱改名
|
||||
|
||||
左上角标题第一次点击选中,选中后再次点击进入编辑;回车或失焦保存,Esc 取消,F2 也可直接编辑。真实图谱改名先读取最新资料和版本,再携带 If-Match 更新名称,保留描述与内容;版本冲突时提示重试。演示模式保存到本地。保存后标题、侧栏列表及导出文件名同步更新。
|
||||
|
||||
左上和底部工具栏按右上视图控件的分组节奏增加横向留白(间隙 6px、横向内边距 6px),按钮仍为 32×32px,竖向内边距仍为 4px。三处分隔线统一;左侧标题不再额外叠加外边距,右上现有样式保持不变。
|
||||
|
||||
@@ -102,3 +102,9 @@
|
||||
- 类型检查和 16 项画布/工作空间测试通过,新增原内容保留、名称校验和版本冲突不重试的检查。
|
||||
- 按既定约定不访问浏览器,未进行实际点击与输入法交互验收。
|
||||
- 隔离 Webpack 生产构建和完整 API 冒烟检查通过;新增改名 PATCH/If-Match、204 响应、重新读取名称和内容保留检查通过。
|
||||
|
||||
## 参照右上控件调整分组留白(2026-11-06)
|
||||
|
||||
- 右上现有尺寸和间距保持不变;左上与底部采用稍宽的 6px 横向间隙和横向内边距,保持 4px 竖向内边距与 32×32px 按钮。
|
||||
- 左上在标题前后增加与右上相同的分隔线,去掉标题额外外边距;三处分隔线改为共享样式。
|
||||
- 类型检查和差异检查通过;本次 CSS 留白试调未重复生产构建或访问浏览器。
|
||||
|
||||
@@ -162,7 +162,7 @@ export default function DashboardSidebar() {
|
||||
<>
|
||||
<AnimatePresence initial={false}>
|
||||
{collapsed && (
|
||||
<motion.div key="sidebar-controls" className={`${toolbar.surface} ${styles.floating}`} aria-label="侧边栏快捷操作"
|
||||
<motion.div key="sidebar-controls" className={`${toolbar.surface} ${toolbar.relaxed} ${styles.floating}`} aria-label="侧边栏快捷操作"
|
||||
initial={{ opacity: 0, y: reduceMotion ? 0 : -6 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: reduceMotion ? 0 : -6 }}
|
||||
@@ -173,9 +173,11 @@ export default function DashboardSidebar() {
|
||||
srcSet="/brand/png/logo-light/endoleap-32.png 1x, /brand/png/logo-light/endoleap-64.png 2x, /brand/png/logo-light/endoleap-128.png 4x"
|
||||
width={20} height={20} alt="" />
|
||||
</Link>
|
||||
<span className={toolbar.divider} aria-hidden="true" />
|
||||
<EditableTitle key={workspace + ":" + (params.board || "home")} title={currentTitle}
|
||||
editable={Boolean(params.board && activeBoard?.id === params.board && activeBoard.workspace_id === workspace && canCreate)}
|
||||
onSave={renameTitle} className={styles.floatingTitle} />
|
||||
<span className={toolbar.divider} aria-hidden="true" />
|
||||
<button type="button" className={styles.floatingAvatarButton} popoverTarget="workspace-account" aria-label="账户和工作空间">
|
||||
<UserAvatar name={name} url={profile?.avatar_url} />
|
||||
</button>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
.node :global(.react-flow__handle) { width: 8px; height: 8px; background: #a47764; border: 2px solid #fff; }
|
||||
.toolbar button[aria-pressed="true"] { background: #f1e6df; color: #78523f; }
|
||||
.toolbar button:disabled { cursor: not-allowed; }
|
||||
.divider { flex: 0 0 1px; width: 1px; height: 16px; margin: 0 2px; background: #ece6df; }
|
||||
.topRight { position: absolute; top: 12px; right: 12px; z-index: 10; display: flex; flex-direction: column; align-items: flex-end; gap: 3px; }
|
||||
.toolbar .zoomValue { box-sizing: border-box; flex: 0 0 48px; width: 48px; height: var(--toolbar-control-height, 32px); padding: 0; border-radius: 5px; font: inherit; font-variant-numeric: tabular-nums; }
|
||||
.toolbar .zoomValue:hover { background: #e9e7e3; }
|
||||
|
||||
@@ -172,25 +172,25 @@ function CanvasEditor({ board }: { board: Board }) {
|
||||
<div className={`${toolbar.surface} ${styles.toolbar}`} role="toolbar" aria-label="图谱视图控制">
|
||||
<IconButton icon={Undo2} label="撤销" disabled={!state.past.length} onClick={() => dispatch({ type: "undo" })} />
|
||||
<IconButton icon={Redo2} label="重做" disabled={!state.future.length} onClick={() => dispatch({ type: "redo" })} />
|
||||
<span className={styles.divider} />
|
||||
<span className={toolbar.divider} aria-hidden="true" />
|
||||
<IconButton icon={Minus} label="缩小" onClick={() => void flow.zoomOut({ duration })} />
|
||||
<button className={styles.zoomValue} onClick={() => void flow.zoomTo(1, { duration })} title="恢复 100% 缩放">{Math.round(zoom * 100)}%</button>
|
||||
<IconButton icon={Plus} label="放大" onClick={() => void flow.zoomIn({ duration })} />
|
||||
<IconButton icon={Maximize} label="适应画布" onClick={() => nodes.length ? void flow.fitView({ padding: 0.2, duration }) : void flow.setViewport({ x: 0, y: 0, zoom: 1 }, { duration })} />
|
||||
<span className={styles.divider} />
|
||||
<span className={toolbar.divider} aria-hidden="true" />
|
||||
<IconButton icon={Download} label="导出图谱" onClick={exportProject} />
|
||||
</div>
|
||||
<span className={styles.saveStatus} role="status">{saved ? "保存在此浏览器" : "正在保存到此浏览器…"}</span>
|
||||
</div>
|
||||
<div className={`${toolbar.surface} ${styles.toolbar} ${styles.bottomToolbar}`} role="toolbar" aria-label="画布创作工具">
|
||||
<div className={`${toolbar.surface} ${toolbar.relaxed} ${styles.toolbar} ${styles.bottomToolbar}`} role="toolbar" aria-label="画布创作工具">
|
||||
<IconButton icon={MousePointer2} label="选择工具(V)" aria-pressed={tool === "select"} onClick={() => setTool("select")} />
|
||||
<IconButton icon={Hand} label="抓手工具(H)" aria-pressed={tool === "hand"} onClick={() => setTool("hand")} />
|
||||
<span className={styles.divider} />
|
||||
<span className={toolbar.divider} aria-hidden="true" />
|
||||
<IconButton icon={Type} label="添加文字" onClick={() => addNode("text")} />
|
||||
<IconButton icon={ImagePlus} label="添加图片" onClick={() => imageInput.current?.click()} />
|
||||
<IconButton icon={FileText} label="添加脚本" onClick={() => addNode("script")} />
|
||||
<IconButton icon={Sparkles} label="插入创作模板" onClick={addTemplate} />
|
||||
<span className={styles.divider} />
|
||||
<span className={toolbar.divider} aria-hidden="true" />
|
||||
<IconButton icon={Upload} label="导入图谱" onClick={() => projectInput.current?.click()} />
|
||||
</div>
|
||||
<div className={`${toolbar.surface} ${styles.helpToolbar}`}>
|
||||
|
||||
@@ -16,3 +16,7 @@
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
/* Text in the view controls already creates wider visual spacing. */
|
||||
.relaxed { column-gap: 6px; padding-inline: 6px; }
|
||||
.divider { flex: 0 0 1px; width: 1px; height: 16px; margin: 0 2px; background: #ece6df; }
|
||||
|
||||
@@ -122,5 +122,5 @@
|
||||
.accountPopup[data-floating="true"] { inset: 62px auto auto 12px; max-height: calc(100dvh - 76px); transform-origin: top left; }
|
||||
|
||||
.floatingAvatarButton .avatar { flex-basis: var(--toolbar-icon-size, 20px); width: var(--toolbar-icon-size, 20px); height: var(--toolbar-icon-size, 20px); font-size: 14px; }
|
||||
.floatingTitle { flex: 1 1 auto; min-width: 0; max-width: 240px; margin: 0 4px; color: #37352f; font-size: 14px; line-height: var(--toolbar-control-height, 32px); font-weight: 500; overflow: visible; }
|
||||
.floatingTitle { flex: 1 1 auto; min-width: 0; max-width: 240px; margin: 0; color: #37352f; font-size: 14px; line-height: var(--toolbar-control-height, 32px); font-weight: 500; overflow: visible; }
|
||||
@media (max-width: 700px) { .floatingTitle { max-width: 180px; } }
|
||||
|
||||
Reference in New Issue
Block a user