外壳:侧栏改 fixed,请求页改名日志,错误提示点击复制,弹窗锁滚动
侧栏从 sticky 改 fixed:sticky 的位置跟着 scrollTop 走,滚到底时 scrollTop 是 scrollHeight 减 clientHeight,在 Windows 显示缩放下是 小数,部分图标会跳 1px;fixed 按视口摆放,不参与这个运算。网格第一列 只当占位,主区显式站到第二列。 错误提示是拿去粘贴排查的,点击改成复制而不是关闭,关闭交给自动消失; 局域网 http 下没有 clipboard API,退回 execCommand。撤回/重做各加 2.5 秒冷却,窗内连点算一次,顺带避开重做备份名的同秒覆盖。弹窗打开 时锁住背景滚动,滚动条位置由 scrollbar-gutter 常驻,不横向跳。
This commit is contained in:
+31
-8
@@ -100,8 +100,24 @@ const busyAct = ref(false)
|
||||
const historyOpen = ref(false)
|
||||
const askRestart = ref(false)
|
||||
|
||||
/**
|
||||
* 撤回/重做各自的冷却:窗内的连点算一次。手抖不该多退一步;顺带避开
|
||||
* 重做的备份名同秒覆盖(备份名精确到秒,窗比一秒宽就撞不上)。
|
||||
* 两个方向分开冷却,撤回错了马上重做这条路不受影响。
|
||||
*/
|
||||
const HISTORY_COOLDOWN_MS = 2_500
|
||||
const cooling = ref({ undo: false, redo: false })
|
||||
|
||||
function coolDown(kind: 'undo' | 'redo') {
|
||||
cooling.value = { ...cooling.value, [kind]: true }
|
||||
window.setTimeout(() => {
|
||||
cooling.value = { ...cooling.value, [kind]: false }
|
||||
}, HISTORY_COOLDOWN_MS)
|
||||
}
|
||||
|
||||
async function undo() {
|
||||
if (busyAct.value) return
|
||||
if (busyAct.value || cooling.value.undo) return
|
||||
coolDown('undo')
|
||||
busyAct.value = true
|
||||
try {
|
||||
const result = await api.undoConfig()
|
||||
@@ -115,7 +131,8 @@ async function undo() {
|
||||
}
|
||||
|
||||
async function redo() {
|
||||
if (busyAct.value) return
|
||||
if (busyAct.value || cooling.value.redo) return
|
||||
coolDown('redo')
|
||||
busyAct.value = true
|
||||
try {
|
||||
const result = await api.redoConfig()
|
||||
@@ -239,7 +256,7 @@ const current = computed(() => NAV.find((n) => n.key === active.value))
|
||||
type="button"
|
||||
class="act"
|
||||
title="撤回"
|
||||
:disabled="busyAct || !snapshot || history.backups.length === 0"
|
||||
:disabled="busyAct || cooling.undo || !snapshot || history.backups.length === 0"
|
||||
@click="undo"
|
||||
>
|
||||
<IconUndo />
|
||||
@@ -248,7 +265,7 @@ const current = computed(() => NAV.find((n) => n.key === active.value))
|
||||
type="button"
|
||||
class="act"
|
||||
title="重做"
|
||||
:disabled="busyAct || !snapshot || history.redo === 0"
|
||||
:disabled="busyAct || cooling.redo || !snapshot || history.redo === 0"
|
||||
@click="redo"
|
||||
>
|
||||
<IconRedo />
|
||||
@@ -411,14 +428,18 @@ const current = computed(() => NAV.find((n) => n.key === active.value))
|
||||
|
||||
/* ── 侧栏 ───────────────────────────────────── */
|
||||
/*
|
||||
* 钉在视口里。不加 sticky 的话它会被网格行撑到和主区一样高,页面一长,
|
||||
* 导航就跟着滚出屏幕外,而它是全局导航,任何时候都该够得着。
|
||||
* 钉在视口里。用 fixed 而不是 sticky:sticky 元素的位置跟着 scrollTop 走,
|
||||
* 而滚动到底时 scrollTop = scrollHeight - clientHeight,在 Windows 显示缩放下
|
||||
* 是小数——侧栏落在小数像素上,图标和文字取整方向不同,部分图标会跳 1px。
|
||||
* fixed 按视口摆放,不参与滚动偏移的运算。网格的第一列只当占位。
|
||||
*/
|
||||
.side {
|
||||
position: sticky;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
align-self: start;
|
||||
left: 0;
|
||||
width: var(--side-w);
|
||||
height: 100vh;
|
||||
transition: width 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-5);
|
||||
@@ -696,7 +717,9 @@ const current = computed(() => NAV.find((n) => n.key === active.value))
|
||||
|
||||
|
||||
/* ── 主区 ───────────────────────────────────── */
|
||||
/* 侧栏是 fixed、不占网格位,主区要自己站到第二列,否则会顶进第一列 */
|
||||
.main {
|
||||
grid-column: 2;
|
||||
padding: var(--s-6) var(--s-6) var(--s-7);
|
||||
max-width: 1600px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user