240 lines
6.0 KiB
TypeScript
240 lines
6.0 KiB
TypeScript
import { writeFile } from 'fs/promises';
|
||
import path from 'path';
|
||
|
||
interface Event {
|
||
title: string;
|
||
date: string;
|
||
description: string;
|
||
imageUrl: string;
|
||
}
|
||
|
||
interface GalleryImage {
|
||
imageUrl: string;
|
||
altText: string;
|
||
}
|
||
|
||
interface ContentSection {
|
||
[key: string]: any;
|
||
}
|
||
|
||
export class FileGeneratorService {
|
||
|
||
escapeQuotes(str: string): string {
|
||
return str.replace(/"/g, '\\"');
|
||
}
|
||
|
||
escapeBackticks(str: string): string {
|
||
return str.replace(/`/g, '\\`').replace(/\${/g, '\\${');
|
||
}
|
||
|
||
generateIndexAstro(events: Event[], images: GalleryImage[]): string {
|
||
const eventsCode = events.map(e => `\t{
|
||
\t\timage: "${e.imageUrl}",
|
||
\t\ttitle: "${this.escapeQuotes(e.title)}",
|
||
\t\tdate: "${e.date}",
|
||
\t\tdescription: \`
|
||
\t\t\t${this.escapeBackticks(e.description)}
|
||
\t\t\`,
|
||
\t}`).join(',\n');
|
||
|
||
const imagesCode = images.map(g =>
|
||
`\t{ src: "${g.imageUrl}", alt: "${this.escapeQuotes(g.altText)}" }`
|
||
).join(',\n');
|
||
|
||
return `---
|
||
import Layout from "../components/Layout.astro";
|
||
import Hero from "../components/Hero.astro";
|
||
import Welcome from "../components/Welcome.astro";
|
||
import EventsGrid from "../components/EventsGrid.astro";
|
||
import Drinks from "../components/Drinks.astro";
|
||
import ImageCarousel from "../components/ImageCarousel.astro";
|
||
import Contact from "../components/Contact.astro";
|
||
import About from "../components/About.astro";
|
||
|
||
const events = [
|
||
${eventsCode}
|
||
];
|
||
|
||
const images = [
|
||
${imagesCode}
|
||
];
|
||
---
|
||
|
||
<Layout>
|
||
\t<Hero id="hero" />
|
||
\t<Welcome id="welcome" />
|
||
\t<EventsGrid id="events" events={events} />
|
||
\t<ImageCarousel id="gallery" images={images} />
|
||
\t<Drinks id="drinks" />
|
||
</Layout>
|
||
`;
|
||
}
|
||
|
||
generateHeroComponent(content: ContentSection): string {
|
||
return `---
|
||
// src/components/Hero.astro
|
||
import "../styles/components/Hero.css"
|
||
|
||
const { id } = Astro.props;
|
||
---
|
||
|
||
<section id={id} class="hero container">
|
||
|
||
\t<div class="hero-overlay">
|
||
|
||
\t\t<div class="hero-content">
|
||
|
||
\t\t\t<h1>${content.heading || 'Dein Irish Pub'}</h1>
|
||
|
||
\t\t\t<p>${content.subheading || 'Im Herzen von St.Gallen'}</p>
|
||
|
||
\t\t\t<a href="#" class="button">Aktuelles ↓</a>
|
||
\t\t</div>
|
||
|
||
\t</div>
|
||
|
||
</section>
|
||
|
||
<style>
|
||
|
||
</style>
|
||
`;
|
||
}
|
||
|
||
generateWelcomeComponent(content: ContentSection): string {
|
||
const highlightsList = (content.highlights || []).map((h: any) =>
|
||
`\t\t\t<li>\n\t\t\t\t<b>${h.title}:</b> ${h.description}\n\t\t\t</li>`
|
||
).join('\n\n');
|
||
|
||
return `---
|
||
// src/components/Welcome.astro
|
||
import "../styles/components/Welcome.css"
|
||
|
||
const { id } = Astro.props;
|
||
---
|
||
|
||
<section id={id} class="welcome container">
|
||
|
||
\t<div class="welcome-text">
|
||
|
||
\t\t<h2>${content.heading1 || 'Herzlich willkommen im'}</h2>
|
||
\t\t<h2>${content.heading2 || 'Gallus Pub!'}</h2>
|
||
|
||
\t\t<p>
|
||
\t\t\t${content.introText || ''}
|
||
\t\t</p>
|
||
|
||
\t\t<p><b>Unsere Highlights:</b></p>
|
||
|
||
\t\t<ul>
|
||
${highlightsList}
|
||
\t\t</ul>
|
||
|
||
\t\t<p>
|
||
\t\t\t${content.closingText || ''}
|
||
\t\t</p>
|
||
|
||
\t</div>
|
||
|
||
|
||
\t<div class="welcome-image">
|
||
\t\t<img src="${content.imageUrl || '/images/Welcome.png'}" alt="Welcome background image" />
|
||
\t</div>
|
||
|
||
</section>
|
||
`;
|
||
}
|
||
|
||
generateDrinksComponent(content: ContentSection): string {
|
||
return `---
|
||
import "../styles/components/Drinks.css"
|
||
|
||
const { id } = Astro.props;
|
||
---
|
||
<section id={id} class="Drinks">
|
||
<h2 class="title">Drinks</h2>
|
||
|
||
<p class="note">
|
||
${content.introText || 'Ob ein frisch gezapftes Pint, ein edler Tropfen Whiskey oder ein gemütliches Glas Wein – hier kannst du in entspannter Atmosphäre das Leben genießen.'}
|
||
</p>
|
||
|
||
<a href="/pdf/Getraenke_Gallus_2025.pdf" class="card-link" target="_blank" rel="noopener noreferrer">Getränkekarte</a>
|
||
|
||
<h3 class="monats-hit">Monats Hit</h3>
|
||
|
||
<div class="mate-vodka">
|
||
<div class="circle" title="${content.monthlySpecialName || 'Mate Vodka'}">
|
||
<img src="${content.monthlySpecialImage || '/images/MonthlyHit.png'}" alt="Monats Hit" class="circle-image" />
|
||
<span class="circle-label"></span>
|
||
</div>
|
||
<div>${content.monthlySpecialName || 'Mate Vodka'}</div>
|
||
</div>
|
||
|
||
<p class="note">
|
||
${content.whiskeyText || 'Für Whisky-Liebhaber haben wir erlesene Sorten aus Schottland und Irland im Angebot.'}
|
||
</p>
|
||
|
||
<div class="circle-row">
|
||
<div class="circle whiskey-circle" title="Whiskey 1">
|
||
<img src="${content.whiskeyImage1 || '/images/Whiskey1.png'}" alt="Whiskey 1" class="circle-image" />
|
||
<span class="circle-label"></span>
|
||
</div>
|
||
<div class="circle whiskey-circle" title="Whiskey 2">
|
||
<img src="${content.whiskeyImage2 || '/images/Whiskey2.png'}" alt="Whiskey 2" class="circle-image" />
|
||
<span class="circle-label"></span>
|
||
</div>
|
||
<div class="circle whiskey-circle" title="Whiskey 3">
|
||
<img src="${content.whiskeyImage3 || '/images/Whiskey3.png'}" alt="Whiskey 3" class="circle-image" />
|
||
<span class="circle-label"></span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
`;
|
||
}
|
||
|
||
async writeFiles(
|
||
workspaceDir: string,
|
||
events: Event[],
|
||
images: GalleryImage[],
|
||
sections: Map<string, ContentSection>
|
||
) {
|
||
// Write index.astro
|
||
const indexContent = this.generateIndexAstro(events, images);
|
||
await writeFile(
|
||
path.join(workspaceDir, 'src/pages/index.astro'),
|
||
indexContent,
|
||
'utf-8'
|
||
);
|
||
|
||
// Write Hero component
|
||
if (sections.has('hero')) {
|
||
const heroContent = this.generateHeroComponent(sections.get('hero')!);
|
||
await writeFile(
|
||
path.join(workspaceDir, 'src/components/Hero.astro'),
|
||
heroContent,
|
||
'utf-8'
|
||
);
|
||
}
|
||
|
||
// Write Welcome component
|
||
if (sections.has('welcome')) {
|
||
const welcomeContent = this.generateWelcomeComponent(sections.get('welcome')!);
|
||
await writeFile(
|
||
path.join(workspaceDir, 'src/components/Welcome.astro'),
|
||
welcomeContent,
|
||
'utf-8'
|
||
);
|
||
}
|
||
|
||
// Write Drinks component
|
||
if (sections.has('drinks')) {
|
||
const drinksContent = this.generateDrinksComponent(sections.get('drinks')!);
|
||
await writeFile(
|
||
path.join(workspaceDir, 'src/components/Drinks.astro'),
|
||
drinksContent,
|
||
'utf-8'
|
||
);
|
||
}
|
||
}
|
||
}
|