EDMS/composables/useSiteSettings.js
2025-05-30 04:23:17 +00:00

363 lines
14 KiB
JavaScript

export const useSiteSettings = () => {
// Global site settings state
const siteSettings = useState('siteSettings', () => ({
siteName: 'corradAF',
siteDescription: 'corradAF Base Project',
siteLogo: '',
siteLoginLogo: '',
siteLoadingLogo: '',
siteFavicon: '',
showSiteNameInHeader: true,
siteNameFontSize: 18,
customCSS: '',
selectedTheme: 'biasa', // Use existing theme system
customThemeFile: '',
currentFont: '',
fontSource: '',
// SEO fields
seoTitle: '',
seoDescription: '',
seoKeywords: '',
seoAuthor: '',
seoOgImage: '',
seoTwitterCard: 'summary_large_image',
seoCanonicalUrl: '',
seoRobots: 'index, follow',
seoGoogleAnalytics: '',
seoGoogleTagManager: '',
seoFacebookPixel: ''
}));
// Loading state
const loading = useState('siteSettingsLoading', () => false);
// Load site settings from API
const loadSiteSettings = async () => {
loading.value = true;
try {
const response = await $fetch("/api/devtool/config/site-settings", {
method: "GET",
});
if (response && response.data) {
siteSettings.value = { ...siteSettings.value, ...response.data };
applyThemeSettings();
updateGlobalMeta();
}
} catch (error) {
console.error("Error loading site settings:", error);
} finally {
loading.value = false;
}
};
// Update global meta tags and SEO
const updateGlobalMeta = () => {
if (process.client) {
// Update page title - use SEO title if available
const title = siteSettings.value.seoTitle || siteSettings.value.siteName;
if (title) {
document.title = title;
// Update meta description - use SEO description if available
let metaDescription = document.querySelector('meta[name="description"]');
if (!metaDescription) {
metaDescription = document.createElement('meta');
metaDescription.name = 'description';
document.head.appendChild(metaDescription);
}
metaDescription.content = siteSettings.value.seoDescription || siteSettings.value.siteDescription || title;
// Update keywords meta tag
if (siteSettings.value.seoKeywords) {
let keywordsMeta = document.querySelector('meta[name="keywords"]');
if (!keywordsMeta) {
keywordsMeta = document.createElement('meta');
keywordsMeta.name = 'keywords';
document.head.appendChild(keywordsMeta);
}
keywordsMeta.content = siteSettings.value.seoKeywords;
}
// Update author meta tag
if (siteSettings.value.seoAuthor) {
let authorMeta = document.querySelector('meta[name="author"]');
if (!authorMeta) {
authorMeta = document.createElement('meta');
authorMeta.name = 'author';
document.head.appendChild(authorMeta);
}
authorMeta.content = siteSettings.value.seoAuthor;
}
// Update robots meta tag
let robotsMeta = document.querySelector('meta[name="robots"]');
if (!robotsMeta) {
robotsMeta = document.createElement('meta');
robotsMeta.name = 'robots';
document.head.appendChild(robotsMeta);
}
robotsMeta.content = siteSettings.value.seoRobots;
// Update Open Graph tags
let ogTitle = document.querySelector('meta[property="og:title"]');
if (!ogTitle) {
ogTitle = document.createElement('meta');
ogTitle.setAttribute('property', 'og:title');
document.head.appendChild(ogTitle);
}
ogTitle.content = title;
let ogDescription = document.querySelector('meta[property="og:description"]');
if (!ogDescription) {
ogDescription = document.createElement('meta');
ogDescription.setAttribute('property', 'og:description');
document.head.appendChild(ogDescription);
}
ogDescription.content = siteSettings.value.seoDescription || siteSettings.value.siteDescription || title;
// Update OG image
if (siteSettings.value.seoOgImage) {
let ogImage = document.querySelector('meta[property="og:image"]');
if (!ogImage) {
ogImage = document.createElement('meta');
ogImage.setAttribute('property', 'og:image');
document.head.appendChild(ogImage);
}
ogImage.content = siteSettings.value.seoOgImage;
}
// Update Twitter Card tags
let twitterCard = document.querySelector('meta[name="twitter:card"]');
if (!twitterCard) {
twitterCard = document.createElement('meta');
twitterCard.name = 'twitter:card';
document.head.appendChild(twitterCard);
}
twitterCard.content = siteSettings.value.seoTwitterCard;
let twitterTitle = document.querySelector('meta[name="twitter:title"]');
if (!twitterTitle) {
twitterTitle = document.createElement('meta');
twitterTitle.name = 'twitter:title';
document.head.appendChild(twitterTitle);
}
twitterTitle.content = title;
let twitterDescription = document.querySelector('meta[name="twitter:description"]');
if (!twitterDescription) {
twitterDescription = document.createElement('meta');
twitterDescription.name = 'twitter:description';
document.head.appendChild(twitterDescription);
}
twitterDescription.content = siteSettings.value.seoDescription || siteSettings.value.siteDescription || title;
// Update canonical URL
if (siteSettings.value.seoCanonicalUrl) {
let canonicalLink = document.querySelector('link[rel="canonical"]');
if (!canonicalLink) {
canonicalLink = document.createElement('link');
canonicalLink.rel = 'canonical';
document.head.appendChild(canonicalLink);
}
canonicalLink.href = siteSettings.value.seoCanonicalUrl;
}
}
// Update favicon
if (siteSettings.value.siteFavicon) {
let faviconLink = document.querySelector("link[rel*='icon']");
if (!faviconLink) {
faviconLink = document.createElement('link');
faviconLink.rel = 'icon';
document.head.appendChild(faviconLink);
}
faviconLink.href = siteSettings.value.siteFavicon;
// Update apple touch icon
let appleTouchIcon = document.querySelector("link[rel='apple-touch-icon']");
if (!appleTouchIcon) {
appleTouchIcon = document.createElement('link');
appleTouchIcon.rel = 'apple-touch-icon';
document.head.appendChild(appleTouchIcon);
}
appleTouchIcon.href = siteSettings.value.siteFavicon;
}
// Apply analytics scripts
if (siteSettings.value.seoGoogleAnalytics) {
// Add Google Analytics
const script = document.createElement('script');
script.async = true;
script.src = `https://www.googletagmanager.com/gtag/js?id=${siteSettings.value.seoGoogleAnalytics}`;
document.head.appendChild(script);
const gtag = document.createElement('script');
gtag.textContent = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${siteSettings.value.seoGoogleAnalytics}');
`;
document.head.appendChild(gtag);
}
if (siteSettings.value.seoGoogleTagManager) {
// Add Google Tag Manager
const gtmScript = document.createElement('script');
gtmScript.textContent = `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${siteSettings.value.seoGoogleTagManager}');
`;
document.head.appendChild(gtmScript);
}
if (siteSettings.value.seoFacebookPixel) {
// Add Facebook Pixel
const fbScript = document.createElement('script');
fbScript.textContent = `
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '${siteSettings.value.seoFacebookPixel}');
fbq('track', 'PageView');
`;
document.head.appendChild(fbScript);
}
}
};
// Apply theme settings to the document
const applyThemeSettings = () => {
if (process.client) {
// Apply selected theme using existing theme system
if (siteSettings.value.selectedTheme) {
document.documentElement.setAttribute("data-theme", siteSettings.value.selectedTheme);
localStorage.setItem("theme", siteSettings.value.selectedTheme);
}
// Apply custom theme file if exists (append to theme.css)
if (siteSettings.value.customThemeFile) {
let customThemeElement = document.getElementById('custom-theme-file');
if (!customThemeElement) {
customThemeElement = document.createElement('link');
customThemeElement.id = 'custom-theme-file';
customThemeElement.rel = 'stylesheet';
customThemeElement.type = 'text/css';
document.head.appendChild(customThemeElement);
}
customThemeElement.href = siteSettings.value.customThemeFile;
} else {
// Remove custom theme file if it exists
const existingThemeElement = document.getElementById('custom-theme-file');
if (existingThemeElement) {
existingThemeElement.remove();
}
}
// Apply custom CSS
let customStyleElement = document.getElementById('custom-site-styles');
if (!customStyleElement) {
customStyleElement = document.createElement('style');
customStyleElement.id = 'custom-site-styles';
document.head.appendChild(customStyleElement);
}
customStyleElement.textContent = siteSettings.value.customCSS || '';
}
};
// Set theme (integrate with existing theme system)
const setTheme = (theme) => {
siteSettings.value.selectedTheme = theme;
applyThemeSettings();
// Optionally save to server
updateSiteSettings(siteSettings.value);
};
// Get current theme
const getCurrentTheme = () => {
return siteSettings.value.selectedTheme || 'biasa';
};
// Update site settings
const updateSiteSettings = async (newSettings) => {
console.log("[useSiteSettings] updateSiteSettings called with:", JSON.parse(JSON.stringify(newSettings)));
try {
const response = await $fetch("/api/devtool/config/site-settings", {
method: "POST",
body: newSettings,
});
console.log("[useSiteSettings] API response received:", JSON.parse(JSON.stringify(response)));
if (response && response.data) {
siteSettings.value = { ...siteSettings.value, ...response.data };
applyThemeSettings();
updateGlobalMeta();
console.log("[useSiteSettings] Returning success from updateSiteSettings.");
return { success: true, data: response.data };
}
let errorMessage = "Update operation failed: No data returned from server.";
if (response && typeof response === 'object' && response !== null && 'message' in response) {
errorMessage = response.message;
} else if (response) {
errorMessage = "Update operation failed: Unexpected server response format on success.";
} else if (response === undefined) {
errorMessage = "Update failed: Server returned no content (e.g. 204). Treating as failure as data is expected for settings.";
console.log("[useSiteSettings] Returning failure (204 or undefined response) from updateSiteSettings.");
return { success: false, error: { message: errorMessage, details: response } };
}
console.log("[useSiteSettings] Returning failure (general case) from updateSiteSettings:", errorMessage);
return { success: false, error: { message: errorMessage, details: response } };
} catch (error) {
console.error("[useSiteSettings] Error in updateSiteSettings catch block:", error);
let detailedMessage = "An unexpected error occurred during update.";
if (error.data && error.data.message) {
detailedMessage = error.data.message;
} else if (error.message) {
detailedMessage = error.message;
}
console.log("[useSiteSettings] Returning failure (catch block) from updateSiteSettings:", detailedMessage);
return { success: false, error: { message: detailedMessage, details: error } };
}
};
// Add custom theme to theme.css file
const addCustomThemeToFile = async (themeName, themeCSS) => {
try {
const response = await $fetch("/api/devtool/config/add-custom-theme", {
method: "POST",
body: {
themeName,
themeCSS
}
});
return response;
} catch (error) {
console.error("Error adding custom theme:", error);
return { success: false, error };
}
};
return {
siteSettings,
loading: readonly(loading),
loadSiteSettings,
updateSiteSettings,
applyThemeSettings,
updateGlobalMeta,
getCurrentTheme,
setTheme,
addCustomThemeToFile
};
};