mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-07 16:37:52 +08:00
iOS Safari 在输入框字号小于 16px 时聚焦会自动放大页面,且失焦后不会恢复, 导致布局错位。启动时仅对 iOS 设备为 viewport 注入 maximum-scale=1 阻止该 行为;iOS 10+ 用户仍可双指手动缩放,Android 不受影响。 - utils/device.ts 新增 detectIOSDevice/isIOSDevice(含 iPadOS 桌面模式识别) - main.ts 启动阶段执行 initIOSViewportZoomFix - 补充 detectIOSDevice 单元测试 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
64 lines
2.1 KiB
TypeScript
64 lines
2.1 KiB
TypeScript
import { createApp } from 'vue'
|
|
import { createPinia } from 'pinia'
|
|
import App from './App.vue'
|
|
import router from './router'
|
|
import i18n, { initI18n } from './i18n'
|
|
import { useAppStore } from '@/stores/app'
|
|
import { updateFavicon } from '@/utils/branding'
|
|
import { isIOSDevice } from '@/utils/device'
|
|
import './style.css'
|
|
|
|
function initIOSViewportZoomFix() {
|
|
// iOS Safari 在输入框字号小于 16px 时聚焦会自动放大页面,且失焦后不会恢复。
|
|
// 限制 maximum-scale 可阻止该行为;iOS 10+ 用户仍可双指手动缩放,不影响可访问性。
|
|
// 仅在 iOS 设备上注入,避免影响 Android Chrome 的手动缩放能力。
|
|
if (!isIOSDevice()) return
|
|
|
|
const viewport = document.querySelector('meta[name="viewport"]')
|
|
if (!viewport) return
|
|
|
|
const content = viewport.getAttribute('content') || ''
|
|
if (/maximum-scale/i.test(content)) return
|
|
viewport.setAttribute('content', `${content}, maximum-scale=1.0`)
|
|
}
|
|
|
|
function initThemeClass() {
|
|
const savedTheme = localStorage.getItem('theme')
|
|
const shouldUseDark =
|
|
savedTheme === 'dark' ||
|
|
(!savedTheme && window.matchMedia('(prefers-color-scheme: dark)').matches)
|
|
document.documentElement.classList.toggle('dark', shouldUseDark)
|
|
}
|
|
|
|
async function bootstrap() {
|
|
// Apply theme class globally before app mount to keep all routes consistent.
|
|
initThemeClass()
|
|
initIOSViewportZoomFix()
|
|
|
|
const app = createApp(App)
|
|
const pinia = createPinia()
|
|
app.use(pinia)
|
|
|
|
// Initialize settings from injected config BEFORE mounting (prevents flash)
|
|
// This must happen after pinia is installed but before router and i18n
|
|
const appStore = useAppStore()
|
|
appStore.initFromInjectedConfig()
|
|
|
|
// Set document title immediately after config is loaded
|
|
if (appStore.siteName && appStore.siteName !== 'Sub2API') {
|
|
document.title = `${appStore.siteName} - AI API Gateway`
|
|
}
|
|
updateFavicon(appStore.siteLogo)
|
|
|
|
await initI18n()
|
|
|
|
app.use(router)
|
|
app.use(i18n)
|
|
|
|
// 等待路由器完成初始导航后再挂载,避免竞态条件导致的空白渲染
|
|
await router.isReady()
|
|
app.mount('#app')
|
|
}
|
|
|
|
bootstrap()
|