Integracja Directus LabAI, naprawa Schema.org, poprawki UI
- Zmiana kolekcji Directus z Laboratorium_AI na LabAI - Usunięcie fallbacku na fake dane — brak wpisów = komunikat - revalidate=0 na stronie głównej (zawsze świeże dane) - BlogPosting przeniesiony do @graph (poprawna spec Schema.org) - Inbox Libredesk zaktualizowany - Hero image-wrap powiększony (scale 1.56) - Dokumentacja projektu w CLAUDE.md Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
const DIRECTUS_URL = 'https://cms.dexterlab.pl'
|
||||
const DOMAIN = 'labai.pro'
|
||||
const BASE_URL = `https://${DOMAIN}`
|
||||
|
||||
const FALLBACK = {
|
||||
name: 'Laboratorium AI',
|
||||
description: 'Automatyzacja procesów biznesowych bez programowania. Wdrażamy AI i no-code w 48h.',
|
||||
logo: `${BASE_URL}/logo.webp`,
|
||||
sameAs: [
|
||||
'https://linkedin.com/company/dexterlab',
|
||||
'https://x.com/dexterlab_pl',
|
||||
'https://facebook.com/dexterlab',
|
||||
],
|
||||
}
|
||||
|
||||
async function fetchSiteData() {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${DIRECTUS_URL}/items/sites?filter[domain][_eq]=${DOMAIN}`,
|
||||
{ next: { revalidate: 3600 } }
|
||||
)
|
||||
if (!res.ok) return null
|
||||
const json = await res.json()
|
||||
return json.data?.[0] ?? null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchArticles() {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${DIRECTUS_URL}/items/LabAI?sort=-date_published&limit=5&fields=Title,Slug`,
|
||||
{ next: { revalidate: 300 } }
|
||||
)
|
||||
if (!res.ok) return []
|
||||
const json = await res.json()
|
||||
return json.data ?? []
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
function buildSchema(site, articles) {
|
||||
const s = site ?? {}
|
||||
const baseUrl = (s.url ?? BASE_URL).replace(/\/$/, '')
|
||||
const name = s.site_name ?? FALLBACK.name
|
||||
const description = s.site_description ?? FALLBACK.description
|
||||
const logo = s.logo ?? { '@type': 'ImageObject', url: FALLBACK.logo }
|
||||
const sameAs = Array.isArray(s.social_links) && s.social_links.length
|
||||
? s.social_links
|
||||
: FALLBACK.sameAs
|
||||
|
||||
const blogPostings = articles.map((a) => ({
|
||||
'@type': 'BlogPosting',
|
||||
'@id': `${baseUrl}/blog/${a.Slug}`,
|
||||
headline: a.Title,
|
||||
url: `${baseUrl}/blog/${a.Slug}`,
|
||||
isPartOf: { '@id': `${baseUrl}/#webpage` },
|
||||
}))
|
||||
|
||||
return {
|
||||
'@context': 'https://schema.org',
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'WebSite',
|
||||
'@id': `${baseUrl}/#website`,
|
||||
url: `${baseUrl}/`,
|
||||
name,
|
||||
publisher: { '@id': `${baseUrl}/#organization` },
|
||||
},
|
||||
{
|
||||
'@type': 'WebPage',
|
||||
'@id': `${baseUrl}/#webpage`,
|
||||
url: `${baseUrl}/`,
|
||||
name,
|
||||
isPartOf: { '@id': `${baseUrl}/#website` },
|
||||
description,
|
||||
},
|
||||
{
|
||||
'@type': 'Organization',
|
||||
'@id': `${baseUrl}/#organization`,
|
||||
name: s.company_name ?? name,
|
||||
url: `${baseUrl}/`,
|
||||
logo,
|
||||
sameAs,
|
||||
...(s.contact && { contactPoint: s.contact }),
|
||||
},
|
||||
...blogPostings,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
export default async function SchemaOrg() {
|
||||
const [site, articles] = await Promise.all([fetchSiteData(), fetchArticles()])
|
||||
const schema = buildSchema(site, articles)
|
||||
|
||||
return (
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user