Files
DAO_DE_JING/.vitepress/theme/InstallApp.vue
T
dekun a8907d6cc0 Improve mobile reading layout and typography
Make classic text chapters easier to read on phones with responsive styles, collapsed sidebar groups, and less intrusive install prompts on doc pages.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-05 17:57:57 +08:00

147 lines
3.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useRoute } from 'vitepress'
const route = useRoute()
const showAndroidInstall = ref(false)
const showIOSHint = ref(false)
const dismissed = ref(false)
const isMobile = ref(false)
let deferredPrompt: BeforeInstallPromptEvent | null = null
interface BeforeInstallPromptEvent extends Event {
prompt: () => Promise<void>
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>
}
const isDocPage = computed(() => route.path !== '/')
const visible = computed(() => {
if (dismissed.value) return false
if (isMobile.value && isDocPage.value) return false
return showAndroidInstall.value || showIOSHint.value
})
onMounted(() => {
isMobile.value = window.matchMedia('(max-width: 768px)').matches
if (sessionStorage.getItem('install-app-dismissed') === '1') {
dismissed.value = true
return
}
const isStandalone =
window.matchMedia('(display-mode: standalone)').matches ||
(window.navigator as Navigator & { standalone?: boolean }).standalone
if (isStandalone) return
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent)
if (isIOS) {
showIOSHint.value = true
return
}
window.addEventListener('beforeinstallprompt', (event) => {
event.preventDefault()
deferredPrompt = event as BeforeInstallPromptEvent
showAndroidInstall.value = true
})
})
async function installApp() {
if (!deferredPrompt) return
await deferredPrompt.prompt()
await deferredPrompt.userChoice
deferredPrompt = null
showAndroidInstall.value = false
}
function dismiss() {
dismissed.value = true
sessionStorage.setItem('install-app-dismissed', '1')
}
</script>
<template>
<div v-if="visible" class="install-app">
<div class="install-app__content">
<p v-if="showAndroidInstall" class="install-app__text">
可将道德经安装到桌面 App 一样使用
</p>
<p v-else class="install-app__text">
iPhoneSafari 底部分享 添加到主屏幕阅读更方便
</p>
<div class="install-app__actions">
<button
v-if="showAndroidInstall"
type="button"
class="install-app__primary"
@click="installApp"
>
安装应用
</button>
<button type="button" class="install-app__ghost" @click="dismiss">知道了</button>
</div>
</div>
</div>
</template>
<style scoped>
.install-app {
position: fixed;
right: 16px;
bottom: calc(16px + env(safe-area-inset-bottom, 0));
z-index: 50;
max-width: min(92vw, 360px);
}
.install-app__content {
padding: 14px 16px;
border-radius: 12px;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
box-shadow: var(--vp-shadow-3);
}
.install-app__text {
margin: 0 0 12px;
font-size: 14px;
line-height: 1.5;
color: var(--vp-c-text-1);
}
.install-app__actions {
display: flex;
gap: 8px;
}
.install-app__primary,
.install-app__ghost {
border-radius: 8px;
padding: 10px 14px;
font-size: 14px;
cursor: pointer;
}
.install-app__primary {
border: none;
background: var(--vp-c-brand-1);
color: var(--vp-c-bg);
}
.install-app__ghost {
border: 1px solid var(--vp-c-divider);
background: transparent;
color: var(--vp-c-text-2);
}
@media (max-width: 768px) {
.install-app {
left: 12px;
right: 12px;
max-width: none;
}
}
</style>