imlemented step 16 by Gemini
- Template
This commit is contained in:
@ -6,6 +6,8 @@ namespace App\Services;
|
||||
|
||||
use Exception;
|
||||
|
||||
require_once __DIR__ . '/../Utils/Helpers.php';
|
||||
|
||||
class Renderer
|
||||
{
|
||||
private FileStorage $storage;
|
||||
@ -41,13 +43,27 @@ class Renderer
|
||||
$siteCssSource = $this->templatesPath . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . 'site.css';
|
||||
copy($siteCssSource, $assetsDir . DIRECTORY_SEPARATOR . 'site.css');
|
||||
|
||||
// 3. Render HTML
|
||||
// 3. Render Content Sections
|
||||
$sectionsHtml = '';
|
||||
$selectedSections = $projectData['wizard_data']['modules']['sections'] ?? [];
|
||||
|
||||
foreach ($selectedSections as $sectionId) {
|
||||
try {
|
||||
$sectionsHtml .= $this->renderTemplate("sections/{$sectionId}", [
|
||||
'project' => $projectData
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
error_log("Renderer: Failed to render section $sectionId: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Render HTML base template
|
||||
$html = $this->renderTemplate('base', [
|
||||
'project' => $projectData,
|
||||
'content' => '<!-- Final content sections will go here -->'
|
||||
'content' => $sectionsHtml
|
||||
]);
|
||||
|
||||
// 4. Save to exports
|
||||
// 5. Save to exports
|
||||
return file_put_contents($projectExportDir . DIRECTORY_SEPARATOR . 'index.html', $html) !== false;
|
||||
}
|
||||
|
||||
|
||||
@ -8,13 +8,6 @@ $identity = $project['wizard_data']['identity'] ?? [];
|
||||
$contact = $project['wizard_data']['contact'] ?? [];
|
||||
$visuals = $project['wizard_data']['visuals'] ?? [];
|
||||
$assets = $project['wizard_data']['assets'] ?? [];
|
||||
|
||||
// Helper function for safe output
|
||||
if (!function_exists('e')) {
|
||||
function e($value) {
|
||||
return htmlspecialchars((string)($value ?? ''), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="sk">
|
||||
|
||||
@ -81,3 +81,104 @@ footer {
|
||||
padding: 4rem 0;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
/* Section specific */
|
||||
.section-header {
|
||||
text-align: center;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
/* Hero */
|
||||
.hero {
|
||||
background-color: #f3f4f6;
|
||||
text-align: center;
|
||||
padding: 8rem 1.5rem;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 3rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.hero .subtitle {
|
||||
font-size: 1.25rem;
|
||||
color: #4b5563;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
/* Services */
|
||||
.services-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.service-card {
|
||||
padding: 2rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.5rem;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.service-card:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.price {
|
||||
font-weight: 700;
|
||||
color: var(--primary-color);
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* Gallery */
|
||||
.gallery-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.gallery-item img {
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
object-fit: cover;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
/* FAQ */
|
||||
.faq-list {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.faq-item {
|
||||
margin-bottom: 2rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
padding-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
/* Contact */
|
||||
.contact-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 4rem;
|
||||
}
|
||||
|
||||
.contact-form .form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.contact-form input, .contact-form textarea {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.contact-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.hero h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
16
src/Templates/sections/about.php
Normal file
16
src/Templates/sections/about.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $project
|
||||
*/
|
||||
$about = $project['content']['generated']['about'] ?? [];
|
||||
?>
|
||||
<section id="about" class="about">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2><?= e($about['title'] ?? 'O nás') ?></h2>
|
||||
</div>
|
||||
<div class="about-content">
|
||||
<?= nl2br(e($about['text'] ?? $project['wizard_data']['identity']['description'])) ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
51
src/Templates/sections/contact.php
Normal file
51
src/Templates/sections/contact.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $project
|
||||
*/
|
||||
$contact = $project['wizard_data']['contact'] ?? [];
|
||||
$formEnabled = $project['wizard_data']['modules']['contact_form']['enabled'] ?? false;
|
||||
?>
|
||||
<section id="contact" class="contact">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2>Kontakt</h2>
|
||||
</div>
|
||||
<div class="contact-grid">
|
||||
<div class="contact-info">
|
||||
<h3>Kde nás nájdete</h3>
|
||||
<p><strong>Adresa:</strong> <?= e($contact['address']) ?>, <?= e($contact['city']) ?></p>
|
||||
<p><strong>Email:</strong> <a href="mailto:<?= e($contact['email']) ?>"><?= e($contact['email']) ?></a></p>
|
||||
<p><strong>Telefón:</strong> <a href="tel:<?= e($contact['phone']) ?>"><?= e($contact['phone']) ?></a></p>
|
||||
|
||||
<?php if (!empty($contact['socials']['facebook']) || !empty($contact['socials']['instagram'])): ?>
|
||||
<div class="socials">
|
||||
<?php if ($contact['socials']['facebook']): ?>
|
||||
<a href="<?= e($contact['socials']['facebook']) ?>" target="_blank" class="social-link">Facebook</a>
|
||||
<?php endif; ?>
|
||||
<?php if ($contact['socials']['instagram']): ?>
|
||||
<a href="<?= e($contact['socials']['instagram']) ?>" target="_blank" class="social-link">Instagram</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($formEnabled): ?>
|
||||
<div class="contact-form">
|
||||
<h3>Napíšte nám</h3>
|
||||
<form action="ajax.php" method="POST" id="site-contact-form">
|
||||
<div class="form-group">
|
||||
<input type="text" name="name" placeholder="Vaše meno" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="email" name="email" placeholder="Váš email" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<textarea name="message" placeholder="Vaša správa" rows="4" required></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Odoslať správu</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
21
src/Templates/sections/faq.php
Normal file
21
src/Templates/sections/faq.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $project
|
||||
*/
|
||||
$faq = $project['content']['generated']['faq'] ?? [];
|
||||
?>
|
||||
<section id="faq" class="faq">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2>Časté otázky (FAQ)</h2>
|
||||
</div>
|
||||
<div class="faq-list">
|
||||
<?php foreach ($faq as $item): ?>
|
||||
<div class="faq-item">
|
||||
<h3><?= e($item['question']) ?></h3>
|
||||
<p><?= e($item['answer']) ?></p>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
20
src/Templates/sections/gallery.php
Normal file
20
src/Templates/sections/gallery.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $project
|
||||
*/
|
||||
$gallery = $project['wizard_data']['assets']['gallery'] ?? [];
|
||||
?>
|
||||
<section id="gallery" class="gallery">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2>Galéria</h2>
|
||||
</div>
|
||||
<div class="gallery-grid">
|
||||
<?php foreach ($gallery as $imagePath): ?>
|
||||
<div class="gallery-item">
|
||||
<img src="<?= e($imagePath) ?>" alt="Galéria - <?= e($project['wizard_data']['identity']['business_name']) ?>" loading="lazy">
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
18
src/Templates/sections/hero.php
Normal file
18
src/Templates/sections/hero.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $project
|
||||
*/
|
||||
$hero = $project['content']['generated']['hero'] ?? [];
|
||||
?>
|
||||
<section id="hero" class="hero">
|
||||
<div class="container">
|
||||
<div class="hero-content">
|
||||
<h1><?= e($hero['title'] ?? $project['wizard_data']['identity']['business_name']) ?></h1>
|
||||
<p class="subtitle"><?= e($hero['subtitle'] ?? $project['wizard_data']['identity']['tagline']) ?></p>
|
||||
<div class="hero-actions">
|
||||
<a href="#contact" class="btn btn-primary">Kontaktujte nás</a>
|
||||
<a href="#services" class="btn btn-secondary">Naše služby</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
13
src/Templates/sections/pricing.php
Normal file
13
src/Templates/sections/pricing.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $project
|
||||
*/
|
||||
?>
|
||||
<section id="pricing" class="pricing">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2>Cenník</h2>
|
||||
</div>
|
||||
<p>Informácie o cenách našich služieb nájdete v sekcii Služby alebo nás kontaktujte pre individuálnu ponuku.</p>
|
||||
</div>
|
||||
</section>
|
||||
28
src/Templates/sections/services.php
Normal file
28
src/Templates/sections/services.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $project
|
||||
*/
|
||||
$services = $project['content']['generated']['services'] ?? [];
|
||||
$pricingNote = $project['wizard_data']['services']['pricing_note'] ?? '';
|
||||
?>
|
||||
<section id="services" class="services">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2>Naše služby</h2>
|
||||
</div>
|
||||
<div class="services-grid">
|
||||
<?php foreach ($services as $service): ?>
|
||||
<article class="service-card">
|
||||
<h3><?= e($service['title']) ?></h3>
|
||||
<p><?= e($service['text']) ?></p>
|
||||
<?php if (!empty($service['price_info'])): ?>
|
||||
<div class="price"><?= e($service['price_info']) ?></div>
|
||||
<?php endif; ?>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ($pricingNote): ?>
|
||||
<p class="pricing-note"><em><?= e($pricingNote) ?></em></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
15
src/Utils/Helpers.php
Normal file
15
src/Utils/Helpers.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Global helper functions for templates.
|
||||
*/
|
||||
|
||||
if (!function_exists('e')) {
|
||||
/**
|
||||
* Securely escapes a value for HTML output.
|
||||
*/
|
||||
function e($value): string
|
||||
{
|
||||
return htmlspecialchars((string)($value ?? ''), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user