fix(layout): 侧边栏置顶,文档标签栏移到侧边栏右侧
TabBar 从菜单栏下方的整行移入主区右侧内容列(新增 .content-col 纵向容器), 侧边栏自此从菜单栏下方贯通到状态栏;隐藏侧边栏时标签栏占满整行。 打印规则同步覆盖新容器。无头浏览器实测:标签栏左边缘与侧边栏右边缘对齐 (250px)。vitest 87 通过 + 2 跳过,tsc 与构建通过。
This commit is contained in:
28
src/App.tsx
28
src/App.tsx
@@ -1150,19 +1150,6 @@ export default function App() {
|
|||||||
<div className="app">
|
<div className="app">
|
||||||
<TitleBar docTitle={tab?.title ?? 'new-markdown'} dirty={tab ? isDirty(tab) : false} />
|
<TitleBar docTitle={tab?.title ?? 'new-markdown'} dirty={tab ? isDirty(tab) : false} />
|
||||||
<MenuBar menus={menus} />
|
<MenuBar menus={menus} />
|
||||||
<TabBar
|
|
||||||
tabs={state.tabs}
|
|
||||||
activeId={state.activeId}
|
|
||||||
onActivate={(id) => { dispatch({ type: 'activate', id }); setSourceMode(false) }}
|
|
||||||
onClose={closeTab}
|
|
||||||
onCloseOthers={(id) => requestClose(state.tabs.filter((t) => t.id !== id).map((t) => t.id), () => dispatch({ type: 'closeOthers', id }))}
|
|
||||||
onCloseRight={(id) => {
|
|
||||||
const idx = state.tabs.findIndex((t) => t.id === id)
|
|
||||||
requestClose(state.tabs.slice(idx + 1).map((t) => t.id), () => dispatch({ type: 'closeRight', id }))
|
|
||||||
}}
|
|
||||||
onNew={newDoc}
|
|
||||||
onMove={(id, toIndex) => dispatch({ type: 'move', id, toIndex })}
|
|
||||||
/>
|
|
||||||
<div className="main">
|
<div className="main">
|
||||||
{ui.sidebar && (
|
{ui.sidebar && (
|
||||||
<div style={{ width: ui.sidebarWidth, flex: 'none', display: 'flex' }}>
|
<div style={{ width: ui.sidebarWidth, flex: 'none', display: 'flex' }}>
|
||||||
@@ -1185,6 +1172,20 @@ export default function App() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div className="content-col">
|
||||||
|
<TabBar
|
||||||
|
tabs={state.tabs}
|
||||||
|
activeId={state.activeId}
|
||||||
|
onActivate={(id) => { dispatch({ type: 'activate', id }); setSourceMode(false) }}
|
||||||
|
onClose={closeTab}
|
||||||
|
onCloseOthers={(id) => requestClose(state.tabs.filter((t) => t.id !== id).map((t) => t.id), () => dispatch({ type: 'closeOthers', id }))}
|
||||||
|
onCloseRight={(id) => {
|
||||||
|
const idx = state.tabs.findIndex((t) => t.id === id)
|
||||||
|
requestClose(state.tabs.slice(idx + 1).map((t) => t.id), () => dispatch({ type: 'closeRight', id }))
|
||||||
|
}}
|
||||||
|
onNew={newDoc}
|
||||||
|
onMove={(id, toIndex) => dispatch({ type: 'move', id, toIndex })}
|
||||||
|
/>
|
||||||
<div className="editor-area" style={{ ['--doc-zoom' as string]: zoom }}>
|
<div className="editor-area" style={{ ['--doc-zoom' as string]: zoom }}>
|
||||||
{!tab && (
|
{!tab && (
|
||||||
<div className="empty-state">
|
<div className="empty-state">
|
||||||
@@ -1285,6 +1286,7 @@ export default function App() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<StatusBar
|
<StatusBar
|
||||||
words={statusCounts.words}
|
words={statusCounts.words}
|
||||||
chars={statusCounts.chars}
|
chars={statusCounts.chars}
|
||||||
|
|||||||
@@ -56,7 +56,9 @@ button { font: inherit; color: inherit; }
|
|||||||
.menu-divider { height: 1px; background: var(--border); margin: 5px 8px; }
|
.menu-divider { height: 1px; background: var(--border); margin: 5px 8px; }
|
||||||
|
|
||||||
/* 标签栏 */
|
/* 标签栏 */
|
||||||
.tabbar { display: flex; align-items: stretch; background: var(--bg-panel); border-bottom: 1px solid var(--border); min-height: 36px; overflow-x: auto; }
|
.tabbar { display: flex; align-items: stretch; background: var(--bg-panel); border-bottom: 1px solid var(--border); min-height: 36px; overflow-x: auto; flex: none; }
|
||||||
|
/* 左侧栏置顶、文档标签栏移到侧边栏右侧的内容列顶部 */
|
||||||
|
.content-col { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
|
||||||
.tab { display: flex; align-items: center; gap: 7px; padding: 0 8px 0 14px; font-size: 13px; cursor: pointer; border-right: 1px solid var(--border); white-space: nowrap; color: var(--text-dim); }
|
.tab { display: flex; align-items: center; gap: 7px; padding: 0 8px 0 14px; font-size: 13px; cursor: pointer; border-right: 1px solid var(--border); white-space: nowrap; color: var(--text-dim); }
|
||||||
.tab.active { background: var(--bg-editor); color: var(--text); box-shadow: inset 0 2px 0 var(--accent); }
|
.tab.active { background: var(--bg-editor); color: var(--text); box-shadow: inset 0 2px 0 var(--accent); }
|
||||||
.tab-title { max-width: 180px; overflow: hidden; text-overflow: ellipsis; }
|
.tab-title { max-width: 180px; overflow: hidden; text-overflow: ellipsis; }
|
||||||
@@ -95,7 +97,7 @@ button { font: inherit; color: inherit; }
|
|||||||
.tree-icon { color: var(--text-dim); width: 12px; flex: none; }
|
.tree-icon { color: var(--text-dim); width: 12px; flex: none; }
|
||||||
|
|
||||||
.editor-scroll { flex: 1; overflow-y: auto; background: var(--bg-editor); min-width: 0; position: relative; }
|
.editor-scroll { flex: 1; overflow-y: auto; background: var(--bg-editor); min-width: 0; position: relative; }
|
||||||
.editor-area { flex: 1; display: flex; min-width: 0; position: relative; }
|
.editor-area { flex: 1; display: flex; min-width: 0; min-height: 0; position: relative; }
|
||||||
/* 标签保活后每个窗格自带滚动容器,各自保留滚动位置;窗格加载状态覆盖层 */
|
/* 标签保活后每个窗格自带滚动容器,各自保留滚动位置;窗格加载状态覆盖层 */
|
||||||
.pane-loading { position: absolute; inset: 0; display: flex; flex-direction: column; gap: 12px; align-items: center; justify-content: center; color: var(--text-dim); font-size: 13px; background: var(--doc-paper); z-index: 5; }
|
.pane-loading { position: absolute; inset: 0; display: flex; flex-direction: column; gap: 12px; align-items: center; justify-content: center; color: var(--text-dim); font-size: 13px; background: var(--doc-paper); z-index: 5; }
|
||||||
.pane-spinner { width: 26px; height: 26px; border-radius: 50%; border: 3px solid var(--border); border-top-color: var(--accent); animation: pane-spin 0.8s linear infinite; }
|
.pane-spinner { width: 26px; height: 26px; border-radius: 50%; border: 3px solid var(--border); border-top-color: var(--accent); animation: pane-spin 0.8s linear infinite; }
|
||||||
@@ -269,7 +271,7 @@ kbd { background: var(--code-bg); border: 1px solid var(--border); border-radius
|
|||||||
@media print {
|
@media print {
|
||||||
.titlebar, .menubar, .tabbar, .sidebar, .statusbar, .modal-backdrop, .app-notice, .context-menu,
|
.titlebar, .menubar, .tabbar, .sidebar, .statusbar, .modal-backdrop, .app-notice, .context-menu,
|
||||||
.table-toolbar, .tree-context-menu, .findbar, .mermaid-head { display: none !important; }
|
.table-toolbar, .tree-context-menu, .findbar, .mermaid-head { display: none !important; }
|
||||||
.app, .main, .editor-scroll { display: block !important; height: auto !important; overflow: visible !important; }
|
.app, .main, .content-col, .editor-area, .editor-scroll { display: block !important; height: auto !important; overflow: visible !important; }
|
||||||
.editor-scroll { background: #fff !important; }
|
.editor-scroll { background: #fff !important; }
|
||||||
/* 打印只出活动窗格:保活的隐藏窗格不能被上面的 display:block 通杀带出来 */
|
/* 打印只出活动窗格:保活的隐藏窗格不能被上面的 display:block 通杀带出来 */
|
||||||
.editor-scroll.tab-pane { display: none !important; }
|
.editor-scroll.tab-pane { display: none !important; }
|
||||||
|
|||||||
Reference in New Issue
Block a user