// composables/composSystemTheme.ts import type { Ref } from "vue"; import { ref, computed, watch, onMounted } from "vue"; import { useState } from "#imports"; type Theme = { name: string; title: string; subTitle: string; logo: { light: string; dark: string; }; font: string; fontFiles: Array<{ weight: string; style: string; src: string }>; colors: { primary: Record< | "50" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900" | "950", string >; }; }; export function composSystemTheme() { const currentTheme = useState("system-theme", () => null); const isDark = useState("is-dark", () => false); const isReady = ref(false); onMounted(() => { const saved = localStorage.getItem("theme-mode"); const shouldBeDark = saved === "dark"; if (isDark.value !== shouldBeDark) { isDark.value = shouldBeDark; } isReady.value = true; }); // فقط هنگامی که کاربر دستی تم را تغییر داد، ذخیره کن watch( () => isDark.value, (val) => { if (!isReady.value || process.server) return; localStorage.setItem("theme-mode", val ? "dark" : "light"); const root = document.documentElement; val ? root.classList.add("dark") : root.classList.remove("dark"); }, { immediate: false } ); const toggleDarkMode = () => { isDark.value = !isDark.value; }; const applyTheme = async () => { const system = useRuntimeConfig().public.system as string; if (!system) { console.warn("No system specified in runtime config"); return; } try { // 🔹 دقت: مسیر دقیقاً ~/assets/${system}/theme.json const themeModule = await import(`~/assets/${system}/theme.json`); const theme = themeModule.default || themeModule; if (process.client) { const root = document.documentElement; // رنگ‌ها Object.entries(theme.colors.primary).forEach(([key, value]) => { root.style.setProperty(`--color-primary-${key}`, value); }); // فونت if (theme.font && theme.fontFiles) { root.style.setProperty("--app-font", theme.font); const fontId = `font-${theme.font}`; if (!document.getElementById(fontId)) { const style = document.createElement("style"); style.id = fontId; let rules = ""; theme.fontFiles.forEach((file) => { rules += ` @font-face { font-family: "${theme.font}"; src: url("${file.src}") format("woff2"); font-weight: ${file.weight}; font-style: ${file.style}; font-display: swap; } `; }); style.textContent = rules; document.head.appendChild(style); } } } currentTheme.value = theme; return theme; } catch (error) { console.error(`Failed to load theme for system: ${system}`, error); } }; const logo = computed(() => { if (!currentTheme.value) return ""; return isDark.values ? currentTheme.value.logo.dark : currentTheme.value.logo.light; }); const primaryColor = computed(() => { return currentTheme.value?.colors.primary["500"] || "#3b82f6"; }); return { applyTheme, currentTheme: currentTheme as Ref, isDark, toggleDarkMode, logo, primaryColor, }; }