外壳:侧栏改 fixed,请求页改名日志,错误提示点击复制,弹窗锁滚动
侧栏从 sticky 改 fixed:sticky 的位置跟着 scrollTop 走,滚到底时 scrollTop 是 scrollHeight 减 clientHeight,在 Windows 显示缩放下是 小数,部分图标会跳 1px;fixed 按视口摆放,不参与这个运算。网格第一列 只当占位,主区显式站到第二列。 错误提示是拿去粘贴排查的,点击改成复制而不是关闭,关闭交给自动消失; 局域网 http 下没有 clipboard API,退回 execCommand。撤回/重做各加 2.5 秒冷却,窗内连点算一次,顺带避开重做备份名的同秒覆盖。弹窗打开 时锁住背景滚动,滚动条位置由 scrollbar-gutter 常驻,不横向跳。
This commit is contained in:
@@ -1,12 +1,45 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 轻提示的渲染宿主,挂在外壳根部。进场从右滑入,退场上移淡出;
|
||||
* 点一下立刻消掉。内容来自 web/toast.ts 的单例队列。
|
||||
* 轻提示的渲染宿主,挂在外壳根部。进场从右滑入,退场上移淡出。
|
||||
* 点一下:普通提示立刻消掉;错误提示是要拿去粘贴求助的,点击复制而不是关闭,
|
||||
* 消失交给 toast.ts 的定时器。内容来自 web/toast.ts 的单例队列。
|
||||
*/
|
||||
import { ref } from 'vue'
|
||||
import { dismiss, toasts } from '../toast'
|
||||
import type { Toast } from '../toast'
|
||||
import IconOk from '~icons/ri/checkbox-circle-line'
|
||||
import IconErr from '~icons/ri/error-warning-line'
|
||||
import IconInfo from '~icons/ri/information-line'
|
||||
|
||||
/** 已复制的错误提示:hint 原地换成「已复制到剪贴板」作为反馈。 */
|
||||
const copied = ref(new Set<number>())
|
||||
|
||||
async function onClick(t: Toast) {
|
||||
if (t.kind !== 'error') {
|
||||
dismiss(t.id)
|
||||
return
|
||||
}
|
||||
const ok = await copyText([t.message, t.hint].filter(Boolean).join('\n'))
|
||||
if (ok) copied.value = new Set(copied.value).add(t.id)
|
||||
}
|
||||
|
||||
/** 经 http 从局域网访问时没有 navigator.clipboard(非安全上下文),退回 execCommand。 */
|
||||
async function copyText(text: string): Promise<boolean> {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text)
|
||||
return true
|
||||
} catch {
|
||||
const area = document.createElement('textarea')
|
||||
area.value = text
|
||||
area.style.position = 'fixed'
|
||||
area.style.opacity = '0'
|
||||
document.body.appendChild(area)
|
||||
area.select()
|
||||
const ok = document.execCommand('copy')
|
||||
area.remove()
|
||||
return ok
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -16,14 +49,16 @@ import IconInfo from '~icons/ri/information-line'
|
||||
v-for="t in toasts"
|
||||
:key="t.id"
|
||||
:class="['tst', t.kind === 'error' && 'is-error']"
|
||||
@click="dismiss(t.id)"
|
||||
:title="t.kind === 'error' ? '点击复制错误信息' : undefined"
|
||||
@click="onClick(t)"
|
||||
>
|
||||
<IconErr v-if="t.kind === 'error'" class="tico" />
|
||||
<IconInfo v-else-if="t.kind === 'info'" class="tico is-info" />
|
||||
<IconOk v-else class="tico" />
|
||||
<div class="tbody">
|
||||
<strong class="tmsg">{{ t.message }}</strong>
|
||||
<span v-if="t.hint" class="thint">{{ t.hint }}</span>
|
||||
<span v-if="copied.has(t.id)" class="thint">已复制到剪贴板</span>
|
||||
<span v-else-if="t.hint" class="thint">{{ t.hint }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
|
||||
Reference in New Issue
Block a user