Files
orion/app/templates/platform/sections/_hero.html
Samir Boulahtit dca52d004e feat: implement section-based homepage management system
Add structured JSON sections to ContentPage for multi-language homepage editing:

Database:
- Add `sections` JSON column to content_pages table
- Migration z8i9j0k1l2m3 adds the column

Schema:
- New models/schema/homepage_sections.py with Pydantic schemas
- TranslatableText for language-keyed translations
- HeroSection, FeaturesSection, PricingSection, CTASection

Templates:
- New section partials in app/templates/platform/sections/
- Updated homepage-default.html to render sections dynamically
- Fallback to placeholder content when sections not configured

Service:
- update_homepage_sections() - validate and save all sections
- update_single_section() - update individual section
- get_default_sections() - empty structure for new homepages

API:
- GET /{page_id}/sections - get sections with platform languages
- PUT /{page_id}/sections - update all sections
- PUT /{page_id}/sections/{section_name} - update single section

Admin UI:
- Section editor appears when editing homepage (slug='home')
- Language tabs from platform.supported_languages
- Accordion sections for Hero, Features, Pricing, CTA
- Button/feature card repeaters with add/remove

Also fixes broken line 181 in z4e5f6a7b8c9 migration.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 14:31:23 +01:00

72 lines
3.2 KiB
HTML

{# app/templates/platform/sections/_hero.html #}
{# Hero section partial with multi-language support #}
{#
Parameters:
- hero: HeroSection object (or dict)
- lang: Current language code (from request.state.language)
- default_lang: Fallback language (from platform.default_language)
#}
{% macro render_hero(hero, lang, default_lang) %}
{% if hero and hero.enabled %}
<section class="gradient-primary text-white py-20 relative overflow-hidden">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center">
{# Badge #}
{% if hero.badge_text and hero.badge_text.translations %}
{% set badge = hero.badge_text.translations.get(lang) or hero.badge_text.translations.get(default_lang) %}
{% if badge %}
<div class="inline-flex items-center px-4 py-2 bg-white/20 backdrop-blur-sm rounded-full text-white text-sm font-medium mb-6">
{{ badge }}
</div>
{% endif %}
{% endif %}
{# Title #}
{% set title = hero.title.translations.get(lang) or hero.title.translations.get(default_lang) or '' %}
{% if title %}
<h1 class="text-4xl md:text-5xl lg:text-6xl font-extrabold leading-tight mb-6">
{{ title }}
</h1>
{% endif %}
{# Subtitle #}
{% set subtitle = hero.subtitle.translations.get(lang) or hero.subtitle.translations.get(default_lang) or '' %}
{% if subtitle %}
<p class="text-xl md:text-2xl mb-10 opacity-90 max-w-3xl mx-auto">
{{ subtitle }}
</p>
{% endif %}
{# Buttons #}
{% if hero.buttons %}
<div class="flex flex-col sm:flex-row gap-4 justify-center items-center">
{% for button in hero.buttons %}
{% set btn_text = button.text.translations.get(lang) or button.text.translations.get(default_lang) or '' %}
{% if btn_text and button.url %}
<a href="{{ button.url }}"
class="{% if button.style == 'primary' %}bg-white text-gray-900 hover:bg-gray-100{% elif button.style == 'secondary' %}bg-white/20 text-white hover:bg-white/30{% else %}border-2 border-white text-white hover:bg-white/10{% endif %} px-8 py-4 rounded-xl font-semibold transition inline-flex items-center space-x-2">
<span>{{ btn_text }}</span>
{% if button.style == 'primary' %}
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"></path>
</svg>
{% endif %}
</a>
{% endif %}
{% endfor %}
</div>
{% endif %}
</div>
</div>
{# Background decorations #}
<div class="absolute top-0 right-0 w-1/3 h-full opacity-10">
<svg viewBox="0 0 200 200" class="w-full h-full">
<circle cx="100" cy="100" r="80" fill="white"/>
</svg>
</div>
</section>
{% endif %}
{% endmacro %}