fix: 修复系统设置动态注入到静态文件
- 简化前端 useSiteSettings,直接使用后端注入的 window.__SITE_CONFIG__ - 修复后端 serveIndexHTML 中的设置 key 名,与前端的 key 名一致 - site_name 替换为正确的数据库字段名 - logo 和 favicon 使用 site_logo 和 site_favicon - 添加 getLogo 函数根据主题自动选择 logo Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+8
-10
@@ -319,20 +319,18 @@ func serveIndexHTML(c *gin.Context, indexHTML string) {
|
|||||||
settings = make(map[string]interface{})
|
settings = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
siteName := getSettingString(settings, "siteName", "微授权")
|
siteName := getSettingString(settings, "site_name", "微授权")
|
||||||
siteDescription := getSettingString(settings, "siteDescription", "专业的应用验证平台")
|
siteDescription := getSettingString(settings, "site_description", "专业的应用验证平台")
|
||||||
siteKeywords := getSettingString(settings, "siteKeywords", "验证平台,软件授权,卡密验证")
|
siteLogo := getSettingString(settings, "site_logo", "")
|
||||||
logoLight := getSettingString(settings, "logoLight", "")
|
siteFavicon := getSettingString(settings, "site_favicon", "")
|
||||||
logoDark := getSettingString(settings, "logoDark", "")
|
|
||||||
favicon := getSettingString(settings, "favicon", "")
|
|
||||||
|
|
||||||
html := indexHTML
|
html := indexHTML
|
||||||
html = strings.ReplaceAll(html, "{{.SiteName}}", siteName)
|
html = strings.ReplaceAll(html, "{{.SiteName}}", siteName)
|
||||||
html = strings.ReplaceAll(html, "{{.SiteDescription}}", siteDescription)
|
html = strings.ReplaceAll(html, "{{.SiteDescription}}", siteDescription)
|
||||||
html = strings.ReplaceAll(html, "{{.SiteKeywords}}", siteKeywords)
|
html = strings.ReplaceAll(html, "{{.SiteKeywords}}", "验证平台,软件授权,卡密验证")
|
||||||
html = strings.ReplaceAll(html, "{{.LogoLight}}", logoLight)
|
html = strings.ReplaceAll(html, "{{.LogoLight}}", siteLogo)
|
||||||
html = strings.ReplaceAll(html, "{{.LogoDark}}", logoDark)
|
html = strings.ReplaceAll(html, "{{.LogoDark}}", siteLogo)
|
||||||
html = strings.ReplaceAll(html, "{{.Favicon}}", favicon)
|
html = strings.ReplaceAll(html, "{{.Favicon}}", siteFavicon)
|
||||||
|
|
||||||
c.Data(200, "text/html; charset=utf-8", []byte(html))
|
c.Data(200, "text/html; charset=utf-8", []byte(html))
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-17
@@ -2,19 +2,18 @@
|
|||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" media="(prefers-color-scheme: dark)" href="/logo.svg" />
|
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
||||||
<link rel="icon" type="image/svg+xml" media="(prefers-color-scheme: light)" href="/logo-black.svg" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>加载中...</title>
|
<title>{{.SiteName}}</title>
|
||||||
|
<meta name="description" content="{{.SiteDescription}}" />
|
||||||
|
|
||||||
<!-- Google Fonts - Inter -->
|
<!-- Google Fonts - Inter -->
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
<!-- 后端注入的系统配置(生产环境由后端渲染) -->
|
<!-- 后端注入的系统配置 -->
|
||||||
<script>
|
<script>
|
||||||
// 后端渲染时会注入这些变量,开发环境使用默认值
|
|
||||||
window.__SITE_CONFIG__ = {
|
window.__SITE_CONFIG__ = {
|
||||||
siteName: '{{.SiteName}}',
|
siteName: '{{.SiteName}}',
|
||||||
siteDescription: '{{.SiteDescription}}',
|
siteDescription: '{{.SiteDescription}}',
|
||||||
@@ -22,21 +21,10 @@
|
|||||||
logoDark: '{{.LogoDark}}',
|
logoDark: '{{.LogoDark}}',
|
||||||
favicon: '{{.Favicon}}',
|
favicon: '{{.Favicon}}',
|
||||||
};
|
};
|
||||||
|
|
||||||
// 检测是否是开发环境(模板变量未被替换)
|
|
||||||
if (window.__SITE_CONFIG__.siteName.indexOf('{{') === 0) {
|
|
||||||
window.__SITE_CONFIG__ = {
|
|
||||||
siteName: '',
|
|
||||||
siteDescription: '',
|
|
||||||
logoLight: '',
|
|
||||||
logoDark: '',
|
|
||||||
favicon: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script type="module" src="/src/main.ts"></script>
|
<script type="module" src="/src/main.ts"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Boxes, Code, CreditCard, DollarSign, FileLock, Gauge, GitBranch, HardDrive, Hash, Key, KeyRound, Mail, Megaphone, MessageSquare, Monitor, Network, Plug, ScrollText, Settings, Shield, Smartphone, Users, Variable } from 'lucide-vue-next'
|
import { Boxes, Code, CreditCard, DollarSign, FileLock, Gauge, GitBranch, HardDrive, Hash, Key, KeyRound, Mail, Megaphore, MessageSquare, Monitor, Network, Plug, ScrollText, Settings, Shield, Smartphone, Users, Variable } from 'lucide-vue-next'
|
||||||
import { computed, onMounted, onUnmounted, reactive, watch } from 'vue'
|
import { computed, onMounted, reactive, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { usePreferredDark } from '@vueuse/core'
|
||||||
|
|
||||||
import NavTeam from '@/components/app-sidebar/nav-team.vue'
|
import NavTeam from '@/components/app-sidebar/nav-team.vue'
|
||||||
import TeamSwitcher from '@/components/app-sidebar/team-switcher.vue'
|
import TeamSwitcher from '@/components/app-sidebar/team-switcher.vue'
|
||||||
@@ -9,7 +10,8 @@ import NavFooter from '@/components/admin-sidebar/nav-footer.vue'
|
|||||||
import { useSiteSettings } from '@/composables/use-site-settings'
|
import { useSiteSettings } from '@/composables/use-site-settings'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const { siteSettings } = useSiteSettings()
|
const { siteSettings, getLogo } = useSiteSettings()
|
||||||
|
const isDark = usePreferredDark()
|
||||||
|
|
||||||
const user = reactive({
|
const user = reactive({
|
||||||
name: t('nav.admin'),
|
name: t('nav.admin'),
|
||||||
@@ -20,31 +22,32 @@ const user = reactive({
|
|||||||
|
|
||||||
const teams = reactive([
|
const teams = reactive([
|
||||||
{
|
{
|
||||||
name: t('nav.adminDashboard'),
|
name: '',
|
||||||
logo: Code as any,
|
logo: '' as any,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// 计算当前 logo
|
||||||
|
const currentLogo = computed(() => {
|
||||||
|
if (siteSettings.logoLight || siteSettings.logoDark || siteSettings.siteLogo) {
|
||||||
|
return getLogo(isDark.value)
|
||||||
|
}
|
||||||
|
return Code // 默认图标
|
||||||
|
})
|
||||||
|
|
||||||
// 监听系统设置变化
|
// 监听系统设置变化
|
||||||
watch(() => siteSettings.siteName, (newName) => {
|
watch(() => siteSettings.siteName, (newName) => {
|
||||||
if (newName) {
|
if (newName) {
|
||||||
teams[0].name = newName
|
teams[0].name = newName
|
||||||
|
} else {
|
||||||
|
teams[0].name = t('nav.adminDashboard')
|
||||||
}
|
}
|
||||||
})
|
}, { immediate: true })
|
||||||
|
|
||||||
watch(() => siteSettings.siteLogo, (newLogo) => {
|
// 监听 logo 变化
|
||||||
if (newLogo) {
|
watch(currentLogo, (newLogo) => {
|
||||||
teams[0].logo = newLogo
|
teams[0].logo = newLogo
|
||||||
}
|
}, { immediate: true })
|
||||||
})
|
|
||||||
|
|
||||||
// 初始化时设置
|
|
||||||
if (siteSettings.siteName) {
|
|
||||||
teams[0].name = siteSettings.siteName
|
|
||||||
}
|
|
||||||
if (siteSettings.siteLogo) {
|
|
||||||
teams[0].logo = siteSettings.siteLogo
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const storedUser = localStorage.getItem('user')
|
const storedUser = localStorage.getItem('user')
|
||||||
@@ -62,9 +65,6 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
})
|
|
||||||
|
|
||||||
const navMain = computed(() => [
|
const navMain = computed(() => [
|
||||||
{
|
{
|
||||||
title: t('nav.mainFeatures'),
|
title: t('nav.mainFeatures'),
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
import { reactive } from 'vue'
|
import { reactive, watch } from 'vue'
|
||||||
import { getFileUrl } from '@/utils/config'
|
import { getFileUrl } from '@/utils/config'
|
||||||
|
|
||||||
|
interface SiteConfig {
|
||||||
|
siteName: string
|
||||||
|
siteDescription: string
|
||||||
|
logoLight: string
|
||||||
|
logoDark: string
|
||||||
|
favicon: string
|
||||||
|
}
|
||||||
|
|
||||||
interface SiteSettings {
|
interface SiteSettings {
|
||||||
siteName: string
|
siteName: string
|
||||||
siteDescription: string
|
siteDescription: string
|
||||||
@@ -8,7 +16,6 @@ interface SiteSettings {
|
|||||||
siteFavicon: string
|
siteFavicon: string
|
||||||
logoLight: string
|
logoLight: string
|
||||||
logoDark: string
|
logoDark: string
|
||||||
loaded: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const siteSettings = reactive<SiteSettings>({
|
const siteSettings = reactive<SiteSettings>({
|
||||||
@@ -18,9 +25,62 @@ const siteSettings = reactive<SiteSettings>({
|
|||||||
siteFavicon: '',
|
siteFavicon: '',
|
||||||
logoLight: '',
|
logoLight: '',
|
||||||
logoDark: '',
|
logoDark: '',
|
||||||
loaded: false,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 从 window.__SITE_CONFIG__ 获取后端注入的配置
|
||||||
|
function initFromServerConfig(): boolean {
|
||||||
|
const config = (window as any).__SITE_CONFIG__ as SiteConfig | undefined
|
||||||
|
if (config) {
|
||||||
|
if (config.siteName) {
|
||||||
|
siteSettings.siteName = config.siteName
|
||||||
|
document.title = config.siteName
|
||||||
|
}
|
||||||
|
if (config.siteDescription) {
|
||||||
|
siteSettings.siteDescription = config.siteDescription
|
||||||
|
}
|
||||||
|
if (config.logoLight) {
|
||||||
|
siteSettings.logoLight = config.logoLight
|
||||||
|
siteSettings.siteLogo = config.logoLight
|
||||||
|
}
|
||||||
|
if (config.logoDark) {
|
||||||
|
siteSettings.logoDark = config.logoDark
|
||||||
|
}
|
||||||
|
if (config.favicon) {
|
||||||
|
siteSettings.siteFavicon = config.favicon
|
||||||
|
updateFavicon(config.favicon)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 localStorage 获取缓存的设置(作为备用)
|
||||||
|
function initFromLocalStorage(): boolean {
|
||||||
|
const storedSettings = localStorage.getItem('systemSettings')
|
||||||
|
if (storedSettings) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(storedSettings)
|
||||||
|
if (parsed.site_name && !siteSettings.siteName) {
|
||||||
|
siteSettings.siteName = parsed.site_name
|
||||||
|
}
|
||||||
|
if (parsed.site_description && !siteSettings.siteDescription) {
|
||||||
|
siteSettings.siteDescription = parsed.site_description
|
||||||
|
}
|
||||||
|
if (parsed.site_logo && !siteSettings.siteLogo) {
|
||||||
|
siteSettings.siteLogo = parsed.site_logo
|
||||||
|
}
|
||||||
|
if (parsed.site_favicon && !siteSettings.siteFavicon) {
|
||||||
|
siteSettings.siteFavicon = parsed.site_favicon
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error('Failed to parse systemSettings from localStorage', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
function updateFavicon(favicon: string) {
|
function updateFavicon(favicon: string) {
|
||||||
if (!favicon)
|
if (!favicon)
|
||||||
return
|
return
|
||||||
@@ -38,7 +98,6 @@ function updateFavicon(favicon: string) {
|
|||||||
link.href = getFileUrl(favicon)
|
link.href = getFileUrl(favicon)
|
||||||
head.appendChild(link)
|
head.appendChild(link)
|
||||||
|
|
||||||
// 同时添加 icon 类型的 link
|
|
||||||
const linkIcon = document.createElement('link')
|
const linkIcon = document.createElement('link')
|
||||||
linkIcon.type = 'image/x-icon'
|
linkIcon.type = 'image/x-icon'
|
||||||
linkIcon.rel = 'icon'
|
linkIcon.rel = 'icon'
|
||||||
@@ -46,129 +105,33 @@ function updateFavicon(favicon: string) {
|
|||||||
head.appendChild(linkIcon)
|
head.appendChild(linkIcon)
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTitle(title?: string) {
|
// 初始化系统设置
|
||||||
if (title) {
|
function initSiteSettings() {
|
||||||
document.title = title
|
|
||||||
} else if (siteSettings.siteName) {
|
|
||||||
document.title = siteSettings.siteName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function applySettings(settings: Partial<SiteSettings>) {
|
|
||||||
if (settings.siteName) {
|
|
||||||
siteSettings.siteName = settings.siteName
|
|
||||||
updateTitle(settings.siteName)
|
|
||||||
}
|
|
||||||
if (settings.siteDescription) {
|
|
||||||
siteSettings.siteDescription = settings.siteDescription
|
|
||||||
}
|
|
||||||
if (settings.siteLogo) {
|
|
||||||
siteSettings.siteLogo = settings.siteLogo
|
|
||||||
}
|
|
||||||
if (settings.siteFavicon) {
|
|
||||||
siteSettings.siteFavicon = settings.siteFavicon
|
|
||||||
updateFavicon(settings.siteFavicon)
|
|
||||||
}
|
|
||||||
if (settings.logoLight) {
|
|
||||||
siteSettings.logoLight = settings.logoLight
|
|
||||||
}
|
|
||||||
if (settings.logoDark) {
|
|
||||||
siteSettings.logoDark = settings.logoDark
|
|
||||||
}
|
|
||||||
siteSettings.loaded = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从 window.__SITE_CONFIG__ 获取初始配置(由后端注入)
|
|
||||||
function initFromServerConfig() {
|
|
||||||
const config = (window as any).__SITE_CONFIG__
|
|
||||||
if (config) {
|
|
||||||
applySettings({
|
|
||||||
siteName: config.siteName || '',
|
|
||||||
siteDescription: config.siteDescription || '',
|
|
||||||
siteLogo: config.logoLight || config.logoDark || '',
|
|
||||||
logoLight: config.logoLight || '',
|
|
||||||
logoDark: config.logoDark || '',
|
|
||||||
favicon: config.favicon || '',
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从 localStorage 获取缓存的设置
|
|
||||||
function initFromLocalStorage() {
|
|
||||||
const storedSettings = localStorage.getItem('systemSettings')
|
|
||||||
if (storedSettings) {
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(storedSettings)
|
|
||||||
applySettings({
|
|
||||||
siteName: parsed.site_name || '',
|
|
||||||
siteDescription: parsed.site_description || '',
|
|
||||||
siteLogo: parsed.site_logo || '',
|
|
||||||
siteFavicon: parsed.site_favicon || '',
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error('Failed to parse systemSettings from localStorage', e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从 API 获取最新设置
|
|
||||||
async function fetchSettings() {
|
|
||||||
try {
|
|
||||||
const response = await fetch('/api/v1/dev/system-settings', {
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${localStorage.getItem('token')}`,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const data = await response.json()
|
|
||||||
if (data.code === 200 && data.data) {
|
|
||||||
const settings = {
|
|
||||||
site_name: data.data.site_name || '',
|
|
||||||
site_description: data.data.site_description || '',
|
|
||||||
site_logo: data.data.site_logo || '',
|
|
||||||
site_favicon: data.data.site_favicon || '',
|
|
||||||
}
|
|
||||||
localStorage.setItem('systemSettings', JSON.stringify(settings))
|
|
||||||
applySettings({
|
|
||||||
siteName: settings.site_name,
|
|
||||||
siteDescription: settings.site_description,
|
|
||||||
siteLogo: settings.site_logo,
|
|
||||||
siteFavicon: settings.site_favicon,
|
|
||||||
})
|
|
||||||
// 触发事件通知其他组件
|
|
||||||
window.dispatchEvent(new CustomEvent('system-settings-changed', { detail: settings }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error('Failed to fetch system settings:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化系统设置(在应用启动时调用)
|
|
||||||
async function initSiteSettings() {
|
|
||||||
// 优先从后端注入的配置获取
|
// 优先从后端注入的配置获取
|
||||||
const hasServerConfig = initFromServerConfig()
|
initFromServerConfig()
|
||||||
|
|
||||||
// 然后从 localStorage 获取缓存
|
// 如果后端没有注入配置,从 localStorage 获取
|
||||||
const hasLocalConfig = initFromLocalStorage()
|
if (!siteSettings.siteName) {
|
||||||
|
initFromLocalStorage()
|
||||||
// 如果都没有,尝试从 API 获取
|
|
||||||
if (!hasServerConfig && !hasLocalConfig) {
|
|
||||||
await fetchSettings()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听设置变化
|
// 监听设置变化(来自系统设置页面的更新)
|
||||||
window.addEventListener('system-settings-changed', ((event: CustomEvent) => {
|
window.addEventListener('system-settings-changed', ((event: CustomEvent) => {
|
||||||
applySettings({
|
const settings = event.detail
|
||||||
siteName: event.detail.site_name,
|
if (settings.site_name) {
|
||||||
siteDescription: event.detail.site_description,
|
siteSettings.siteName = settings.site_name
|
||||||
siteLogo: event.detail.site_logo,
|
}
|
||||||
siteFavicon: event.detail.site_favicon,
|
if (settings.site_description) {
|
||||||
})
|
siteSettings.siteDescription = settings.site_description
|
||||||
|
}
|
||||||
|
if (settings.site_logo) {
|
||||||
|
siteSettings.siteLogo = settings.site_logo
|
||||||
|
siteSettings.logoLight = settings.site_logo
|
||||||
|
}
|
||||||
|
if (settings.site_favicon) {
|
||||||
|
siteSettings.siteFavicon = settings.site_favicon
|
||||||
|
updateFavicon(settings.site_favicon)
|
||||||
|
}
|
||||||
}) as EventListener)
|
}) as EventListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,12 +146,25 @@ function getPageTitle(pageTitle?: string): string {
|
|||||||
return pageTitle || ''
|
return pageTitle || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取 logo(根据主题自动选择)
|
||||||
|
function getLogo(isDark: boolean): string {
|
||||||
|
if (isDark && siteSettings.logoDark) {
|
||||||
|
return getFileUrl(siteSettings.logoDark)
|
||||||
|
}
|
||||||
|
if (siteSettings.logoLight) {
|
||||||
|
return getFileUrl(siteSettings.logoLight)
|
||||||
|
}
|
||||||
|
if (siteSettings.siteLogo) {
|
||||||
|
return getFileUrl(siteSettings.siteLogo)
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
export function useSiteSettings() {
|
export function useSiteSettings() {
|
||||||
return {
|
return {
|
||||||
siteSettings,
|
siteSettings,
|
||||||
initSiteSettings,
|
initSiteSettings,
|
||||||
updateTitle,
|
|
||||||
getPageTitle,
|
getPageTitle,
|
||||||
fetchSettings,
|
getLogo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Vendored
+1
@@ -78,6 +78,7 @@ declare global {
|
|||||||
const useRoute: typeof import('vue-router').useRoute
|
const useRoute: typeof import('vue-router').useRoute
|
||||||
const useRouter: typeof import('vue-router').useRouter
|
const useRouter: typeof import('vue-router').useRouter
|
||||||
const useSidebar: typeof import('../composables/use-sidebar').useSidebar
|
const useSidebar: typeof import('../composables/use-sidebar').useSidebar
|
||||||
|
const useSiteSettings: typeof import('../composables/use-site-settings').useSiteSettings
|
||||||
const useSlots: typeof import('vue').useSlots
|
const useSlots: typeof import('vue').useSlots
|
||||||
const useSystemTheme: typeof import('../composables/use-system-theme').useSystemTheme
|
const useSystemTheme: typeof import('../composables/use-system-theme').useSystemTheme
|
||||||
const useTemplateRef: typeof import('vue').useTemplateRef
|
const useTemplateRef: typeof import('vue').useTemplateRef
|
||||||
|
|||||||
Reference in New Issue
Block a user