feat(hosting): add industry template infrastructure (Workstream 3B)

5 industry templates as JSON presets, each with theme + multi-page content:
- generic: clean minimal (homepage, about, contact)
- restaurant: warm tones, Playfair Display (homepage, about, menu, contact)
- construction: amber/earth tones, Montserrat (homepage, services, projects, contact)
- auto-parts: red/bold, parts-focused (homepage, catalog, contact)
- professional-services: navy/blue, Merriweather (homepage, services, team, contact)

Each template has:
- meta.json (name, description, tags, languages)
- theme.json (colors, fonts, layout, header style)
- pages/*.json (section-based homepage + content pages with i18n)
- {{placeholder}} variables for prospect data injection

TemplateService loads from templates_library/ directory with caching.
GET /admin/hosting/sites/templates endpoint to list available templates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-01 22:41:33 +02:00
parent 1828ac85eb
commit 2e043260eb
32 changed files with 604 additions and 0 deletions

View File

@@ -22,13 +22,26 @@ from app.modules.hosting.schemas.hosted_site import (
HostedSiteUpdate,
SendProposalRequest,
)
from app.modules.hosting.schemas.template import TemplateListResponse, TemplateResponse
from app.modules.hosting.services.hosted_site_service import hosted_site_service
from app.modules.hosting.services.template_service import template_service
from app.modules.tenancy.schemas.auth import UserContext
router = APIRouter(prefix="/sites")
logger = logging.getLogger(__name__)
@router.get("/templates", response_model=TemplateListResponse)
def list_templates(
current_admin: UserContext = Depends(get_current_admin_api),
):
"""List available industry templates for POC site generation."""
templates = template_service.list_templates()
return TemplateListResponse(
templates=[TemplateResponse(**t) for t in templates],
)
def _to_response(site) -> HostedSiteResponse:
"""Convert a hosted site model to response schema."""
return HostedSiteResponse(

View File

@@ -0,0 +1,21 @@
# app/modules/hosting/schemas/template.py
"""Pydantic schemas for template responses."""
from pydantic import BaseModel
class TemplateResponse(BaseModel):
"""Schema for a single template."""
id: str
name: str
description: str
tags: list[str] = []
languages: list[str] = []
pages: list[str] = []
class TemplateListResponse(BaseModel):
"""Schema for template list response."""
templates: list[TemplateResponse]

View File

@@ -0,0 +1,114 @@
# app/modules/hosting/services/template_service.py
"""
Template service for the hosting module.
Loads and manages industry templates from the templates_library directory.
Templates are JSON files that define page content, themes, and sections
for different business types (restaurant, construction, etc.).
"""
import json
import logging
from pathlib import Path
logger = logging.getLogger(__name__)
TEMPLATES_DIR = Path(__file__).parent.parent / "templates_library"
class TemplateService:
"""Manages industry templates for POC site generation."""
def __init__(self):
self._manifest = None
self._cache: dict[str, dict] = {}
def _load_manifest(self) -> dict:
"""Load the manifest.json file."""
if self._manifest is None:
manifest_path = TEMPLATES_DIR / "manifest.json"
self._manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
return self._manifest
def list_templates(self) -> list[dict]:
"""List all available templates with metadata."""
manifest = self._load_manifest()
templates = []
for entry in manifest.get("templates", []):
template_id = entry["id"]
meta = self._load_meta(template_id)
templates.append({
"id": template_id,
"name": meta.get("name", entry.get("name", template_id)),
"description": meta.get("description", entry.get("description", "")),
"tags": meta.get("tags", entry.get("tags", [])),
"languages": meta.get("languages", []),
"pages": entry.get("pages", []),
})
return templates
def get_template(self, template_id: str) -> dict | None:
"""Load a complete template with meta, theme, and all pages."""
if template_id in self._cache:
return self._cache[template_id]
template_dir = TEMPLATES_DIR / template_id
if not template_dir.is_dir():
return None
meta = self._load_meta(template_id)
theme = self._load_json(template_dir / "theme.json")
pages = self._load_pages(template_dir)
template = {
"id": template_id,
"meta": meta,
"theme": theme,
"pages": pages,
}
self._cache[template_id] = template
return template
def get_theme(self, template_id: str) -> dict | None:
"""Load just the theme configuration for a template."""
template_dir = TEMPLATES_DIR / template_id
return self._load_json(template_dir / "theme.json")
def get_page(self, template_id: str, page_slug: str) -> dict | None:
"""Load a single page definition from a template."""
page_path = TEMPLATES_DIR / template_id / "pages" / f"{page_slug}.json"
return self._load_json(page_path)
def template_exists(self, template_id: str) -> bool:
"""Check if a template exists."""
return (TEMPLATES_DIR / template_id / "meta.json").is_file()
def _load_meta(self, template_id: str) -> dict:
"""Load meta.json for a template."""
return self._load_json(TEMPLATES_DIR / template_id / "meta.json") or {}
def _load_pages(self, template_dir: Path) -> list[dict]:
"""Load all page JSONs from a template's pages/ directory."""
pages_dir = template_dir / "pages"
if not pages_dir.is_dir():
return []
pages = []
for page_file in sorted(pages_dir.glob("*.json")):
page_data = self._load_json(page_file)
if page_data:
pages.append(page_data)
return pages
@staticmethod
def _load_json(path: Path) -> dict | None:
"""Safely load a JSON file."""
if not path.is_file():
return None
try:
return json.loads(path.read_text(encoding="utf-8"))
except (json.JSONDecodeError, OSError) as e:
logger.warning("Failed to load template file %s: %s", path, e)
return None
template_service = TemplateService()

View File

@@ -0,0 +1 @@
{"id": "auto-parts", "name": "Auto Parts & Garage", "description": "Template for auto parts shops, garages, and car dealers", "tags": ["automotive", "garage", "car", "parts"], "languages": ["en", "fr", "de"]}

View File

@@ -0,0 +1,12 @@
{
"slug": "catalog",
"title": "Catalog",
"title_translations": {"en": "Parts Catalog", "fr": "Catalogue de pièces", "de": "Teilekatalog"},
"template": "default",
"is_published": true,
"show_in_header": true,
"content_translations": {
"en": "<h2>Parts Catalog</h2>\n<p>Browse our extensive catalog of auto parts for all major brands.</p>",
"fr": "<h2>Catalogue de pièces</h2>\n<p>Parcourez notre catalogue complet de pièces auto pour toutes les grandes marques.</p>"
}
}

View File

@@ -0,0 +1,13 @@
{
"slug": "contact",
"title": "Contact",
"title_translations": {"en": "Contact Us", "fr": "Contactez-nous", "de": "Kontakt"},
"template": "default",
"is_published": true,
"show_in_header": true,
"show_in_footer": true,
"content_translations": {
"en": "<h2>Contact Us</h2>\n<p>Visit our store or get in touch for parts inquiries.</p>\n<ul>\n<li>Phone: {{phone}}</li>\n<li>Email: {{email}}</li>\n<li>Address: {{address}}</li>\n</ul>",
"fr": "<h2>Contactez-nous</h2>\n<p>Visitez notre magasin ou contactez-nous pour vos demandes de pièces.</p>\n<ul>\n<li>Téléphone : {{phone}}</li>\n<li>Email : {{email}}</li>\n<li>Adresse : {{address}}</li>\n</ul>"
}
}

View File

@@ -0,0 +1,34 @@
{
"slug": "homepage",
"title": "{{business_name}}",
"template": "full",
"is_published": true,
"sections": {
"hero": {
"enabled": true,
"title": {"translations": {"en": "{{business_name}}", "fr": "{{business_name}}"}},
"subtitle": {"translations": {"en": "Your trusted auto parts specialist in {{city}}", "fr": "Votre spécialiste pièces auto de confiance à {{city}}"}},
"background_type": "image",
"buttons": [
{"label": {"translations": {"en": "Browse Parts", "fr": "Voir les pièces"}}, "url": "/catalog", "style": "primary"},
{"label": {"translations": {"en": "Contact Us", "fr": "Contactez-nous"}}, "url": "/contact", "style": "secondary"}
]
},
"features": {
"enabled": true,
"title": {"translations": {"en": "Why Choose Us", "fr": "Pourquoi nous choisir"}},
"items": [
{"icon": "truck", "title": {"translations": {"en": "Fast Delivery", "fr": "Livraison rapide"}}, "description": {"translations": {"en": "Same-day delivery on in-stock parts", "fr": "Livraison le jour même pour les pièces en stock"}}},
{"icon": "shield-check", "title": {"translations": {"en": "Quality Guaranteed", "fr": "Qualité garantie"}}, "description": {"translations": {"en": "OEM and certified aftermarket parts", "fr": "Pièces OEM et aftermarket certifiées"}}},
{"icon": "currency-euro", "title": {"translations": {"en": "Best Prices", "fr": "Meilleurs prix"}}, "description": {"translations": {"en": "Competitive pricing on all brands", "fr": "Prix compétitifs sur toutes les marques"}}}
]
},
"cta": {
"enabled": true,
"title": {"translations": {"en": "Need a specific part?", "fr": "Besoin d'une pièce spécifique ?"}},
"buttons": [
{"label": {"translations": {"en": "Contact Us", "fr": "Contactez-nous"}}, "url": "/contact", "style": "primary"}
]
}
}
}

View File

@@ -0,0 +1,8 @@
{
"theme_name": "modern",
"colors": {"primary": "#dc2626", "secondary": "#991b1b", "accent": "#f59e0b", "background": "#fafafa", "text": "#18181b", "border": "#e4e4e7"},
"font_family_heading": "Montserrat",
"font_family_body": "Inter",
"layout_style": "grid",
"header_style": "fixed"
}

View File

@@ -0,0 +1 @@
{"id": "construction", "name": "Construction & Renovation", "description": "Professional template for builders, renovators, and tradespeople", "tags": ["construction", "renovation", "building", "trades"], "languages": ["en", "fr", "de"]}

View File

@@ -0,0 +1,13 @@
{
"slug": "contact",
"title": "Contact",
"title_translations": {"en": "Contact Us", "fr": "Contactez-nous", "de": "Kontakt"},
"template": "default",
"is_published": true,
"show_in_header": true,
"show_in_footer": true,
"content_translations": {
"en": "<h2>Get a Free Quote</h2>\n<p>Tell us about your project and we'll get back to you within 24 hours.</p>\n<ul>\n<li>Phone: {{phone}}</li>\n<li>Email: {{email}}</li>\n<li>Address: {{address}}</li>\n</ul>",
"fr": "<h2>Demandez un devis gratuit</h2>\n<p>Décrivez-nous votre projet et nous vous recontacterons sous 24h.</p>\n<ul>\n<li>Téléphone : {{phone}}</li>\n<li>Email : {{email}}</li>\n<li>Adresse : {{address}}</li>\n</ul>"
}
}

View File

@@ -0,0 +1,40 @@
{
"slug": "homepage",
"title": "{{business_name}}",
"template": "full",
"is_published": true,
"sections": {
"hero": {
"enabled": true,
"title": {"translations": {"en": "{{business_name}}", "fr": "{{business_name}}"}},
"subtitle": {"translations": {"en": "Quality construction and renovation in {{city}}", "fr": "Construction et rénovation de qualité à {{city}}"}},
"background_type": "image",
"buttons": [
{"label": {"translations": {"en": "Get a Free Quote", "fr": "Devis gratuit"}}, "url": "/contact", "style": "primary"},
{"label": {"translations": {"en": "Our Projects", "fr": "Nos réalisations"}}, "url": "/projects", "style": "secondary"}
]
},
"features": {
"enabled": true,
"title": {"translations": {"en": "Our Services", "fr": "Nos Services"}},
"items": [
{"icon": "home", "title": {"translations": {"en": "New Construction", "fr": "Construction neuve"}}, "description": {"translations": {"en": "Custom-built homes and commercial buildings", "fr": "Maisons et bâtiments commerciaux sur mesure"}}},
{"icon": "wrench", "title": {"translations": {"en": "Renovation", "fr": "Rénovation"}}, "description": {"translations": {"en": "Complete interior and exterior renovation", "fr": "Rénovation complète intérieure et extérieure"}}},
{"icon": "color-swatch", "title": {"translations": {"en": "Painting & Finishing", "fr": "Peinture & Finitions"}}, "description": {"translations": {"en": "Professional painting and finishing work", "fr": "Travaux de peinture et finitions professionnels"}}},
{"icon": "shield-check", "title": {"translations": {"en": "Insulation", "fr": "Isolation"}}, "description": {"translations": {"en": "Energy-efficient insulation solutions", "fr": "Solutions d'isolation éco-énergétiques"}}}
]
},
"testimonials": {
"enabled": true,
"title": {"translations": {"en": "What Our Clients Say", "fr": "Témoignages de nos clients"}},
"items": []
},
"cta": {
"enabled": true,
"title": {"translations": {"en": "Ready to start your project?", "fr": "Prêt à démarrer votre projet ?"}},
"buttons": [
{"label": {"translations": {"en": "Request a Quote", "fr": "Demander un devis"}}, "url": "/contact", "style": "primary"}
]
}
}
}

View File

@@ -0,0 +1,12 @@
{
"slug": "projects",
"title": "Projects",
"title_translations": {"en": "Our Projects", "fr": "Nos Réalisations", "de": "Unsere Projekte"},
"template": "default",
"is_published": true,
"show_in_header": true,
"content_translations": {
"en": "<h2>Our Projects</h2>\n<p>Browse our portfolio of completed construction and renovation projects.</p>",
"fr": "<h2>Nos Réalisations</h2>\n<p>Découvrez notre portfolio de projets de construction et rénovation réalisés.</p>"
}
}

View File

@@ -0,0 +1,12 @@
{
"slug": "services",
"title": "Services",
"title_translations": {"en": "Our Services", "fr": "Nos Services", "de": "Unsere Leistungen"},
"template": "default",
"is_published": true,
"show_in_header": true,
"content_translations": {
"en": "<h2>Our Services</h2>\n<p>We offer a comprehensive range of construction and renovation services.</p>\n<h3>Construction</h3>\n<p>From foundations to finishing touches, we handle every aspect of new builds.</p>\n<h3>Renovation</h3>\n<p>Transform your existing space with our expert renovation team.</p>\n<h3>Painting & Decoration</h3>\n<p>Professional interior and exterior painting services.</p>",
"fr": "<h2>Nos Services</h2>\n<p>Nous proposons une gamme complète de services de construction et rénovation.</p>\n<h3>Construction</h3>\n<p>Des fondations aux finitions, nous gérons chaque aspect des constructions neuves.</p>\n<h3>Rénovation</h3>\n<p>Transformez votre espace avec notre équipe de rénovation experte.</p>\n<h3>Peinture & Décoration</h3>\n<p>Services professionnels de peinture intérieure et extérieure.</p>"
}
}

View File

@@ -0,0 +1,15 @@
{
"theme_name": "modern",
"colors": {
"primary": "#d97706",
"secondary": "#92400e",
"accent": "#fbbf24",
"background": "#fafaf9",
"text": "#1c1917",
"border": "#d6d3d1"
},
"font_family_heading": "Montserrat",
"font_family_body": "Open Sans",
"layout_style": "grid",
"header_style": "fixed"
}

View File

@@ -0,0 +1,7 @@
{
"id": "generic",
"name": "Generic Business",
"description": "Clean, minimal template that works for any business type",
"tags": ["general", "minimal", "any"],
"languages": ["en", "fr", "de"]
}

View File

@@ -0,0 +1,13 @@
{
"slug": "about",
"title": "About Us",
"title_translations": {"en": "About Us", "fr": "À propos", "de": "Über uns"},
"template": "default",
"is_published": true,
"show_in_header": true,
"content": "{{about_content}}",
"content_translations": {
"en": "<h2>About {{business_name}}</h2>\n<p>{{about_paragraph}}</p>",
"fr": "<h2>À propos de {{business_name}}</h2>\n<p>{{about_paragraph}}</p>"
}
}

View File

@@ -0,0 +1,13 @@
{
"slug": "contact",
"title": "Contact",
"title_translations": {"en": "Contact Us", "fr": "Contact", "de": "Kontakt"},
"template": "default",
"is_published": true,
"show_in_header": true,
"show_in_footer": true,
"content_translations": {
"en": "<h2>Get in Touch</h2>\n<p>We'd love to hear from you. Reach out using the information below.</p>\n<ul>\n<li>Email: {{email}}</li>\n<li>Phone: {{phone}}</li>\n<li>Address: {{address}}</li>\n</ul>",
"fr": "<h2>Contactez-nous</h2>\n<p>N'hésitez pas à nous contacter.</p>\n<ul>\n<li>Email : {{email}}</li>\n<li>Téléphone : {{phone}}</li>\n<li>Adresse : {{address}}</li>\n</ul>"
}
}

View File

@@ -0,0 +1,35 @@
{
"slug": "homepage",
"title": "{{business_name}}",
"template": "full",
"is_published": true,
"show_in_header": false,
"sections": {
"hero": {
"enabled": true,
"title": {"translations": {"en": "{{business_name}}", "fr": "{{business_name}}"}},
"subtitle": {"translations": {"en": "{{meta_description}}", "fr": "{{meta_description}}"}},
"background_type": "gradient",
"buttons": [
{"label": {"translations": {"en": "Contact Us", "fr": "Contactez-nous"}}, "url": "/contact", "style": "primary"}
]
},
"features": {
"enabled": true,
"title": {"translations": {"en": "What We Offer", "fr": "Nos Services"}},
"items": [
{"icon": "shield-check", "title": {"translations": {"en": "Quality", "fr": "Qualité"}}, "description": {"translations": {"en": "Committed to excellence in everything we do", "fr": "Engagés pour l'excellence dans tout ce que nous faisons"}}},
{"icon": "clock", "title": {"translations": {"en": "Reliability", "fr": "Fiabilité"}}, "description": {"translations": {"en": "Dependable service you can count on", "fr": "Un service fiable sur lequel vous pouvez compter"}}},
{"icon": "users", "title": {"translations": {"en": "Experience", "fr": "Expérience"}}, "description": {"translations": {"en": "Years of expertise at your service", "fr": "Des années d'expertise à votre service"}}}
]
},
"cta": {
"enabled": true,
"title": {"translations": {"en": "Ready to get started?", "fr": "Prêt à commencer ?"}},
"subtitle": {"translations": {"en": "Contact us today for a free consultation", "fr": "Contactez-nous pour une consultation gratuite"}},
"buttons": [
{"label": {"translations": {"en": "Get in Touch", "fr": "Nous Contacter"}}, "url": "/contact", "style": "primary"}
]
}
}
}

View File

@@ -0,0 +1,15 @@
{
"theme_name": "modern",
"colors": {
"primary": "#3b82f6",
"secondary": "#1e40af",
"accent": "#f59e0b",
"background": "#ffffff",
"text": "#1e293b",
"border": "#e2e8f0"
},
"font_family_heading": "Inter",
"font_family_body": "Inter",
"layout_style": "grid",
"header_style": "fixed"
}

View File

@@ -0,0 +1,40 @@
{
"version": "1.0",
"templates": [
{
"id": "generic",
"name": "Generic Business",
"description": "Clean, minimal template that works for any business type",
"tags": ["general", "minimal", "any"],
"pages": ["homepage", "about", "contact"]
},
{
"id": "restaurant",
"name": "Restaurant & Dining",
"description": "Elegant template for restaurants, cafés, bars, and catering",
"tags": ["food", "dining", "hospitality", "café"],
"pages": ["homepage", "about", "menu", "contact"]
},
{
"id": "construction",
"name": "Construction & Renovation",
"description": "Professional template for builders, renovators, and tradespeople",
"tags": ["construction", "renovation", "building", "trades"],
"pages": ["homepage", "services", "projects", "contact"]
},
{
"id": "auto-parts",
"name": "Auto Parts & Garage",
"description": "Template for auto parts shops, garages, and car dealers",
"tags": ["automotive", "garage", "car", "parts"],
"pages": ["homepage", "catalog", "contact"]
},
{
"id": "professional-services",
"name": "Professional Services",
"description": "Template for lawyers, accountants, consultants, and agencies",
"tags": ["professional", "consulting", "legal", "finance"],
"pages": ["homepage", "services", "team", "contact"]
}
]
}

View File

@@ -0,0 +1 @@
{"id": "professional-services", "name": "Professional Services", "description": "Template for lawyers, accountants, consultants, and agencies", "tags": ["professional", "consulting", "legal", "finance"], "languages": ["en", "fr", "de"]}

View File

@@ -0,0 +1,13 @@
{
"slug": "contact",
"title": "Contact",
"title_translations": {"en": "Contact Us", "fr": "Contactez-nous", "de": "Kontakt"},
"template": "default",
"is_published": true,
"show_in_header": true,
"show_in_footer": true,
"content_translations": {
"en": "<h2>Contact Us</h2>\n<p>Schedule a consultation or reach out with any questions.</p>\n<ul>\n<li>Phone: {{phone}}</li>\n<li>Email: {{email}}</li>\n<li>Address: {{address}}</li>\n</ul>",
"fr": "<h2>Contactez-nous</h2>\n<p>Planifiez une consultation ou posez-nous vos questions.</p>\n<ul>\n<li>Téléphone : {{phone}}</li>\n<li>Email : {{email}}</li>\n<li>Adresse : {{address}}</li>\n</ul>"
}
}

View File

@@ -0,0 +1,34 @@
{
"slug": "homepage",
"title": "{{business_name}}",
"template": "full",
"is_published": true,
"sections": {
"hero": {
"enabled": true,
"title": {"translations": {"en": "{{business_name}}", "fr": "{{business_name}}"}},
"subtitle": {"translations": {"en": "Professional expertise you can trust", "fr": "Une expertise professionnelle de confiance"}},
"background_type": "gradient",
"buttons": [
{"label": {"translations": {"en": "Book a Consultation", "fr": "Prendre rendez-vous"}}, "url": "/contact", "style": "primary"},
{"label": {"translations": {"en": "Our Expertise", "fr": "Notre expertise"}}, "url": "/services", "style": "secondary"}
]
},
"features": {
"enabled": true,
"title": {"translations": {"en": "Areas of Expertise", "fr": "Domaines d'expertise"}},
"items": [
{"icon": "briefcase", "title": {"translations": {"en": "Advisory", "fr": "Conseil"}}, "description": {"translations": {"en": "Strategic guidance tailored to your needs", "fr": "Conseils stratégiques adaptés à vos besoins"}}},
{"icon": "document-text", "title": {"translations": {"en": "Compliance", "fr": "Conformité"}}, "description": {"translations": {"en": "Ensure regulatory compliance across your operations", "fr": "Assurez la conformité réglementaire de vos opérations"}}},
{"icon": "chart-bar", "title": {"translations": {"en": "Analysis", "fr": "Analyse"}}, "description": {"translations": {"en": "Data-driven insights for informed decisions", "fr": "Analyses basées sur les données pour des décisions éclairées"}}}
]
},
"cta": {
"enabled": true,
"title": {"translations": {"en": "Need professional guidance?", "fr": "Besoin d'un accompagnement professionnel ?"}},
"buttons": [
{"label": {"translations": {"en": "Schedule a Meeting", "fr": "Planifier un rendez-vous"}}, "url": "/contact", "style": "primary"}
]
}
}
}

View File

@@ -0,0 +1,12 @@
{
"slug": "services",
"title": "Services",
"title_translations": {"en": "Our Services", "fr": "Nos Services", "de": "Unsere Leistungen"},
"template": "default",
"is_published": true,
"show_in_header": true,
"content_translations": {
"en": "<h2>Our Services</h2>\n<p>We provide comprehensive professional services to help your business thrive.</p>",
"fr": "<h2>Nos Services</h2>\n<p>Nous proposons des services professionnels complets pour aider votre entreprise à prospérer.</p>"
}
}

View File

@@ -0,0 +1,12 @@
{
"slug": "team",
"title": "Team",
"title_translations": {"en": "Our Team", "fr": "Notre Équipe", "de": "Unser Team"},
"template": "default",
"is_published": true,
"show_in_header": true,
"content_translations": {
"en": "<h2>Our Team</h2>\n<p>Meet the professionals behind {{business_name}}.</p>",
"fr": "<h2>Notre Équipe</h2>\n<p>Découvrez les professionnels derrière {{business_name}}.</p>"
}
}

View File

@@ -0,0 +1,8 @@
{
"theme_name": "modern",
"colors": {"primary": "#1e40af", "secondary": "#1e3a8a", "accent": "#3b82f6", "background": "#f8fafc", "text": "#0f172a", "border": "#cbd5e1"},
"font_family_heading": "Merriweather",
"font_family_body": "Source Sans Pro",
"layout_style": "grid",
"header_style": "fixed"
}

View File

@@ -0,0 +1 @@
{"id": "restaurant", "name": "Restaurant & Dining", "description": "Elegant template for restaurants, cafés, bars, and catering", "tags": ["food", "dining", "hospitality"], "languages": ["en", "fr", "de"]}

View File

@@ -0,0 +1,12 @@
{
"slug": "about",
"title": "About",
"title_translations": {"en": "Our Story", "fr": "Notre Histoire", "de": "Über uns"},
"template": "default",
"is_published": true,
"show_in_header": true,
"content_translations": {
"en": "<h2>Our Story</h2>\n<p>{{about_paragraph}}</p>",
"fr": "<h2>Notre Histoire</h2>\n<p>{{about_paragraph}}</p>"
}
}

View File

@@ -0,0 +1,13 @@
{
"slug": "contact",
"title": "Contact",
"title_translations": {"en": "Visit Us", "fr": "Nous Rendre Visite", "de": "Besuchen Sie uns"},
"template": "default",
"is_published": true,
"show_in_header": true,
"show_in_footer": true,
"content_translations": {
"en": "<h2>Visit Us</h2>\n<p>We look forward to welcoming you.</p>\n<ul>\n<li>Address: {{address}}</li>\n<li>Phone: {{phone}}</li>\n<li>Email: {{email}}</li>\n</ul>",
"fr": "<h2>Nous Rendre Visite</h2>\n<p>Nous avons hâte de vous accueillir.</p>\n<ul>\n<li>Adresse : {{address}}</li>\n<li>Téléphone : {{phone}}</li>\n<li>Email : {{email}}</li>\n</ul>"
}
}

View File

@@ -0,0 +1,39 @@
{
"slug": "homepage",
"title": "{{business_name}}",
"template": "full",
"is_published": true,
"sections": {
"hero": {
"enabled": true,
"title": {"translations": {"en": "{{business_name}}", "fr": "{{business_name}}"}},
"subtitle": {"translations": {"en": "A culinary experience in {{city}}", "fr": "Une expérience culinaire à {{city}}"}},
"background_type": "image",
"buttons": [
{"label": {"translations": {"en": "Reserve a Table", "fr": "Réserver une table"}}, "url": "/contact", "style": "primary"},
{"label": {"translations": {"en": "See Our Menu", "fr": "Voir la carte"}}, "url": "/menu", "style": "secondary"}
]
},
"features": {
"enabled": true,
"title": {"translations": {"en": "Our Specialties", "fr": "Nos Spécialités"}},
"items": [
{"icon": "fire", "title": {"translations": {"en": "Fresh Ingredients", "fr": "Produits frais"}}, "description": {"translations": {"en": "Locally sourced, seasonal ingredients", "fr": "Produits locaux et de saison"}}},
{"icon": "star", "title": {"translations": {"en": "Chef's Selection", "fr": "Sélection du chef"}}, "description": {"translations": {"en": "Carefully crafted dishes by our expert chef", "fr": "Plats élaborés par notre chef expert"}}},
{"icon": "heart", "title": {"translations": {"en": "Warm Atmosphere", "fr": "Ambiance chaleureuse"}}, "description": {"translations": {"en": "A welcoming space for every occasion", "fr": "Un espace accueillant pour chaque occasion"}}}
]
},
"testimonials": {
"enabled": true,
"title": {"translations": {"en": "What Our Guests Say", "fr": "Ce que disent nos clients"}},
"items": []
},
"cta": {
"enabled": true,
"title": {"translations": {"en": "Ready to dine with us?", "fr": "Prêt à nous rendre visite ?"}},
"buttons": [
{"label": {"translations": {"en": "Make a Reservation", "fr": "Réserver"}}, "url": "/contact", "style": "primary"}
]
}
}
}

View File

@@ -0,0 +1,12 @@
{
"slug": "menu",
"title": "Menu",
"title_translations": {"en": "Our Menu", "fr": "Notre Carte", "de": "Speisekarte"},
"template": "default",
"is_published": true,
"show_in_header": true,
"content_translations": {
"en": "<h2>Our Menu</h2>\n<p>Discover our selection of dishes, prepared with fresh, local ingredients.</p>",
"fr": "<h2>Notre Carte</h2>\n<p>Découvrez notre sélection de plats, préparés avec des produits frais et locaux.</p>"
}
}

View File

@@ -0,0 +1,15 @@
{
"theme_name": "modern",
"colors": {
"primary": "#b45309",
"secondary": "#78350f",
"accent": "#f59e0b",
"background": "#fffbeb",
"text": "#1c1917",
"border": "#e7e5e4"
},
"font_family_heading": "Playfair Display",
"font_family_body": "Inter",
"layout_style": "grid",
"header_style": "transparent"
}