feat(waas): add catch-all route, page manager and draft-publish pipeline
This commit is contained in:
115
src/pages/[...slug].astro
Normal file
115
src/pages/[...slug].astro
Normal file
@@ -0,0 +1,115 @@
|
||||
---
|
||||
// src/pages/[...slug].astro
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import { loadWaasConfigs } from '../utils/configLoader';
|
||||
import { resolveDynamicBinding } from '../utils/dynamicDataBinding';
|
||||
|
||||
// Component Registry Import (Zero-Sumpf & Modular)
|
||||
import HeroSection from '../components/sections/HeroSection.astro';
|
||||
import BentoGrid from '../components/sections/BentoGrid.astro';
|
||||
import ContactSection from '../components/sections/ContactSection.astro';
|
||||
import FallbackSection from '../components/sections/FallbackSection.astro';
|
||||
|
||||
// Strikter SSR-Modus für Instant-Updates ohne Re-Build
|
||||
export const prerender = false;
|
||||
|
||||
// 1. Slug aus der URL auslesen
|
||||
const { slug } = Astro.params;
|
||||
|
||||
// 2. Config aus /app/data/site.config.json oder site.config.draft.json laden
|
||||
const userAgent = Astro.request.headers.get('user-agent') ?? '';
|
||||
const isDraft = Astro.url.searchParams.get('preview') === 'draft';
|
||||
const { siteConfig } = loadWaasConfigs(userAgent, isDraft);
|
||||
|
||||
// Helper function to resolve dynamic data recursively in settings or objects
|
||||
function resolveDynamicData(settings: any, dynamicBindings: any, config: any): any {
|
||||
if (!settings) return settings;
|
||||
const context = { site: config, ...config };
|
||||
|
||||
if (typeof settings === 'string') {
|
||||
return resolveDynamicBinding(settings, context);
|
||||
}
|
||||
|
||||
if (Array.isArray(settings)) {
|
||||
return settings.map((item) => resolveDynamicData(item, dynamicBindings, config));
|
||||
}
|
||||
|
||||
if (typeof settings === 'object') {
|
||||
const resolved: Record<string, any> = {};
|
||||
for (const [key, value] of Object.entries(settings)) {
|
||||
resolved[key] = resolveDynamicData(value, dynamicBindings, config);
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
// 3. Normalized Slug-Handling: "/" für Startseite, sonst z.B. "leistungen"
|
||||
const currentSlug = slug === undefined || slug === '' ? '/' : slug.replace(/\/$/, '');
|
||||
|
||||
// 4. Richtige Seite im pages-Array ermitteln (falls vorhanden, sonst Fallback auf Hauptkonfiguration)
|
||||
const pages = (siteConfig as any).pages || [
|
||||
{
|
||||
id: (siteConfig as any).homepage_id || 'home',
|
||||
slug: '/',
|
||||
title: siteConfig.siteName,
|
||||
is_published: true,
|
||||
sections: siteConfig.sectionsOrder.map((secType: string) => ({
|
||||
id: secType,
|
||||
type: secType,
|
||||
settings: (siteConfig as any)[secType] || {}
|
||||
}))
|
||||
}
|
||||
];
|
||||
|
||||
let page = pages.find((p: any) => {
|
||||
if (currentSlug === '/') {
|
||||
// Startseiten-Mapping über homepage_id oder Slug "/"
|
||||
return p.id === (siteConfig as any).homepage_id || p.slug === '/' || p.slug === '';
|
||||
}
|
||||
return p.slug === currentSlug || p.slug === `/${currentSlug}`;
|
||||
});
|
||||
|
||||
// 5. Zero-Crash Fallback Guard: Wenn Seite fehlt oder unveröffentlicht ist
|
||||
if (!page || (page.is_published === false && import.meta.env.PROD)) {
|
||||
return Astro.redirect('/404');
|
||||
}
|
||||
|
||||
// 6. Dynamic Component Registry Mapping
|
||||
const ComponentRegistry: Record<string, any> = {
|
||||
hero: HeroSection,
|
||||
bento: BentoGrid,
|
||||
contact: ContactSection,
|
||||
HeroSection,
|
||||
BentoGrid,
|
||||
ContactSection
|
||||
};
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={page.title || siteConfig.siteName || 'N&D IT Solutions'}
|
||||
description={page.seo?.description || siteConfig.metaDescription || ''}
|
||||
ogImage={page.seo?.og_image || ''}
|
||||
>
|
||||
<main id="main-content" role="main" class="min-h-screen">
|
||||
{
|
||||
page.sections && page.sections.length > 0 ? (
|
||||
page.sections.map((section: any) => {
|
||||
const Component = ComponentRegistry[section.type] || FallbackSection;
|
||||
|
||||
// Löse Platzhalter & DB-Bindings aus /admin/ live auf
|
||||
const resolvedSettings = resolveDynamicData(
|
||||
section.settings || {},
|
||||
section.dynamic_bindings || {},
|
||||
siteConfig
|
||||
);
|
||||
|
||||
return <Component id={section.id} settings={resolvedSettings} {...resolvedSettings} />;
|
||||
})
|
||||
) : (
|
||||
<FallbackSection message="Diese Seite enthält aktuell noch keine Abschnitte." />
|
||||
)
|
||||
}
|
||||
</main>
|
||||
</Layout>
|
||||
Reference in New Issue
Block a user