style: reorganize key list layout — actions to bottom, fix footer wrap

Layout restructure:
- Move Import Keys button from toolbar to footer (left side)
- Move batch action bar (select-all + export/delete) to bottom,
  above the footer, below the tree view
- Toolbar now only contains filter input + refresh/toggle buttons

Footer fix:
- Add min-width:0 + overflow:hidden on left side to truncate long counts
- Add flex-shrink:0 + white-space:nowrap on right side to keep buttons
  from wrapping when key count is large
This commit is contained in:
2026-07-12 10:59:23 +08:00
parent e39ec7afce
commit 0a5ceeaf4d
+53 -40
View File
@@ -561,20 +561,6 @@ onUnmounted(() => {
<el-icon class="search-icon"><Filter /></el-icon>
</template>
</el-input>
<el-button size="small" @click="importKeys" :disabled="!connStore.activeId" class="import-btn">
{{ t('key.importKeys') }}
</el-button>
<div v-if="multiSelect" class="select-all-wrapper">
<label class="select-all-label" @click.prevent="selectAll">
<input
type="checkbox"
class="select-all-checkbox"
:checked="multiSelect && selectedKeys.size === filteredKeys.length && filteredKeys.length > 0"
:indeterminate="multiSelect && selectedKeys.size > 0 && selectedKeys.size < filteredKeys.length"
/>
<span>{{ t('key.selectAll') }}</span>
</label>
</div>
<el-button-group class="key-actions">
<el-button size="small" @click="refreshKeys" :disabled="!connStore.activeId">
<el-icon><Refresh /></el-icon>
@@ -589,18 +575,6 @@ onUnmounted(() => {
</el-button-group>
</div>
<div v-if="multiSelect && selectedKeys.size > 0" class="batch-bar">
<span class="batch-count">{{ t('key.selected', { n: selectedKeys.size }) }}</span>
<div class="batch-bar-actions">
<el-button size="small" @click="exportKeys">
{{ t('key.exportKeys') }}
</el-button>
<el-button size="small" type="danger" @click="batchDelete">
{{ t('key.batchDelete') }}
</el-button>
</div>
</div>
<div class="key-content">
<!-- Tree View -->
<div class="key-tree">
@@ -642,6 +616,30 @@ onUnmounted(() => {
</div>
</div>
<!-- Batch actions bar (bottom) -->
<div v-if="multiSelect && selectedKeys.size > 0" class="batch-bar">
<div class="batch-bar-left">
<label class="select-all-label" @click.prevent="selectAll">
<input
type="checkbox"
class="select-all-checkbox"
:checked="multiSelect && selectedKeys.size === filteredKeys.length && filteredKeys.length > 0"
:indeterminate="multiSelect && selectedKeys.size > 0 && selectedKeys.size < filteredKeys.length"
/>
<span>{{ t('key.selectAll') }}</span>
</label>
<span class="batch-count">{{ t('key.selected', { n: selectedKeys.size }) }}</span>
</div>
<div class="batch-bar-actions">
<el-button size="small" @click="exportKeys">
{{ t('key.exportKeys') }}
</el-button>
<el-button size="small" type="danger" @click="batchDelete">
{{ t('key.batchDelete') }}
</el-button>
</div>
</div>
<!-- Right-click context menu -->
<div
v-if="contextMenu.visible"
@@ -674,7 +672,12 @@ onUnmounted(() => {
</div>
<div class="key-footer">
<div class="key-footer-left">
<el-button size="small" @click="importKeys" :disabled="!connStore.activeId">
{{ t('key.importKeys') }}
</el-button>
<span class="key-count">{{ t('key.count', { n: keyStore.keys.length }) }}</span>
</div>
<div class="key-footer-actions">
<el-button
v-if="keyStore.hasMore && keyStore.loading"
@@ -738,15 +741,21 @@ onUnmounted(() => {
}
.batch-bar {
padding: 8px 12px;
padding: 6px 12px;
display: flex;
justify-content: space-between;
align-items: center;
background: var(--accent-bg);
border-bottom: 1px solid var(--border-color);
border-top: 1px solid var(--border-color);
flex-shrink: 0;
}
.batch-bar-left {
display: flex;
align-items: center;
gap: 12px;
}
.batch-bar-actions {
display: flex;
gap: 6px;
@@ -759,10 +768,6 @@ onUnmounted(() => {
color: var(--accent-light);
}
.import-btn {
flex-shrink: 0;
}
.key-content {
flex: 1;
overflow: auto;
@@ -859,23 +864,37 @@ onUnmounted(() => {
}
.key-footer {
padding: 8px 12px;
padding: 6px 12px;
border-top: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
gap: 8px;
}
.key-footer-left {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
overflow: hidden;
}
.key-count {
font-size: 11px;
color: var(--text-muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.key-footer-actions {
display: flex;
gap: 6px;
align-items: center;
flex-shrink: 0;
white-space: nowrap;
}
/* Right-click context menu */
@@ -929,13 +948,7 @@ onUnmounted(() => {
color: var(--danger);
}
/* Select All checkbox */
.select-all-wrapper {
display: flex;
align-items: center;
flex-shrink: 0;
}
/* Select All checkbox (in batch bar) */
.select-all-label {
display: flex;
align-items: center;