x
This commit is contained in:
1 parent
e87176dba3
commit
80e715da76
3 files changed
+59
-8
No files matched your search
@@ -1,9 +1,12 @@
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import { API_BASE } from '@homaroma/types'
|
import { API_BASE } from '@homaroma/types'
|
||||||
|
|
||||||
export default function ThemeInjector() {
|
export default function ThemeInjector() {
|
||||||
|
const { i18n } = useTranslation()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const lang = localStorage.getItem('app_lang') || 'en'
|
const lang = i18n.language || localStorage.getItem('app_lang') || 'en'
|
||||||
|
|
||||||
fetch(`${API_BASE}/settings?lang=${lang}`)
|
fetch(`${API_BASE}/settings?lang=${lang}`)
|
||||||
.then(res => res.ok ? res.json() : null)
|
.then(res => res.ok ? res.json() : null)
|
||||||
@@ -11,6 +14,52 @@ export default function ThemeInjector() {
|
|||||||
if (!settings) return
|
if (!settings) return
|
||||||
const root = document.documentElement
|
const root = document.documentElement
|
||||||
|
|
||||||
|
// --- Global SEO & Document Title ---
|
||||||
|
const pageTitle = settings.defaultSeoTitle || settings.brandName
|
||||||
|
if (pageTitle) {
|
||||||
|
document.title = pageTitle
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.defaultSeoDescription) {
|
||||||
|
let metaDesc = document.querySelector('meta[name="description"]')
|
||||||
|
if (!metaDesc) {
|
||||||
|
metaDesc = document.createElement('meta')
|
||||||
|
metaDesc.setAttribute('name', 'description')
|
||||||
|
document.head.appendChild(metaDesc)
|
||||||
|
}
|
||||||
|
metaDesc.setAttribute('content', settings.defaultSeoDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageTitle) {
|
||||||
|
let ogTitle = document.querySelector('meta[property="og:title"]')
|
||||||
|
if (!ogTitle) {
|
||||||
|
ogTitle = document.createElement('meta')
|
||||||
|
ogTitle.setAttribute('property', 'og:title')
|
||||||
|
document.head.appendChild(ogTitle)
|
||||||
|
}
|
||||||
|
ogTitle.setAttribute('content', pageTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.defaultSeoDescription) {
|
||||||
|
let ogDesc = document.querySelector('meta[property="og:description"]')
|
||||||
|
if (!ogDesc) {
|
||||||
|
ogDesc = document.createElement('meta')
|
||||||
|
ogDesc.setAttribute('property', 'og:description')
|
||||||
|
document.head.appendChild(ogDesc)
|
||||||
|
}
|
||||||
|
ogDesc.setAttribute('content', settings.defaultSeoDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.defaultOgImage) {
|
||||||
|
let ogImg = document.querySelector('meta[property="og:image"]')
|
||||||
|
if (!ogImg) {
|
||||||
|
ogImg = document.createElement('meta')
|
||||||
|
ogImg.setAttribute('property', 'og:image')
|
||||||
|
document.head.appendChild(ogImg)
|
||||||
|
}
|
||||||
|
ogImg.setAttribute('content', settings.defaultOgImage)
|
||||||
|
}
|
||||||
|
|
||||||
// --- Theme tokens ---
|
// --- Theme tokens ---
|
||||||
const tokens = settings?.themeTokens
|
const tokens = settings?.themeTokens
|
||||||
if (tokens && typeof tokens === 'object') {
|
if (tokens && typeof tokens === 'object') {
|
||||||
@@ -48,8 +97,8 @@ export default function ThemeInjector() {
|
|||||||
root.style.setProperty('--scroll-reveal-style', style)
|
root.style.setProperty('--scroll-reveal-style', style)
|
||||||
root.style.setProperty('--scroll-reveal-duration', `${duration}ms`)
|
root.style.setProperty('--scroll-reveal-duration', `${duration}ms`)
|
||||||
})
|
})
|
||||||
.catch(err => console.error('Failed to inject theme in SPA:', err))
|
.catch(err => console.error('Failed to inject theme/SEO in SPA:', err))
|
||||||
}, [])
|
}, [i18n.language])
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -12,20 +12,21 @@ import type { CSSProperties } from 'react';
|
|||||||
export async function generateMetadata({ params }: { params: Promise<{ lang: string }> }): Promise<Metadata> {
|
export async function generateMetadata({ params }: { params: Promise<{ lang: string }> }): Promise<Metadata> {
|
||||||
const { lang } = await params;
|
const { lang } = await params;
|
||||||
const settings = await getStoreSettings(lang);
|
const settings = await getStoreSettings(lang);
|
||||||
const brandName = settings?.brandName || '';
|
const brandName = settings?.brandName || 'HomAroma';
|
||||||
|
const defaultTitle = settings?.defaultSeoTitle || brandName;
|
||||||
const description = settings?.defaultSeoDescription || settings?.footerDescription || 'Pure Origins, Artisan Craft, Zero Compromise';
|
const description = settings?.defaultSeoDescription || settings?.footerDescription || 'Pure Origins, Artisan Craft, Zero Compromise';
|
||||||
const ogImage = settings?.defaultOgImage;
|
const ogImage = settings?.defaultOgImage;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: {
|
title: {
|
||||||
template: `%s | ${brandName}`,
|
template: `%s | ${brandName}`,
|
||||||
default: brandName,
|
default: defaultTitle,
|
||||||
},
|
},
|
||||||
description,
|
description,
|
||||||
metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'),
|
metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'),
|
||||||
openGraph: ogImage
|
openGraph: ogImage
|
||||||
? {
|
? {
|
||||||
title: brandName,
|
title: defaultTitle,
|
||||||
description,
|
description,
|
||||||
images: [ogImage],
|
images: [ogImage],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|||||||
getStoreSettings(lang),
|
getStoreSettings(lang),
|
||||||
])
|
])
|
||||||
|
|
||||||
const title = page?.seoTitle || page?.title || undefined
|
const title = page?.seoTitle || settings?.defaultSeoTitle || (page?.title && page.title !== 'Home' && page.title !== 'หน้าแรก' ? page.title : undefined) || settings?.brandName || undefined
|
||||||
const description =
|
const description =
|
||||||
page?.seoDescription ||
|
page?.seoDescription ||
|
||||||
settings?.defaultSeoDescription ||
|
settings?.defaultSeoDescription ||
|
||||||
|
settings?.footerDescription ||
|
||||||
(settings?.brandName ? `${settings.brandName} - Pure Origins, Artisan Craft` : 'Pure Origins, Artisan Craft')
|
(settings?.brandName ? `${settings.brandName} - Pure Origins, Artisan Craft` : 'Pure Origins, Artisan Craft')
|
||||||
const ogImage = page?.ogImageUrl || settings?.defaultOgImage
|
const ogImage = page?.ogImageUrl || settings?.defaultOgImage
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|||||||
lang,
|
lang,
|
||||||
openGraph: ogImage
|
openGraph: ogImage
|
||||||
? {
|
? {
|
||||||
title: page?.seoTitle || page?.title || settings?.brandName || undefined,
|
title,
|
||||||
description,
|
description,
|
||||||
images: [ogImage],
|
images: [ogImage],
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user