77 lines
3.7 KiB
HTML
77 lines
3.7 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg?v=paper-boat">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content">
|
|
<meta name="theme-color" content="#F4F1EB">
|
|
<script>
|
|
/* Applies the saved theme before first paint.
|
|
useTheme.ts sets data-theme and theme-color too, but only once the bundle
|
|
has parsed and run — so a light-theme user saw the dark shell, and dark
|
|
browser chrome, flash on every launch. That is most obvious in the
|
|
installed PWA, where the launch goes straight from a dark splash into the
|
|
app. The manifest's own background_color cannot help: it is static and
|
|
already matches the default (dark) theme.
|
|
Keep the key and the two colours in step with src/composables/useTheme.ts
|
|
and src/config/themeColors.ts — a static document cannot import them. */
|
|
(function () {
|
|
try {
|
|
var stored = localStorage.getItem('cm-theme') || 'light';
|
|
var resolved = stored === 'system'
|
|
? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
|
|
: (stored === 'light' ? 'light' : 'dark');
|
|
document.documentElement.setAttribute('data-theme', resolved);
|
|
var meta = document.querySelector('meta[name="theme-color"]');
|
|
if (meta) meta.setAttribute('content', resolved === 'dark' ? '#121211' : '#F4F1EB');
|
|
} catch (e) {
|
|
/* Private mode can throw on localStorage; the dark default already applies. */
|
|
}
|
|
})();
|
|
</script>
|
|
<!-- iOS installed-PWA (Add to Home Screen) -->
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<meta name="apple-mobile-web-app-title" content="ChatterMate">
|
|
<link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300..600;1,9..144,300..500&family=Hanken+Grotesk:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&family=Noto+Serif+SC:wght@500;600;700&display=swap">
|
|
<title>ChatterMate · 智能客服工作台</title>
|
|
<meta name="shopify-api-key" content="<%= VITE_SHOPIFY_API_KEY %>" />
|
|
<!-- Shopify App Bridge, and the Polaris web components the Shopify views use.
|
|
Only loaded inside the Shopify admin (host/shop query params present);
|
|
outside it App Bridge throws "missing required configuration fields: shop"
|
|
and both scripts are ~200KB of render-blocking script nothing else uses.
|
|
async = false keeps them in order and ahead of the app bundle. Appending
|
|
them beats document.write, which Chrome may block on a slow connection -
|
|
that would leave the embedded admin with no Polaris and an unstyled UI. -->
|
|
<script>
|
|
(function () {
|
|
var params = new URLSearchParams(window.location.search)
|
|
if (!params.has('host') && !params.has('shop')) return
|
|
var sources = [
|
|
'https://cdn.shopify.com/shopifycloud/app-bridge.js',
|
|
'https://cdn.shopify.com/shopifycloud/polaris.js'
|
|
]
|
|
sources.forEach(function (src) {
|
|
var script = document.createElement('script')
|
|
script.src = src
|
|
script.async = false
|
|
document.head.appendChild(script)
|
|
})
|
|
})()
|
|
</script>
|
|
</head>
|
|
|
|
<body>
|
|
<div id="app"></div>
|
|
<script src="/config.js"></script>
|
|
<script type="module" src="/src/main.ts"></script>
|
|
</body>
|
|
|
|
</html>
|