// Site-wide branding (currently just the wordmark / tab title) backed by the // admin-editable config at /admin/api/site. One reactive object so every // component that wants to display "" stays in sync the moment the // admin saves a change. import { reactive } from 'vue' const BASE = import.meta.env.VITE_API_BASE || '' export const site = reactive({ title: 'Vivid', logo: '', subtitle: '', cdkRedeemEnabled: true, // Defaults so the 关于 page is never blank even if /site hasn't loaded (or a // cache serves an older payload without `contact`). The backend value, once // fetched, overrides these. contact: { qq: '1114639355', qq_link: 'https://qm.qq.com/q/ItgCcNA7ac', qq_group: '1106849765', qq_group_link: 'https://qm.qq.com/q/976LeMFoHu', email: 'vividairun@gmail.com', shop: 'https://pay.ldxp.cn/shop/chiyi', }, ready: false, }) // Point the browser-tab favicon at a custom logo (or back to the default svg). export function applyFavicon(url) { let link = document.querySelector("link[rel~='icon']") if (!link) { link = document.createElement('link') link.rel = 'icon' document.head.appendChild(link) } link.removeAttribute('type') // a png/jpg logo must not be forced as svg link.href = url || '/favicon.svg' } export async function loadSite() { try { const r = await fetch(`${BASE}/admin/api/site`) if (r.ok) { const data = await r.json() if (data.title) site.title = String(data.title) site.logo = data.logo ? String(data.logo) : '' site.subtitle = data.subtitle ? String(data.subtitle) : '' site.cdkRedeemEnabled = data.cdk_redeem_enabled !== false if (data.contact) site.contact = { ...site.contact, ...data.contact } // The uploaded logo IS the site icon (favicon / 浏览器标签 / 收藏). if (site.logo) applyFavicon(site.logo) } } catch { /* offline — keep the default. */ } site.ready = true }