diff --git a/app/modules/hosting/routes/api/admin_sites.py b/app/modules/hosting/routes/api/admin_sites.py index d5d1e2ce..065d0c99 100644 --- a/app/modules/hosting/routes/api/admin_sites.py +++ b/app/modules/hosting/routes/api/admin_sites.py @@ -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( diff --git a/app/modules/hosting/schemas/template.py b/app/modules/hosting/schemas/template.py new file mode 100644 index 00000000..0486efdb --- /dev/null +++ b/app/modules/hosting/schemas/template.py @@ -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] diff --git a/app/modules/hosting/services/template_service.py b/app/modules/hosting/services/template_service.py new file mode 100644 index 00000000..965225fa --- /dev/null +++ b/app/modules/hosting/services/template_service.py @@ -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() diff --git a/app/modules/hosting/templates_library/auto-parts/meta.json b/app/modules/hosting/templates_library/auto-parts/meta.json new file mode 100644 index 00000000..dc53a6a8 --- /dev/null +++ b/app/modules/hosting/templates_library/auto-parts/meta.json @@ -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"]} diff --git a/app/modules/hosting/templates_library/auto-parts/pages/catalog.json b/app/modules/hosting/templates_library/auto-parts/pages/catalog.json new file mode 100644 index 00000000..2cd72c1c --- /dev/null +++ b/app/modules/hosting/templates_library/auto-parts/pages/catalog.json @@ -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": "

Parts Catalog

\n

Browse our extensive catalog of auto parts for all major brands.

", + "fr": "

Catalogue de pièces

\n

Parcourez notre catalogue complet de pièces auto pour toutes les grandes marques.

" + } +} diff --git a/app/modules/hosting/templates_library/auto-parts/pages/contact.json b/app/modules/hosting/templates_library/auto-parts/pages/contact.json new file mode 100644 index 00000000..47a5ce43 --- /dev/null +++ b/app/modules/hosting/templates_library/auto-parts/pages/contact.json @@ -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": "

Contact Us

\n

Visit our store or get in touch for parts inquiries.

\n", + "fr": "

Contactez-nous

\n

Visitez notre magasin ou contactez-nous pour vos demandes de pièces.

\n" + } +} diff --git a/app/modules/hosting/templates_library/auto-parts/pages/homepage.json b/app/modules/hosting/templates_library/auto-parts/pages/homepage.json new file mode 100644 index 00000000..03e3847d --- /dev/null +++ b/app/modules/hosting/templates_library/auto-parts/pages/homepage.json @@ -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"} + ] + } + } +} diff --git a/app/modules/hosting/templates_library/auto-parts/theme.json b/app/modules/hosting/templates_library/auto-parts/theme.json new file mode 100644 index 00000000..9984832d --- /dev/null +++ b/app/modules/hosting/templates_library/auto-parts/theme.json @@ -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" +} diff --git a/app/modules/hosting/templates_library/construction/meta.json b/app/modules/hosting/templates_library/construction/meta.json new file mode 100644 index 00000000..2947960e --- /dev/null +++ b/app/modules/hosting/templates_library/construction/meta.json @@ -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"]} diff --git a/app/modules/hosting/templates_library/construction/pages/contact.json b/app/modules/hosting/templates_library/construction/pages/contact.json new file mode 100644 index 00000000..184e4791 --- /dev/null +++ b/app/modules/hosting/templates_library/construction/pages/contact.json @@ -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": "

Get a Free Quote

\n

Tell us about your project and we'll get back to you within 24 hours.

\n", + "fr": "

Demandez un devis gratuit

\n

Décrivez-nous votre projet et nous vous recontacterons sous 24h.

\n" + } +} diff --git a/app/modules/hosting/templates_library/construction/pages/homepage.json b/app/modules/hosting/templates_library/construction/pages/homepage.json new file mode 100644 index 00000000..9df687d0 --- /dev/null +++ b/app/modules/hosting/templates_library/construction/pages/homepage.json @@ -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"} + ] + } + } +} diff --git a/app/modules/hosting/templates_library/construction/pages/projects.json b/app/modules/hosting/templates_library/construction/pages/projects.json new file mode 100644 index 00000000..a9066e32 --- /dev/null +++ b/app/modules/hosting/templates_library/construction/pages/projects.json @@ -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": "

