83 lines
2.9 KiB
Vue
83 lines
2.9 KiB
Vue
<script setup>
|
||
import { computed, onMounted, onBeforeUnmount, watch } from 'vue'
|
||
import { useRoute } from 'vue-router'
|
||
import TopBar from './components/TopBar.vue'
|
||
import ThemeSwitcher from './components/ThemeSwitcher.vue'
|
||
import ImgLightbox from './components/ImgLightbox.vue'
|
||
import YohakuTop from './ui/yohaku/YohakuTop.vue'
|
||
import YohakuFoot from './ui/yohaku/YohakuFoot.vue'
|
||
import { site, setAdminScope } from './site'
|
||
|
||
const route = useRoute()
|
||
|
||
// 正文代码块复制按钮(事件委托:复制按钮是 enhanceProse 注入的静态 HTML)
|
||
function onCopyClick(e) {
|
||
const btn = e.target.closest?.('.pre-copy')
|
||
if (!btn) return
|
||
const pre = btn.closest('.pre-wrap')?.querySelector('pre')
|
||
if (!pre) return
|
||
navigator.clipboard
|
||
.writeText(pre.innerText.replace(/\n$/, ''))
|
||
.then(() => {
|
||
btn.textContent = '已复制'
|
||
btn.classList.add('done')
|
||
setTimeout(() => {
|
||
btn.textContent = '复制'
|
||
btn.classList.remove('done')
|
||
}, 1600)
|
||
})
|
||
.catch(() => {
|
||
btn.textContent = '复制失败'
|
||
setTimeout(() => (btn.textContent = '复制'), 1600)
|
||
})
|
||
}
|
||
onMounted(() => document.addEventListener('click', onCopyClick))
|
||
onBeforeUnmount(() => document.removeEventListener('click', onCopyClick))
|
||
|
||
const isAdmin = computed(() => route.path.startsWith('/admin'))
|
||
// vivid 只在公开前台生效:后台永远走 classic 那套(--admin-* token + 原 data-ui/data-theme),
|
||
// 不受 ui_id 影响。vivid.css 会命中 .btn / .input 这类全局类,后台表单正在用,
|
||
// 所以必须在 data-ui 轴上退回 classic,而不是只靠 --admin-* 区分。
|
||
// 余白(vivid)只在公开前台生效:后台永远走 classic 那套。
|
||
const isVivid = computed(() => site.ui_id === 'vivid' && !isAdmin.value)
|
||
|
||
// body hook:让全局 CSS 知道当前是 admin,
|
||
// focus-visible 等样式跟着切 token。
|
||
watch(
|
||
isAdmin,
|
||
(v) => {
|
||
if (typeof document !== 'undefined') {
|
||
document.body.classList.toggle('admin-shell-active', v)
|
||
}
|
||
// 同一个开关也用于把 data-ui / data-theme 收回 classic
|
||
setAdminScope(v)
|
||
},
|
||
{ immediate: true }
|
||
)
|
||
</script>
|
||
|
||
<template>
|
||
<YohakuTop v-if="isVivid" />
|
||
<TopBar v-else-if="!isAdmin" />
|
||
<RouterView />
|
||
<YohakuFoot v-if="isVivid" />
|
||
<!-- classic 的页脚信息在 RightRail 卡片下方的小字区(Twitter 式侧栏页脚) -->
|
||
<!-- 图片预览层:时间线 / 详情页的配图点开时全屏展示 -->
|
||
<ImgLightbox />
|
||
<!-- 桌面端:左栏底部放 inline 形态;窄屏:左栏收起,浮动按钮兜底。
|
||
vivid 的顶部导航自带切换器,浮动那个就不重复出现了。 -->
|
||
<ThemeSwitcher v-if="!isVivid" variant="floating" class="theme-floating-only" />
|
||
</template>
|
||
|
||
<style scoped>
|
||
/* 窄屏(≤780px)才显示浮动按钮 —— 此时前台左栏 / 后台侧栏都已隐藏 */
|
||
.theme-floating-only {
|
||
display: none;
|
||
}
|
||
|
||
@media (max-width: 780px) {
|
||
.theme-floating-only {
|
||
display: inline-flex;
|
||
}
|
||
}
|
||
</style> |