Our Projects

\n

Browse our portfolio of completed construction and renovation projects.

", + "fr": "

Nos Réalisations

\n

Découvrez notre portfolio de projets de construction et rénovation réalisés.

" + } +} diff --git a/app/modules/hosting/templates_library/construction/pages/services.json b/app/modules/hosting/templates_library/construction/pages/services.json new file mode 100644 index 00000000..5039a83e --- /dev/null +++ b/app/modules/hosting/templates_library/construction/pages/services.json @@ -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": "

Our Services

\n

We offer a comprehensive range of construction and renovation services.

\n

Construction

\n

From foundations to finishing touches, we handle every aspect of new builds.

\n

Renovation

\n

Transform your existing space with our expert renovation team.

\n

Painting & Decoration

\n

Professional interior and exterior painting services.

", + "fr": "

Nos Services

\n

Nous proposons une gamme complète de services de construction et rénovation.

\n

Construction

\n

Des fondations aux finitions, nous gérons chaque aspect des constructions neuves.

\n

Rénovation

\n

Transformez votre espace avec notre équipe de rénovation experte.

\n

Peinture & Décoration

\n

Services professionnels de peinture intérieure et extérieure.

" + } +} diff --git a/app/modules/hosting/templates_library/construction/theme.json b/app/modules/hosting/templates_library/construction/theme.json new file mode 100644 index 00000000..c61f9ae7 --- /dev/null +++ b/app/modules/hosting/templates_library/construction/theme.json @@ -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" +} diff --git a/app/modules/hosting/templates_library/generic/meta.json b/app/modules/hosting/templates_library/generic/meta.json new file mode 100644 index 00000000..b6612d3d --- /dev/null +++ b/app/modules/hosting/templates_library/generic/meta.json @@ -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"] +} diff --git a/app/modules/hosting/templates_library/generic/pages/about.json b/app/modules/hosting/templates_library/generic/pages/about.json new file mode 100644 index 00000000..3b5c4035 --- /dev/null +++ b/app/modules/hosting/templates_library/generic/pages/about.json @@ -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": "

About {{business_name}}

\n

{{about_paragraph}}

", + "fr": "

À propos de {{business_name}}

\n

{{about_paragraph}}

" + } +} diff --git a/app/modules/hosting/templates_library/generic/pages/contact.json b/app/modules/hosting/templates_library/generic/pages/contact.json new file mode 100644 index 00000000..43eb9d31 --- /dev/null +++ b/app/modules/hosting/templates_library/generic/pages/contact.json @@ -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": "

Get in Touch

\n

We'd love to hear from you. Reach out using the information below.

\n", + "fr": "

Contactez-nous

\n

N'hésitez pas à nous contacter.

\n" + } +} diff --git a/app/modules/hosting/templates_library/generic/pages/homepage.json b/app/modules/hosting/templates_library/generic/pages/homepage.json new file mode 100644 index 00000000..eefebdb7 --- /dev/null +++ b/app/modules/hosting/templates_library/generic/pages/homepage.json @@ -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"} + ] + } + } +} diff --git a/app/modules/hosting/templates_library/generic/theme.json b/app/modules/hosting/templates_library/generic/theme.json new file mode 100644 index 00000000..d33d42cd --- /dev/null +++ b/app/modules/hosting/templates_library/generic/theme.json @@ -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" +} diff --git a/app/modules/hosting/templates_library/manifest.json b/app/modules/hosting/templates_library/manifest.json new file mode 100644 index 00000000..ed2e8398 --- /dev/null +++ b/app/modules/hosting/templates_library/manifest.json @@ -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"] + } + ] +} diff --git a/app/modules/hosting/templates_library/professional-services/meta.json b/app/modules/hosting/templates_library/professional-services/meta.json new file mode 100644 index 00000000..1a448be3 --- /dev/null +++ b/app/modules/hosting/templates_library/professional-services/meta.json @@ -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"]} diff --git a/app/modules/hosting/templates_library/professional-services/pages/contact.json b/app/modules/hosting/templates_library/professional-services/pages/contact.json new file mode 100644 index 00000000..34af7b75 --- /dev/null +++ b/app/modules/hosting/templates_library/professional-services/pages/contact.json @@ -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": "

Contact Us

\n

Schedule a consultation or reach out with any questions.

\n", + "fr": "

Contactez-nous

\n

Planifiez une consultation ou posez-nous vos questions.

\n" + } +} diff --git a/app/modules/hosting/templates_library/professional-services/pages/homepage.json b/app/modules/hosting/templates_library/professional-services/pages/homepage.json new file mode 100644 index 00000000..f72cd74b --- /dev/null +++ b/app/modules/hosting/templates_library/professional-services/pages/homepage.json @@ -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"} + ] + } + } +} diff --git a/app/modules/hosting/templates_library/professional-services/pages/services.json b/app/modules/hosting/templates_library/professional-services/pages/services.json new file mode 100644 index 00000000..202c11be --- /dev/null +++ b/app/modules/hosting/templates_library/professional-services/pages/services.json @@ -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": "

Our Services

\n

We provide comprehensive professional services to help your business thrive.

", + "fr": "

Nos Services

\n

Nous proposons des services professionnels complets pour aider votre entreprise à prospérer.

" + } +} diff --git a/app/modules/hosting/templates_library/professional-services/pages/team.json b/app/modules/hosting/templates_library/professional-services/pages/team.json new file mode 100644 index 00000000..8c35e698 --- /dev/null +++ b/app/modules/hosting/templates_library/professional-services/pages/team.json @@ -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": "

Our Team

\n

Meet the professionals behind {{business_name}}.

", + "fr": "

Notre Équipe

\n

Découvrez les professionnels derrière {{business_name}}.

" + } +} diff --git a/app/modules/hosting/templates_library/professional-services/theme.json b/app/modules/hosting/templates_library/professional-services/theme.json new file mode 100644 index 00000000..75388587 --- /dev/null +++ b/app/modules/hosting/templates_library/professional-services/theme.json @@ -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" +} diff --git a/app/modules/hosting/templates_library/restaurant/meta.json b/app/modules/hosting/templates_library/restaurant/meta.json new file mode 100644 index 00000000..69414964 --- /dev/null +++ b/app/modules/hosting/templates_library/restaurant/meta.json @@ -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"]} diff --git a/app/modules/hosting/templates_library/restaurant/pages/about.json b/app/modules/hosting/templates_library/restaurant/pages/about.json new file mode 100644 index 00000000..d25d2908 --- /dev/null +++ b/app/modules/hosting/templates_library/restaurant/pages/about.json @@ -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": "

Our Story

\n

{{about_paragraph}}

", + "fr": "

Notre Histoire

\n

{{about_paragraph}}

" + } +} diff --git a/app/modules/hosting/templates_library/restaurant/pages/contact.json b/app/modules/hosting/templates_library/restaurant/pages/contact.json new file mode 100644 index 00000000..85a7c92d --- /dev/null +++ b/app/modules/hosting/templates_library/restaurant/pages/contact.json @@ -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": "

Visit Us

\n

We look forward to welcoming you.

\n", + "fr": "

Nous Rendre Visite

\n

Nous avons hâte de vous accueillir.

\n" + } +} diff --git a/app/modules/hosting/templates_library/restaurant/pages/homepage.json b/app/modules/hosting/templates_library/restaurant/pages/homepage.json new file mode 100644 index 00000000..b8943e7d --- /dev/null +++ b/app/modules/hosting/templates_library/restaurant/pages/homepage.json @@ -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"} + ] + } + } +} diff --git a/app/modules/hosting/templates_library/restaurant/pages/menu.json b/app/modules/hosting/templates_library/restaurant/pages/menu.json new file mode 100644 index 00000000..11d3b8c8 --- /dev/null +++ b/app/modules/hosting/templates_library/restaurant/pages/menu.json @@ -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": "

Our Menu

\n

Discover our selection of dishes, prepared with fresh, local ingredients.

", + "fr": "

Notre Carte

\n

Découvrez notre sélection de plats, préparés avec des produits frais et locaux.

" + } +} diff --git a/app/modules/hosting/templates_library/restaurant/theme.json b/app/modules/hosting/templates_library/restaurant/theme.json new file mode 100644 index 00000000..0443f71b --- /dev/null +++ b/app/modules/hosting/templates_library/restaurant/theme.json @@ -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" +}