refactor: migrate templates and static files to self-contained modules
Templates Migration: - Migrate admin templates to modules (tenancy, billing, monitoring, marketplace, etc.) - Migrate vendor templates to modules (tenancy, billing, orders, messaging, etc.) - Migrate storefront templates to modules (catalog, customers, orders, cart, checkout, cms) - Migrate public templates to modules (billing, marketplace, cms) - Keep shared templates in app/templates/ (base.html, errors/, partials/, macros/) - Migrate letzshop partials to marketplace module Static Files Migration: - Migrate admin JS to modules: tenancy (23 files), core (5 files), monitoring (1 file) - Migrate vendor JS to modules: tenancy (4 files), core (2 files) - Migrate shared JS: vendor-selector.js to core, media-picker.js to cms - Migrate storefront JS: storefront-layout.js to core - Keep framework JS in static/ (api-client, utils, money, icons, log-config, lib/) - Update all template references to use module_static paths Naming Consistency: - Rename static/platform/ to static/public/ - Rename app/templates/platform/ to app/templates/public/ - Update all extends and static references Documentation: - Update module-system.md with shared templates documentation - Update frontend-structure.md with new module JS organization Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
246
app/modules/cms/templates/cms/public/content-page.html
Normal file
246
app/modules/cms/templates/cms/public/content-page.html
Normal file
@@ -0,0 +1,246 @@
|
||||
{# app/templates/platform/content-page.html #}
|
||||
{# Generic template for platform content pages (About, FAQ, Terms, Contact, etc.) #}
|
||||
{% extends "public/base.html" %}
|
||||
|
||||
{% block title %}{{ page.title }} - Marketplace{% endblock %}
|
||||
|
||||
{% block meta_description %}
|
||||
{% if page.meta_description %}
|
||||
{{ page.meta_description }}
|
||||
{% else %}
|
||||
{{ page.title }} - Multi-Vendor Marketplace Platform
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_keywords %}
|
||||
{% if page.meta_keywords %}
|
||||
{{ page.meta_keywords }}
|
||||
{% else %}
|
||||
{{ page.title }}, marketplace, platform
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
|
||||
{# Breadcrumbs #}
|
||||
<nav class="flex mb-8 text-sm" aria-label="Breadcrumb">
|
||||
<ol class="inline-flex items-center space-x-2">
|
||||
<li class="inline-flex items-center">
|
||||
<a href="/" class="text-gray-600 dark:text-gray-400 hover:text-primary dark:hover:text-primary transition-colors">
|
||||
<svg class="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"></path>
|
||||
</svg>
|
||||
Home
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<div class="flex items-center">
|
||||
<svg class="w-4 h-4 text-gray-400 mx-2" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="text-gray-700 dark:text-gray-300 font-medium">{{ page.title }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{# Page Header #}
|
||||
<div class="mb-12">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
{{ page.title }}
|
||||
</h1>
|
||||
|
||||
{# Published date (if available) #}
|
||||
{% if page.published_at %}
|
||||
<div class="flex items-center text-sm text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
<span>Published {{ page.published_at.strftime('%B %d, %Y') }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Page Content #}
|
||||
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-sm p-8 md:p-12">
|
||||
<div class="prose prose-lg dark:prose-invert max-w-none">
|
||||
{% if page.content_format == 'markdown' %}
|
||||
{# Future enhancement: Render with markdown library #}
|
||||
<div class="markdown-content">
|
||||
{{ page.content | safe }}{# sanitized: CMS content #}
|
||||
</div>
|
||||
{% else %}
|
||||
{# HTML content (default) #}
|
||||
{{ page.content | safe }}{# sanitized: CMS content #}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Last updated timestamp #}
|
||||
{% if page.updated_at %}
|
||||
<div class="mt-8 pt-6 border-t border-gray-200 dark:border-gray-700 text-center">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Last updated: {{ page.updated_at.strftime('%B %d, %Y') }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Call-to-action section (for specific pages) #}
|
||||
{% if page.slug in ['about', 'contact'] %}
|
||||
<div class="mt-12 bg-gradient-to-r from-purple-50 to-pink-50 dark:from-purple-900/20 dark:to-pink-900/20 rounded-2xl p-8 text-center">
|
||||
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
{% if page.slug == 'about' %}
|
||||
Ready to Get Started?
|
||||
{% elif page.slug == 'contact' %}
|
||||
Have Questions?
|
||||
{% endif %}
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-6">
|
||||
{% if page.slug == 'about' %}
|
||||
Join thousands of vendors already selling on our platform
|
||||
{% elif page.slug == 'contact' %}
|
||||
Our team is here to help you succeed
|
||||
{% endif %}
|
||||
</p>
|
||||
<a href="/contact" class="inline-block bg-gray-900 dark:bg-white text-white dark:text-gray-900 px-8 py-3 rounded-lg font-semibold hover:opacity-90 transition">
|
||||
{% if page.slug == 'about' %}
|
||||
Contact Sales
|
||||
{% elif page.slug == 'contact' %}
|
||||
Send Us a Message
|
||||
{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{# Additional styling for prose content #}
|
||||
<style>
|
||||
/* Enhanced prose styling for content pages */
|
||||
.prose {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 {
|
||||
color: inherit;
|
||||
font-weight: 700;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.prose h2 {
|
||||
font-size: 1.875rem;
|
||||
line-height: 2.25rem;
|
||||
border-bottom: 2px solid var(--color-primary);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.prose h3 {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.prose p {
|
||||
margin-bottom: 1.5em;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.prose ul, .prose ol {
|
||||
margin-bottom: 1.5em;
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
|
||||
.prose li {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.prose a {
|
||||
color: var(--color-primary);
|
||||
text-decoration: underline;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.prose a:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.prose strong {
|
||||
font-weight: 600;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.prose code {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.dark .prose code {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.prose pre {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
padding: 1em;
|
||||
border-radius: 0.5rem;
|
||||
overflow-x: auto;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.dark .prose pre {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.prose blockquote {
|
||||
border-left: 4px solid var(--color-primary);
|
||||
padding-left: 1em;
|
||||
font-style: italic;
|
||||
opacity: 0.9;
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
|
||||
.prose table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.prose th, .prose td {
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
padding: 0.75em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.dark .prose th, .dark .prose td {
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.prose th {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dark .prose th {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.prose hr {
|
||||
border: 0;
|
||||
border-top: 2px solid rgba(0, 0, 0, 0.1);
|
||||
margin: 3em 0;
|
||||
}
|
||||
|
||||
.dark .prose hr {
|
||||
border-top-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.prose img {
|
||||
border-radius: 0.5rem;
|
||||
margin: 2em auto;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
134
app/modules/cms/templates/cms/public/homepage-default.html
Normal file
134
app/modules/cms/templates/cms/public/homepage-default.html
Normal file
@@ -0,0 +1,134 @@
|
||||
{# app/templates/platform/homepage-default.html #}
|
||||
{# Default platform homepage template with section-based rendering #}
|
||||
{% extends "public/base.html" %}
|
||||
|
||||
{# Import section partials #}
|
||||
{% from 'platform/sections/_hero.html' import render_hero %}
|
||||
{% from 'platform/sections/_features.html' import render_features %}
|
||||
{% from 'platform/sections/_pricing.html' import render_pricing %}
|
||||
{% from 'platform/sections/_cta.html' import render_cta %}
|
||||
|
||||
{% block title %}
|
||||
{% if page %}{{ page.title }}{% else %}Home{% endif %} - {{ platform.name if platform else 'Multi-Vendor Marketplace' }}
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_description %}
|
||||
{% if page and page.meta_description %}
|
||||
{{ page.meta_description }}
|
||||
{% else %}
|
||||
Leading multi-vendor marketplace platform. Connect with thousands of vendors and discover millions of products.
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{# Set up language context #}
|
||||
{% set lang = request.state.language|default("fr") or (platform.default_language if platform else 'fr') %}
|
||||
{% set default_lang = platform.default_language if platform else 'fr' %}
|
||||
|
||||
{# ═══════════════════════════════════════════════════════════════════════════ #}
|
||||
{# SECTION-BASED RENDERING (when page.sections is configured) #}
|
||||
{# ═══════════════════════════════════════════════════════════════════════════ #}
|
||||
{% if page and page.sections %}
|
||||
|
||||
{# Hero Section #}
|
||||
{% if page.sections.hero %}
|
||||
{{ render_hero(page.sections.hero, lang, default_lang) }}
|
||||
{% endif %}
|
||||
|
||||
{# Features Section #}
|
||||
{% if page.sections.features %}
|
||||
{{ render_features(page.sections.features, lang, default_lang) }}
|
||||
{% endif %}
|
||||
|
||||
{# Pricing Section #}
|
||||
{% if page.sections.pricing %}
|
||||
{{ render_pricing(page.sections.pricing, lang, default_lang, tiers) }}
|
||||
{% endif %}
|
||||
|
||||
{# CTA Section #}
|
||||
{% if page.sections.cta %}
|
||||
{{ render_cta(page.sections.cta, lang, default_lang) }}
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
{# ═══════════════════════════════════════════════════════════════════════════ #}
|
||||
{# PLACEHOLDER CONTENT (when sections not configured) #}
|
||||
{# ═══════════════════════════════════════════════════════════════════════════ #}
|
||||
|
||||
<!-- HERO SECTION -->
|
||||
<section class="gradient-primary text-white py-20">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="text-center">
|
||||
<h1 class="text-4xl md:text-6xl font-bold mb-6">
|
||||
{{ _('homepage.placeholder.title') or 'Configure Your Homepage' }}
|
||||
</h1>
|
||||
<p class="text-xl md:text-2xl mb-8 opacity-90 max-w-3xl mx-auto">
|
||||
{{ _('homepage.placeholder.subtitle') or 'Use the admin panel to configure homepage sections with multi-language content.' }}
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
||||
<a href="/admin/content-pages"
|
||||
class="bg-white text-gray-900 px-8 py-4 rounded-xl font-semibold hover:bg-gray-100 transition inline-flex items-center space-x-2">
|
||||
<span>{{ _('homepage.placeholder.configure_btn') or 'Configure Homepage' }}</span>
|
||||
<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>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FEATURES SECTION (Placeholder) -->
|
||||
<section class="py-16 bg-white dark:bg-gray-800">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
{{ _('homepage.placeholder.features_title') or 'Features Section' }}
|
||||
</h2>
|
||||
<p class="text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
{{ _('homepage.placeholder.features_subtitle') or 'Configure feature cards in the admin panel' }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{% for i in range(3) %}
|
||||
<div class="bg-gray-50 dark:bg-gray-700 rounded-xl p-8 text-center">
|
||||
<div class="w-16 h-16 mx-auto mb-4 rounded-full bg-gray-200 dark:bg-gray-600 flex items-center justify-center">
|
||||
<svg class="w-8 h-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-gray-400 mb-3">
|
||||
Feature {{ i + 1 }}
|
||||
</h3>
|
||||
<p class="text-gray-400">
|
||||
Configure this feature card
|
||||
</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA SECTION (Placeholder) -->
|
||||
<section class="py-16 bg-gray-100 dark:bg-gray-900">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-400 mb-4">
|
||||
{{ _('homepage.placeholder.cta_title') or 'Call to Action' }}
|
||||
</h2>
|
||||
<p class="text-lg text-gray-400 mb-8">
|
||||
{{ _('homepage.placeholder.cta_subtitle') or 'Configure CTA section in the admin panel' }}
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<span class="bg-gray-300 text-gray-500 px-6 py-3 rounded-lg font-semibold">
|
||||
Button 1
|
||||
</span>
|
||||
<span class="bg-gray-200 text-gray-500 px-6 py-3 rounded-lg font-semibold">
|
||||
Button 2
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
100
app/modules/cms/templates/cms/public/homepage-minimal.html
Normal file
100
app/modules/cms/templates/cms/public/homepage-minimal.html
Normal file
@@ -0,0 +1,100 @@
|
||||
{# app/templates/platform/homepage-minimal.html #}
|
||||
{# Minimal/clean platform homepage template #}
|
||||
{% extends "public/base.html" %}
|
||||
|
||||
{% block title %}
|
||||
{% if page %}{{ page.title }}{% else %}Home{% endif %} - Marketplace
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- MINIMAL HERO -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<section class="py-32 bg-white dark:bg-gray-800">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
{% if page %}
|
||||
<h1 class="text-5xl md:text-7xl font-bold text-gray-900 dark:text-white mb-8 leading-tight">
|
||||
{{ page.title }}
|
||||
</h1>
|
||||
<div class="text-xl text-gray-600 dark:text-gray-400 mb-12 max-w-2xl mx-auto">
|
||||
{{ page.content | safe }}{# sanitized: CMS content #}
|
||||
</div>
|
||||
{% else %}
|
||||
<h1 class="text-5xl md:text-7xl font-bold text-gray-900 dark:text-white mb-8 leading-tight">
|
||||
Multi-Vendor<br>Marketplace
|
||||
</h1>
|
||||
<p class="text-xl text-gray-600 dark:text-gray-400 mb-12 max-w-2xl mx-auto">
|
||||
The simplest way to launch your online store and connect with customers worldwide.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<a href="/contact"
|
||||
class="inline-block bg-gray-900 dark:bg-white text-white dark:text-gray-900 px-8 py-4 rounded-lg font-semibold hover:opacity-90 transition text-lg">
|
||||
Get Started
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- MINIMAL FEATURES -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<section class="py-24 bg-gray-50 dark:bg-gray-900">
|
||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-12">
|
||||
<div class="text-center">
|
||||
<div class="text-4xl mb-4">⚡</div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Fast
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm">
|
||||
Lightning-fast performance optimized for conversions
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<div class="text-4xl mb-4">🔒</div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Secure
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm">
|
||||
Enterprise-grade security for your peace of mind
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<div class="text-4xl mb-4">🎨</div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Custom
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm">
|
||||
Fully customizable to match your brand identity
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- MINIMAL CTA -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<section class="py-24 bg-white dark:bg-gray-800">
|
||||
<div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<h2 class="text-3xl font-bold text-gray-900 dark:text-white mb-6">
|
||||
Ready to launch?
|
||||
</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-8">
|
||||
Join our marketplace today
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<a href="/contact"
|
||||
class="inline-block bg-gray-900 dark:bg-white text-white dark:text-gray-900 px-6 py-3 rounded-lg font-semibold hover:opacity-90 transition">
|
||||
Contact Us
|
||||
</a>
|
||||
<a href="/about"
|
||||
class="inline-block border-2 border-gray-900 dark:border-white text-gray-900 dark:text-white px-6 py-3 rounded-lg font-semibold hover:bg-gray-50 dark:hover:bg-gray-700 transition">
|
||||
Learn More
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
598
app/modules/cms/templates/cms/public/homepage-modern.html
Normal file
598
app/modules/cms/templates/cms/public/homepage-modern.html
Normal file
@@ -0,0 +1,598 @@
|
||||
{# app/templates/platform/homepage-modern.html #}
|
||||
{# Wizamart OMS - Luxembourg-focused homepage inspired by Veeqo #}
|
||||
{% extends "public/base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Wizamart - The Back-Office for Letzshop Sellers
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
<style>
|
||||
.gradient-lu {
|
||||
background: linear-gradient(135deg, #00A1DE 0%, #EF3340 100%);
|
||||
}
|
||||
.gradient-lu-subtle {
|
||||
background: linear-gradient(135deg, #f0f9ff 0%, #fef2f2 100%);
|
||||
}
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0px); }
|
||||
50% { transform: translateY(-10px); }
|
||||
}
|
||||
.float-animation {
|
||||
animation: float 4s ease-in-out infinite;
|
||||
}
|
||||
.feature-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- HERO - The Back-Office Letzshop Doesn't Give You -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<section class="relative overflow-hidden bg-gray-900 text-white py-20 md:py-28">
|
||||
{# Background pattern #}
|
||||
<div class="absolute inset-0 opacity-10">
|
||||
<div class="absolute top-0 left-0 w-full h-full" style="background-image: url('data:image/svg+xml,%3Csvg width=\"60\" height=\"60\" viewBox=\"0 0 60 60\" xmlns=\"http://www.w3.org/2000/svg\"%3E%3Cg fill=\"none\" fill-rule=\"evenodd\"%3E%3Cg fill=\"%23ffffff\" fill-opacity=\"0.4\"%3E%3Cpath d=\"M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z\"/%3E%3C/g%3E%3C/g%3E%3C/svg%3E');"></div>
|
||||
</div>
|
||||
|
||||
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
{# Left column - Content #}
|
||||
<div>
|
||||
<div class="inline-flex items-center px-4 py-2 bg-blue-500/20 backdrop-blur-sm rounded-full text-sm font-medium mb-6 border border-blue-400/30">
|
||||
<span class="mr-2">🇱🇺</span> Built for Luxembourg E-Commerce
|
||||
</div>
|
||||
|
||||
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold mb-6 leading-tight">
|
||||
The Back-Office<br>
|
||||
<span class="text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-cyan-400">
|
||||
Letzshop Doesn't Give You
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p class="text-xl md:text-2xl text-gray-300 mb-8 leading-relaxed">
|
||||
Sync orders, manage inventory, generate invoices with correct VAT, and own your customer data. All in one place.
|
||||
</p>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-4 mb-8">
|
||||
<a href="/contact"
|
||||
class="inline-flex items-center justify-center bg-blue-500 hover:bg-blue-600 text-white px-8 py-4 rounded-xl font-bold transition-all duration-200 shadow-lg hover:shadow-xl">
|
||||
<span>Start 14-Day Free Trial</span>
|
||||
<svg class="w-5 h-5 ml-2" 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>
|
||||
</a>
|
||||
<a href="#how-it-works"
|
||||
class="inline-flex items-center justify-center border-2 border-gray-600 text-white px-8 py-4 rounded-xl font-bold hover:bg-white/10 transition-all duration-200">
|
||||
See How It Works
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-gray-400">
|
||||
No credit card required. Setup in 5 minutes. Cancel anytime.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{# Right column - Dashboard Preview #}
|
||||
<div class="hidden lg:block">
|
||||
<div class="relative float-animation">
|
||||
<div class="bg-gray-800 rounded-2xl shadow-2xl border border-gray-700 overflow-hidden">
|
||||
{# Mock dashboard header #}
|
||||
<div class="bg-gray-900 px-4 py-3 flex items-center gap-2 border-b border-gray-700">
|
||||
<div class="w-3 h-3 rounded-full bg-red-500"></div>
|
||||
<div class="w-3 h-3 rounded-full bg-yellow-500"></div>
|
||||
<div class="w-3 h-3 rounded-full bg-green-500"></div>
|
||||
<span class="ml-4 text-gray-400 text-sm">Wizamart Dashboard</span>
|
||||
</div>
|
||||
{# Mock dashboard content #}
|
||||
<div class="p-6 space-y-4">
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div class="bg-gray-700/50 rounded-lg p-4">
|
||||
<div class="text-gray-400 text-xs mb-1">Today's Orders</div>
|
||||
<div class="text-2xl font-bold text-white">24</div>
|
||||
<div class="text-green-400 text-xs">+12% vs yesterday</div>
|
||||
</div>
|
||||
<div class="bg-gray-700/50 rounded-lg p-4">
|
||||
<div class="text-gray-400 text-xs mb-1">Revenue</div>
|
||||
<div class="text-2xl font-bold text-white">EUR 1,847</div>
|
||||
<div class="text-green-400 text-xs">+8% vs yesterday</div>
|
||||
</div>
|
||||
<div class="bg-gray-700/50 rounded-lg p-4">
|
||||
<div class="text-gray-400 text-xs mb-1">Low Stock</div>
|
||||
<div class="text-2xl font-bold text-yellow-400">3</div>
|
||||
<div class="text-gray-400 text-xs">items need restock</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-700/50 rounded-lg p-4">
|
||||
<div class="text-gray-400 text-xs mb-3">Recent Orders from Letzshop</div>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between items-center text-sm">
|
||||
<span class="text-white">#LS-4521</span>
|
||||
<span class="text-gray-400">Marie D.</span>
|
||||
<span class="text-green-400">EUR 89.00</span>
|
||||
<span class="bg-blue-500/20 text-blue-400 px-2 py-0.5 rounded text-xs">Confirmed</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center text-sm">
|
||||
<span class="text-white">#LS-4520</span>
|
||||
<span class="text-gray-400">Jean M.</span>
|
||||
<span class="text-green-400">EUR 156.50</span>
|
||||
<span class="bg-purple-500/20 text-purple-400 px-2 py-0.5 rounded text-xs">Shipped</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- INTEGRATION BADGE - Works with Letzshop -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<section class="py-8 bg-gray-50 dark:bg-gray-800 border-y border-gray-200 dark:border-gray-700">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex flex-col md:flex-row items-center justify-center gap-6 md:gap-12">
|
||||
<span class="text-gray-500 dark:text-gray-400 font-medium">Official Integration</span>
|
||||
<div class="flex items-center gap-3 bg-white dark:bg-gray-700 px-6 py-3 rounded-xl shadow-sm">
|
||||
<span class="text-2xl">🛒</span>
|
||||
<span class="font-bold text-gray-900 dark:text-white">Letzshop.lu</span>
|
||||
</div>
|
||||
<span class="text-gray-500 dark:text-gray-400 text-sm">Connect in 2 minutes</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- THE PROBLEM - Pain Points -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<section class="py-20 bg-white dark:bg-gray-900">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="text-center mb-16">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Sound Familiar?
|
||||
</h2>
|
||||
<p class="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
These are the daily frustrations of Letzshop sellers
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-xl p-6">
|
||||
<div class="text-3xl mb-4">📋</div>
|
||||
<h3 class="font-bold text-gray-900 dark:text-white mb-2">Manual Order Entry</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm">Copy-pasting orders from Letzshop to spreadsheets. Every. Single. Day.</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-xl p-6">
|
||||
<div class="text-3xl mb-4">📦</div>
|
||||
<h3 class="font-bold text-gray-900 dark:text-white mb-2">Inventory Chaos</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm">Stock in Letzshop doesn't match reality. Overselling happens.</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-xl p-6">
|
||||
<div class="text-3xl mb-4">🧾</div>
|
||||
<h3 class="font-bold text-gray-900 dark:text-white mb-2">Wrong VAT Invoices</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm">EU customers need correct VAT. Your accountant keeps complaining.</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-xl p-6">
|
||||
<div class="text-3xl mb-4">👥</div>
|
||||
<h3 class="font-bold text-gray-900 dark:text-white mb-2">Lost Customers</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm">Letzshop owns your customer data. You can't retarget or build loyalty.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- HOW IT WORKS - 4-Step Workflow (Veeqo-style) -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<section id="how-it-works" class="py-20 gradient-lu-subtle dark:bg-gray-800">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="text-center mb-16">
|
||||
<div class="inline-block px-4 py-2 bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 rounded-full text-sm font-semibold mb-4">
|
||||
How It Works
|
||||
</div>
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
From Chaos to Control in 4 Steps
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
{# Step 1 #}
|
||||
<div class="relative">
|
||||
<div class="bg-white dark:bg-gray-900 rounded-2xl p-8 shadow-lg h-full">
|
||||
<div class="w-12 h-12 rounded-full bg-blue-500 text-white flex items-center justify-center font-bold text-xl mb-6">1</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3">Connect Letzshop</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">Enter your Letzshop API credentials. Done in 2 minutes, no technical skills needed.</p>
|
||||
</div>
|
||||
<div class="hidden lg:block absolute top-1/2 -right-4 w-8 h-0.5 bg-blue-300"></div>
|
||||
</div>
|
||||
|
||||
{# Step 2 #}
|
||||
<div class="relative">
|
||||
<div class="bg-white dark:bg-gray-900 rounded-2xl p-8 shadow-lg h-full">
|
||||
<div class="w-12 h-12 rounded-full bg-blue-500 text-white flex items-center justify-center font-bold text-xl mb-6">2</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3">Orders Flow In</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">Orders sync automatically. Confirm and add tracking directly from Wizamart.</p>
|
||||
</div>
|
||||
<div class="hidden lg:block absolute top-1/2 -right-4 w-8 h-0.5 bg-blue-300"></div>
|
||||
</div>
|
||||
|
||||
{# Step 3 #}
|
||||
<div class="relative">
|
||||
<div class="bg-white dark:bg-gray-900 rounded-2xl p-8 shadow-lg h-full">
|
||||
<div class="w-12 h-12 rounded-full bg-blue-500 text-white flex items-center justify-center font-bold text-xl mb-6">3</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3">Generate Invoices</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">One click to create compliant PDF invoices with correct VAT for any EU country.</p>
|
||||
</div>
|
||||
<div class="hidden lg:block absolute top-1/2 -right-4 w-8 h-0.5 bg-blue-300"></div>
|
||||
</div>
|
||||
|
||||
{# Step 4 #}
|
||||
<div class="relative">
|
||||
<div class="bg-white dark:bg-gray-900 rounded-2xl p-8 shadow-lg h-full">
|
||||
<div class="w-12 h-12 rounded-full bg-green-500 text-white flex items-center justify-center font-bold text-xl mb-6">4</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3">Grow Your Business</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">Export customers for marketing. Track inventory. Focus on selling, not spreadsheets.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- FEATURES - What You Get -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<section id="features" class="py-20 bg-white dark:bg-gray-900">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="text-center mb-16">
|
||||
<div class="inline-block px-4 py-2 bg-green-100 dark:bg-green-900/30 text-green-600 dark:text-green-400 rounded-full text-sm font-semibold mb-4">
|
||||
Features
|
||||
</div>
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Everything a Letzshop Seller Needs
|
||||
</h2>
|
||||
<p class="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
The operational tools Letzshop doesn't provide
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{# Feature 1: Order Sync #}
|
||||
<div class="feature-card bg-gray-50 dark:bg-gray-800 rounded-2xl p-8 transition-all duration-300">
|
||||
<div class="w-14 h-14 rounded-2xl bg-blue-500 flex items-center justify-center mb-6">
|
||||
<svg class="w-7 h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3">Automatic Order Sync</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-4">Orders from Letzshop appear instantly. Confirm orders and sync tracking numbers back automatically.</p>
|
||||
<ul class="text-sm text-gray-500 dark:text-gray-400 space-y-1">
|
||||
<li>Real-time sync</li>
|
||||
<li>One-click confirmation</li>
|
||||
<li>Tracking number sync</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{# Feature 2: Inventory #}
|
||||
<div class="feature-card bg-gray-50 dark:bg-gray-800 rounded-2xl p-8 transition-all duration-300">
|
||||
<div class="w-14 h-14 rounded-2xl bg-green-500 flex items-center justify-center mb-6">
|
||||
<svg class="w-7 h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3">Real Inventory Management</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-4">One source of truth for all stock. Locations, reservations, and incoming stock tracking.</p>
|
||||
<ul class="text-sm text-gray-500 dark:text-gray-400 space-y-1">
|
||||
<li>Product locations (bins)</li>
|
||||
<li>Stock reservations</li>
|
||||
<li>Low stock alerts</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{# Feature 3: Invoicing #}
|
||||
<div class="feature-card bg-gray-50 dark:bg-gray-800 rounded-2xl p-8 transition-all duration-300">
|
||||
<div class="w-14 h-14 rounded-2xl bg-purple-500 flex items-center justify-center mb-6">
|
||||
<svg class="w-7 h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3">Smart VAT Invoicing</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-4">Generate PDF invoices with correct VAT rates. Luxembourg, EU countries, B2B reverse charge.</p>
|
||||
<ul class="text-sm text-gray-500 dark:text-gray-400 space-y-1">
|
||||
<li>Luxembourg 17% VAT</li>
|
||||
<li>EU destination VAT (OSS)</li>
|
||||
<li>B2B reverse charge</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{# Feature 4: Customers #}
|
||||
<div class="feature-card bg-gray-50 dark:bg-gray-800 rounded-2xl p-8 transition-all duration-300">
|
||||
<div class="w-14 h-14 rounded-2xl bg-orange-500 flex items-center justify-center mb-6">
|
||||
<svg class="w-7 h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3">Own Your Customers</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-4">All customer data in your database. Export to Mailchimp for marketing campaigns.</p>
|
||||
<ul class="text-sm text-gray-500 dark:text-gray-400 space-y-1">
|
||||
<li>Order history per customer</li>
|
||||
<li>Lifetime value tracking</li>
|
||||
<li>CSV export for marketing</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{# Feature 5: Team #}
|
||||
<div class="feature-card bg-gray-50 dark:bg-gray-800 rounded-2xl p-8 transition-all duration-300">
|
||||
<div class="w-14 h-14 rounded-2xl bg-cyan-500 flex items-center justify-center mb-6">
|
||||
<svg class="w-7 h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3">Team Management</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-4">Invite team members with role-based permissions. Everyone works from one dashboard.</p>
|
||||
<ul class="text-sm text-gray-500 dark:text-gray-400 space-y-1">
|
||||
<li>Multiple users</li>
|
||||
<li>Role-based access</li>
|
||||
<li>Activity logging</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{# Feature 6: Purchase Orders #}
|
||||
<div class="feature-card bg-gray-50 dark:bg-gray-800 rounded-2xl p-8 transition-all duration-300">
|
||||
<div class="w-14 h-14 rounded-2xl bg-pink-500 flex items-center justify-center mb-6">
|
||||
<svg class="w-7 h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3">Purchase Orders</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-4">Track incoming stock from suppliers. Know what's on order and when it arrives.</p>
|
||||
<ul class="text-sm text-gray-500 dark:text-gray-400 space-y-1">
|
||||
<li>Track supplier orders</li>
|
||||
<li>Expected arrival dates</li>
|
||||
<li>Receive and update stock</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- PRICING - 4 Tiers -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<section id="pricing" class="py-20 bg-gray-50 dark:bg-gray-800">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="text-center mb-16">
|
||||
<div class="inline-block px-4 py-2 bg-purple-100 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400 rounded-full text-sm font-semibold mb-4">
|
||||
Pricing
|
||||
</div>
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Simple, Transparent Pricing
|
||||
</h2>
|
||||
<p class="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
No per-order fees. No hidden costs. Flat monthly rate.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{# Essential #}
|
||||
<div class="bg-white dark:bg-gray-900 rounded-2xl p-8 shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2">Essential</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-sm mb-4">For solo vendors getting started</p>
|
||||
<div class="mb-6">
|
||||
<span class="text-4xl font-bold text-gray-900 dark:text-white">EUR 49</span>
|
||||
<span class="text-gray-500 dark:text-gray-400">/month</span>
|
||||
</div>
|
||||
<ul class="space-y-3 mb-8 text-sm">
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
100 orders/month
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
200 products
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
Luxembourg VAT invoices
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
1 team member
|
||||
</li>
|
||||
</ul>
|
||||
<a href="/contact" class="block w-full text-center bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-white px-6 py-3 rounded-xl font-semibold hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
|
||||
Start Free Trial
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{# Professional - Highlighted #}
|
||||
<div class="bg-blue-600 rounded-2xl p-8 shadow-xl relative transform lg:scale-105">
|
||||
<div class="absolute -top-4 left-1/2 -translate-x-1/2 bg-orange-500 text-white text-xs font-bold px-3 py-1 rounded-full">
|
||||
MOST POPULAR
|
||||
</div>
|
||||
<h3 class="text-lg font-bold text-white mb-2">Professional</h3>
|
||||
<p class="text-blue-200 text-sm mb-4">For growing multi-channel sellers</p>
|
||||
<div class="mb-6">
|
||||
<span class="text-4xl font-bold text-white">EUR 99</span>
|
||||
<span class="text-blue-200">/month</span>
|
||||
</div>
|
||||
<ul class="space-y-3 mb-8 text-sm">
|
||||
<li class="flex items-center text-blue-100">
|
||||
<svg class="w-5 h-5 text-green-400 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
500 orders/month
|
||||
</li>
|
||||
<li class="flex items-center text-blue-100">
|
||||
<svg class="w-5 h-5 text-green-400 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
Unlimited products
|
||||
</li>
|
||||
<li class="flex items-center text-blue-100">
|
||||
<svg class="w-5 h-5 text-green-400 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
<strong>EU VAT invoices</strong>
|
||||
</li>
|
||||
<li class="flex items-center text-blue-100">
|
||||
<svg class="w-5 h-5 text-green-400 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
Product locations
|
||||
</li>
|
||||
<li class="flex items-center text-blue-100">
|
||||
<svg class="w-5 h-5 text-green-400 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
Purchase orders
|
||||
</li>
|
||||
<li class="flex items-center text-blue-100">
|
||||
<svg class="w-5 h-5 text-green-400 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
Customer export
|
||||
</li>
|
||||
<li class="flex items-center text-blue-100">
|
||||
<svg class="w-5 h-5 text-green-400 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
3 team members
|
||||
</li>
|
||||
</ul>
|
||||
<a href="/contact" class="block w-full text-center bg-white text-blue-600 px-6 py-3 rounded-xl font-bold hover:bg-blue-50 transition-colors">
|
||||
Start Free Trial
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{# Business #}
|
||||
<div class="bg-white dark:bg-gray-900 rounded-2xl p-8 shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2">Business</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-sm mb-4">For high-volume operations</p>
|
||||
<div class="mb-6">
|
||||
<span class="text-4xl font-bold text-gray-900 dark:text-white">EUR 199</span>
|
||||
<span class="text-gray-500 dark:text-gray-400">/month</span>
|
||||
</div>
|
||||
<ul class="space-y-3 mb-8 text-sm">
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
2,000 orders/month
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
Everything in Professional
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
<strong>Analytics dashboard</strong>
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
<strong>API access</strong>
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
Accounting export
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
10 team members
|
||||
</li>
|
||||
</ul>
|
||||
<a href="/contact" class="block w-full text-center bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-white px-6 py-3 rounded-xl font-semibold hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
|
||||
Start Free Trial
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{# Enterprise #}
|
||||
<div class="bg-white dark:bg-gray-900 rounded-2xl p-8 shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2">Enterprise</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-sm mb-4">For large operations & agencies</p>
|
||||
<div class="mb-6">
|
||||
<span class="text-4xl font-bold text-gray-900 dark:text-white">EUR 399+</span>
|
||||
<span class="text-gray-500 dark:text-gray-400">/month</span>
|
||||
</div>
|
||||
<ul class="space-y-3 mb-8 text-sm">
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
Unlimited orders
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
Everything in Business
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
<strong>White-label option</strong>
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
Custom integrations
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
99.9% SLA
|
||||
</li>
|
||||
<li class="flex items-center text-gray-600 dark:text-gray-400">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
Dedicated support
|
||||
</li>
|
||||
</ul>
|
||||
<a href="/contact" class="block w-full text-center bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-white px-6 py-3 rounded-xl font-semibold hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
|
||||
Contact Sales
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-center text-gray-500 dark:text-gray-400 mt-8">
|
||||
All plans include a 14-day free trial. No credit card required.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- TESTIMONIAL / SOCIAL PROOF -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<section class="py-20 bg-white dark:bg-gray-900">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<div class="inline-block px-4 py-2 bg-yellow-100 dark:bg-yellow-900/30 text-yellow-600 dark:text-yellow-400 rounded-full text-sm font-semibold mb-8">
|
||||
Built for Luxembourg
|
||||
</div>
|
||||
|
||||
<blockquote class="text-2xl md:text-3xl font-medium text-gray-900 dark:text-white mb-8 leading-relaxed">
|
||||
"Finally, a tool that understands what Letzshop sellers actually need. No more spreadsheets, no more VAT headaches."
|
||||
</blockquote>
|
||||
|
||||
<div class="flex items-center justify-center gap-4">
|
||||
<div class="w-12 h-12 bg-gray-200 dark:bg-gray-700 rounded-full flex items-center justify-center text-xl">
|
||||
👩
|
||||
</div>
|
||||
<div class="text-left">
|
||||
<div class="font-semibold text-gray-900 dark:text-white">Marie L.</div>
|
||||
<div class="text-gray-500 dark:text-gray-400 text-sm">Letzshop Vendor, Luxembourg City</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- FINAL CTA -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<section class="py-20 bg-gray-900 text-white">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<h2 class="text-3xl md:text-4xl font-bold mb-6">
|
||||
Ready to Take Control of Your Letzshop Business?
|
||||
</h2>
|
||||
<p class="text-xl text-gray-300 mb-10">
|
||||
Join Luxembourg vendors who've stopped fighting spreadsheets and started growing their business.
|
||||
</p>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<a href="/contact"
|
||||
class="inline-flex items-center justify-center bg-blue-500 hover:bg-blue-600 text-white px-8 py-4 rounded-xl font-bold transition-all duration-200 shadow-lg">
|
||||
<span>Start Your 14-Day Free Trial</span>
|
||||
<svg class="w-5 h-5 ml-2" 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>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p class="mt-8 text-sm text-gray-400">
|
||||
No credit card required. Setup in 5 minutes. Full Professional features during trial.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
427
app/modules/cms/templates/cms/public/homepage-wizamart.html
Normal file
427
app/modules/cms/templates/cms/public/homepage-wizamart.html
Normal file
@@ -0,0 +1,427 @@
|
||||
{# app/templates/platform/homepage-wizamart.html #}
|
||||
{# Wizamart Marketing Homepage - Letzshop OMS Platform #}
|
||||
{% extends "public/base.html" %}
|
||||
{% from 'shared/macros/inputs.html' import toggle_switch %}
|
||||
|
||||
{% block title %}Wizamart - Order Management for Letzshop Sellers{% endblock %}
|
||||
{% block meta_description %}Lightweight OMS for Letzshop vendors. Manage orders, inventory, and invoicing. Start your 30-day free trial today.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div x-data="homepageData()" class="bg-gray-50 dark:bg-gray-900">
|
||||
|
||||
{# =========================================================================
|
||||
HERO SECTION
|
||||
========================================================================= #}
|
||||
<section class="relative overflow-hidden">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 lg:py-24">
|
||||
<div class="text-center">
|
||||
{# Badge #}
|
||||
<div class="inline-flex items-center px-4 py-2 bg-indigo-100 dark:bg-indigo-900/30 rounded-full text-indigo-700 dark:text-indigo-300 text-sm font-medium mb-6">
|
||||
<svg class="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{{ _("platform.hero.badge", trial_days=trial_days) }}
|
||||
</div>
|
||||
|
||||
{# Headline #}
|
||||
<h1 class="text-4xl md:text-5xl lg:text-6xl font-extrabold text-gray-900 dark:text-white leading-tight mb-6">
|
||||
{{ _("platform.hero.title") }}
|
||||
</h1>
|
||||
|
||||
{# Subheadline #}
|
||||
<p class="text-xl text-gray-600 dark:text-gray-400 max-w-3xl mx-auto mb-10">
|
||||
{{ _("platform.hero.subtitle") }}
|
||||
</p>
|
||||
|
||||
{# CTA Buttons #}
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<a href="/signup"
|
||||
class="inline-flex items-center justify-center px-8 py-4 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold rounded-xl shadow-lg shadow-indigo-500/30 transition-all hover:scale-105">
|
||||
{{ _("platform.hero.cta_trial") }}
|
||||
<svg class="w-5 h-5 ml-2" 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"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="#find-shop"
|
||||
class="inline-flex items-center justify-center px-8 py-4 bg-white dark:bg-gray-800 text-gray-900 dark:text-white font-semibold rounded-xl border-2 border-gray-200 dark:border-gray-700 hover:border-indigo-500 transition-all">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
|
||||
</svg>
|
||||
{{ _("platform.hero.cta_find_shop") }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Background Decoration #}
|
||||
<div class="absolute inset-0 -z-10 overflow-hidden">
|
||||
<div class="absolute -top-1/2 -right-1/4 w-96 h-96 bg-indigo-200 dark:bg-indigo-900/20 rounded-full blur-3xl opacity-50"></div>
|
||||
<div class="absolute -bottom-1/2 -left-1/4 w-96 h-96 bg-purple-200 dark:bg-purple-900/20 rounded-full blur-3xl opacity-50"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# =========================================================================
|
||||
PRICING SECTION
|
||||
========================================================================= #}
|
||||
<section id="pricing" class="py-16 lg:py-24 bg-white dark:bg-gray-800">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
{# Section Header #}
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
{{ _("platform.pricing.title") }}
|
||||
</h2>
|
||||
<p class="text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
{{ _("platform.pricing.subtitle", trial_days=trial_days) }}
|
||||
</p>
|
||||
|
||||
{# Billing Toggle #}
|
||||
<div class="flex justify-center mt-8">
|
||||
{{ toggle_switch(
|
||||
model='annual',
|
||||
left_label=_("platform.pricing.monthly"),
|
||||
right_label=_("platform.pricing.annual"),
|
||||
right_badge=_("platform.pricing.save_months")
|
||||
) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Pricing Cards Grid #}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{% for tier in tiers %}
|
||||
<div class="relative bg-gray-50 dark:bg-gray-900 rounded-2xl p-6 border-2 transition-all hover:shadow-xl
|
||||
{% if tier.is_popular %}border-indigo-500 shadow-lg{% else %}border-gray-200 dark:border-gray-700{% endif %}">
|
||||
|
||||
{# Popular Badge #}
|
||||
{% if tier.is_popular %}
|
||||
<div class="absolute -top-3 left-1/2 -translate-x-1/2">
|
||||
<span class="bg-indigo-600 text-white text-xs font-bold px-3 py-1 rounded-full">
|
||||
{{ _("platform.pricing.most_popular") }}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Tier Name #}
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-2">{{ tier.name }}</h3>
|
||||
|
||||
{# Price #}
|
||||
<div class="mb-6">
|
||||
<template x-if="!annual">
|
||||
<div>
|
||||
<span class="text-4xl font-extrabold text-gray-900 dark:text-white">{{ tier.price_monthly|int }}€</span>
|
||||
<span class="text-gray-500 dark:text-gray-400">{{ _("platform.pricing.per_month") }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="annual">
|
||||
<div>
|
||||
{% if tier.price_annual %}
|
||||
<span class="text-4xl font-extrabold text-gray-900 dark:text-white">{{ (tier.price_annual / 12)|round(0)|int }}€</span>
|
||||
<span class="text-gray-500 dark:text-gray-400">{{ _("platform.pricing.per_month") }}</span>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ tier.price_annual|int }}€ {{ _("platform.pricing.per_year") }}
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="text-2xl font-bold text-gray-900 dark:text-white">{{ _("platform.pricing.custom") }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
{# Features List - Show all features, grey out unavailable #}
|
||||
<ul class="space-y-2 mb-8 text-sm">
|
||||
{# Orders #}
|
||||
<li class="flex items-center text-gray-700 dark:text-gray-300">
|
||||
<svg class="w-4 h-4 text-green-500 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{% if tier.orders_per_month %}{{ _("platform.pricing.orders_per_month", count=tier.orders_per_month) }}{% else %}{{ _("platform.pricing.unlimited_orders") }}{% endif %}
|
||||
</li>
|
||||
{# Products #}
|
||||
<li class="flex items-center text-gray-700 dark:text-gray-300">
|
||||
<svg class="w-4 h-4 text-green-500 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{% if tier.products_limit %}{{ _("platform.pricing.products_limit", count=tier.products_limit) }}{% else %}{{ _("platform.pricing.unlimited_products") }}{% endif %}
|
||||
</li>
|
||||
{# Team Members #}
|
||||
<li class="flex items-center text-gray-700 dark:text-gray-300">
|
||||
<svg class="w-4 h-4 text-green-500 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{% if tier.team_members %}{{ _("platform.pricing.team_members", count=tier.team_members) }}{% else %}{{ _("platform.pricing.unlimited_team") }}{% endif %}
|
||||
</li>
|
||||
{# Letzshop Sync - always included #}
|
||||
<li class="flex items-center text-gray-700 dark:text-gray-300">
|
||||
<svg class="w-4 h-4 text-green-500 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{{ _("platform.pricing.letzshop_sync") }}
|
||||
</li>
|
||||
{# EU VAT Invoicing #}
|
||||
<li class="flex items-center {% if 'invoice_eu_vat' in tier.features %}text-gray-700 dark:text-gray-300{% else %}text-gray-400 dark:text-gray-600{% endif %}">
|
||||
{% if 'invoice_eu_vat' in tier.features %}
|
||||
<svg class="w-4 h-4 text-green-500 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{% else %}
|
||||
<svg class="w-4 h-4 text-gray-300 dark:text-gray-600 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{% endif %}
|
||||
{{ _("platform.pricing.eu_vat_invoicing") }}
|
||||
</li>
|
||||
{# Analytics Dashboard #}
|
||||
<li class="flex items-center {% if 'analytics_dashboard' in tier.features %}text-gray-700 dark:text-gray-300{% else %}text-gray-400 dark:text-gray-600{% endif %}">
|
||||
{% if 'analytics_dashboard' in tier.features %}
|
||||
<svg class="w-4 h-4 text-green-500 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{% else %}
|
||||
<svg class="w-4 h-4 text-gray-300 dark:text-gray-600 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{% endif %}
|
||||
{{ _("platform.pricing.analytics_dashboard") }}
|
||||
</li>
|
||||
{# API Access #}
|
||||
<li class="flex items-center {% if 'api_access' in tier.features %}text-gray-700 dark:text-gray-300{% else %}text-gray-400 dark:text-gray-600{% endif %}">
|
||||
{% if 'api_access' in tier.features %}
|
||||
<svg class="w-4 h-4 text-green-500 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{% else %}
|
||||
<svg class="w-4 h-4 text-gray-300 dark:text-gray-600 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{% endif %}
|
||||
{{ _("platform.pricing.api_access") }}
|
||||
</li>
|
||||
{# Multi-channel Integration - Enterprise only #}
|
||||
<li class="flex items-center {% if tier.is_enterprise %}text-gray-700 dark:text-gray-300{% else %}text-gray-400 dark:text-gray-600{% endif %}">
|
||||
{% if tier.is_enterprise %}
|
||||
<svg class="w-4 h-4 text-green-500 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{% else %}
|
||||
<svg class="w-4 h-4 text-gray-300 dark:text-gray-600 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
{% endif %}
|
||||
{{ _("platform.pricing.multi_channel") }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{# CTA Button #}
|
||||
{% if tier.is_enterprise %}
|
||||
<a href="mailto:sales@wizamart.com?subject=Enterprise%20Plan%20Inquiry"
|
||||
class="block w-full py-3 px-4 bg-gray-200 dark:bg-gray-700 text-gray-900 dark:text-white font-semibold rounded-xl text-center hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors">
|
||||
{{ _("platform.pricing.contact_sales") }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="/signup?tier={{ tier.code }}"
|
||||
:href="'/signup?tier={{ tier.code }}&annual=' + annual"
|
||||
class="block w-full py-3 px-4 font-semibold rounded-xl text-center transition-colors
|
||||
{% if tier.is_popular %}bg-indigo-600 hover:bg-indigo-700 text-white{% else %}bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 hover:bg-indigo-200 dark:hover:bg-indigo-900/50{% endif %}">
|
||||
{{ _("platform.pricing.start_trial") }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# =========================================================================
|
||||
ADD-ONS SECTION
|
||||
========================================================================= #}
|
||||
<section id="addons" class="py-16 lg:py-24 bg-gray-50 dark:bg-gray-900">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
{# Section Header #}
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
{{ _("platform.addons.title") }}
|
||||
</h2>
|
||||
<p class="text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
{{ _("platform.addons.subtitle") }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{# Add-ons Grid #}
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{% for addon in addons %}
|
||||
<div class="bg-white dark:bg-gray-800 rounded-2xl p-8 border border-gray-200 dark:border-gray-700 hover:shadow-lg transition-shadow">
|
||||
{# Icon #}
|
||||
<div class="w-14 h-14 bg-indigo-100 dark:bg-indigo-900/30 rounded-xl flex items-center justify-center mb-6">
|
||||
{% if addon.icon == 'globe' %}
|
||||
<svg class="w-7 h-7 text-indigo-600 dark:text-indigo-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9"/>
|
||||
</svg>
|
||||
{% elif addon.icon == 'shield-check' %}
|
||||
<svg class="w-7 h-7 text-indigo-600 dark:text-indigo-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
|
||||
</svg>
|
||||
{% elif addon.icon == 'mail' %}
|
||||
<svg class="w-7 h-7 text-indigo-600 dark:text-indigo-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Name & Description #}
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-2">{{ addon.name }}</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-4">{{ addon.description }}</p>
|
||||
|
||||
{# Price #}
|
||||
<div class="flex items-baseline">
|
||||
<span class="text-2xl font-bold text-gray-900 dark:text-white">{{ addon.price }}€</span>
|
||||
<span class="text-gray-500 dark:text-gray-400 ml-1">/{{ addon.billing_period }}</span>
|
||||
</div>
|
||||
|
||||
{# Options for email packages #}
|
||||
{% if addon.options %}
|
||||
<div class="mt-4 space-y-2">
|
||||
{% for opt in addon.options %}
|
||||
<div class="text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ opt.quantity }} addresses: {{ opt.price }}€/month
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# =========================================================================
|
||||
LETZSHOP VENDOR FINDER
|
||||
========================================================================= #}
|
||||
<section id="find-shop" class="py-16 lg:py-24 bg-white dark:bg-gray-800">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
{# Section Header #}
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
{{ _("platform.find_shop.title") }}
|
||||
</h2>
|
||||
<p class="text-lg text-gray-600 dark:text-gray-400">
|
||||
{{ _("platform.find_shop.subtitle") }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{# Search Form #}
|
||||
<div class="bg-gray-50 dark:bg-gray-900 rounded-2xl p-8 border border-gray-200 dark:border-gray-700">
|
||||
<div class="flex flex-col sm:flex-row gap-4">
|
||||
<input
|
||||
type="text"
|
||||
x-model="shopUrl"
|
||||
placeholder="{{ _('platform.find_shop.placeholder') }}"
|
||||
class="flex-1 px-4 py-3 rounded-xl border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
|
||||
/>
|
||||
<button
|
||||
@click="lookupVendor()"
|
||||
:disabled="loading"
|
||||
class="px-8 py-3 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold rounded-xl transition-colors disabled:opacity-50 flex items-center justify-center">
|
||||
<template x-if="loading">
|
||||
<svg class="animate-spin w-5 h-5 mr-2" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/>
|
||||
</svg>
|
||||
</template>
|
||||
{{ _("platform.find_shop.button") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{# Result #}
|
||||
<template x-if="vendorResult">
|
||||
<div class="mt-6 p-6 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700">
|
||||
<template x-if="vendorResult.found">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white" x-text="vendorResult.vendor.name"></h3>
|
||||
<a :href="vendorResult.vendor.letzshop_url" target="_blank" class="text-sm text-indigo-600 dark:text-indigo-400 hover:underline" x-text="vendorResult.vendor.letzshop_url"></a>
|
||||
</div>
|
||||
<template x-if="!vendorResult.vendor.is_claimed">
|
||||
<a :href="'/signup?letzshop=' + vendorResult.vendor.slug"
|
||||
class="px-6 py-2 bg-green-600 hover:bg-green-700 text-white font-semibold rounded-lg transition-colors">
|
||||
{{ _("platform.find_shop.claim_shop") }}
|
||||
</a>
|
||||
</template>
|
||||
<template x-if="vendorResult.vendor.is_claimed">
|
||||
<span class="px-4 py-2 bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400 rounded-lg">
|
||||
{{ _("platform.find_shop.already_claimed") }}
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="!vendorResult.found">
|
||||
<div class="text-center text-gray-600 dark:text-gray-400">
|
||||
<p x-text="vendorResult.error || 'Shop not found. Please check your URL and try again.'"></p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
{# Help Text #}
|
||||
<p class="mt-4 text-sm text-gray-500 dark:text-gray-400 text-center">
|
||||
{{ _("platform.find_shop.no_account") }} <a href="https://letzshop.lu" target="_blank" class="text-indigo-600 dark:text-indigo-400 hover:underline">{{ _("platform.find_shop.signup_letzshop") }}</a>{{ _("platform.find_shop.then_connect") }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# =========================================================================
|
||||
FINAL CTA SECTION
|
||||
========================================================================= #}
|
||||
<section class="py-16 lg:py-24 bg-gradient-to-r from-indigo-600 to-purple-600">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-white mb-6">
|
||||
{{ _("platform.cta.title") }}
|
||||
</h2>
|
||||
<p class="text-xl text-indigo-100 mb-10">
|
||||
{{ _("platform.cta.subtitle", trial_days=trial_days) }}
|
||||
</p>
|
||||
<a href="/signup"
|
||||
class="inline-flex items-center px-10 py-4 bg-white text-indigo-600 font-bold rounded-xl shadow-lg hover:shadow-xl transition-all hover:scale-105">
|
||||
{{ _("platform.cta.button") }}
|
||||
<svg class="w-5 h-5 ml-2" 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"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script>
|
||||
function homepageData() {
|
||||
return {
|
||||
annual: false,
|
||||
shopUrl: '',
|
||||
vendorResult: null,
|
||||
loading: false,
|
||||
|
||||
async lookupVendor() {
|
||||
if (!this.shopUrl.trim()) return;
|
||||
|
||||
this.loading = true;
|
||||
this.vendorResult = null;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/v1/public/letzshop-vendors/lookup', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ url: this.shopUrl })
|
||||
});
|
||||
|
||||
this.vendorResult = await response.json();
|
||||
} catch (error) {
|
||||
console.error('Lookup error:', error);
|
||||
this.vendorResult = { found: false, error: 'Failed to lookup. Please try again.' };
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
54
app/modules/cms/templates/cms/public/sections/_cta.html
Normal file
54
app/modules/cms/templates/cms/public/sections/_cta.html
Normal file
@@ -0,0 +1,54 @@
|
||||
{# app/templates/platform/sections/_cta.html #}
|
||||
{# Call-to-action section partial with multi-language support #}
|
||||
{#
|
||||
Parameters:
|
||||
- cta: CTASection object (or dict)
|
||||
- lang: Current language code
|
||||
- default_lang: Fallback language
|
||||
#}
|
||||
|
||||
{% macro render_cta(cta, lang, default_lang) %}
|
||||
{% if cta and cta.enabled %}
|
||||
<section class="py-16 lg:py-24 {% if cta.background_type == 'gradient' %}bg-gradient-to-r from-indigo-600 to-purple-600{% else %}bg-indigo-600{% endif %}">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
{# Title #}
|
||||
{% set title = cta.title.translations.get(lang) or cta.title.translations.get(default_lang) or '' %}
|
||||
{% if title %}
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-white mb-6">
|
||||
{{ title }}
|
||||
</h2>
|
||||
{% endif %}
|
||||
|
||||
{# Subtitle #}
|
||||
{% if cta.subtitle and cta.subtitle.translations %}
|
||||
{% set subtitle = cta.subtitle.translations.get(lang) or cta.subtitle.translations.get(default_lang) %}
|
||||
{% if subtitle %}
|
||||
<p class="text-xl text-indigo-100 mb-10 max-w-2xl mx-auto">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{# Buttons #}
|
||||
{% if cta.buttons %}
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
||||
{% for button in cta.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-indigo-600 hover:bg-gray-100{% elif button.style == 'secondary' %}bg-indigo-500 text-white hover:bg-indigo-400{% else %}border-2 border-white text-white hover:bg-white/10{% endif %} px-10 py-4 rounded-xl font-bold 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>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
72
app/modules/cms/templates/cms/public/sections/_features.html
Normal file
72
app/modules/cms/templates/cms/public/sections/_features.html
Normal file
@@ -0,0 +1,72 @@
|
||||
{# app/templates/platform/sections/_features.html #}
|
||||
{# Features section partial with multi-language support #}
|
||||
{#
|
||||
Parameters:
|
||||
- features: FeaturesSection object (or dict)
|
||||
- lang: Current language code
|
||||
- default_lang: Fallback language
|
||||
#}
|
||||
|
||||
{% macro render_features(features, lang, default_lang) %}
|
||||
{% if features and features.enabled %}
|
||||
<section class="py-16 lg:py-24 bg-white dark:bg-gray-800">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
{# Section header #}
|
||||
<div class="text-center mb-12">
|
||||
{% set title = features.title.translations.get(lang) or features.title.translations.get(default_lang) or '' %}
|
||||
{% if title %}
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
{{ title }}
|
||||
</h2>
|
||||
{% endif %}
|
||||
|
||||
{% if features.subtitle and features.subtitle.translations %}
|
||||
{% set subtitle = features.subtitle.translations.get(lang) or features.subtitle.translations.get(default_lang) %}
|
||||
{% if subtitle %}
|
||||
<p class="text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Feature cards #}
|
||||
{% if features.features %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-{{ [features.features|length, 4]|min }} gap-8">
|
||||
{% for feature in features.features %}
|
||||
<div class="card-hover bg-gray-50 dark:bg-gray-700 rounded-xl p-8 text-center">
|
||||
{# Icon #}
|
||||
{% if feature.icon %}
|
||||
<div class="w-16 h-16 mx-auto mb-4 rounded-full gradient-primary flex items-center justify-center">
|
||||
{# Support for icon names - rendered via Alpine $icon helper or direct SVG #}
|
||||
{% if feature.icon.startswith('<svg') %}
|
||||
{{ feature.icon | safe }}
|
||||
{% else %}
|
||||
<span x-html="typeof $icon !== 'undefined' ? $icon('{{ feature.icon }}', 'w-8 h-8 text-white') : ''"></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Title #}
|
||||
{% set feature_title = feature.title.translations.get(lang) or feature.title.translations.get(default_lang) or '' %}
|
||||
{% if feature_title %}
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">
|
||||
{{ feature_title }}
|
||||
</h3>
|
||||
{% endif %}
|
||||
|
||||
{# Description #}
|
||||
{% set feature_desc = feature.description.translations.get(lang) or feature.description.translations.get(default_lang) or '' %}
|
||||
{% if feature_desc %}
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
{{ feature_desc }}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
71
app/modules/cms/templates/cms/public/sections/_hero.html
Normal file
71
app/modules/cms/templates/cms/public/sections/_hero.html
Normal file
@@ -0,0 +1,71 @@
|
||||
{# app/templates/platform/sections/_hero.html #}
|
||||
{# Hero section partial with multi-language support #}
|
||||
{#
|
||||
Parameters:
|
||||
- hero: HeroSection object (or dict)
|
||||
- lang: Current language code (passed from parent template)
|
||||
- default_lang: Fallback language (passed from parent template)
|
||||
#}
|
||||
|
||||
{% 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 %}
|
||||
116
app/modules/cms/templates/cms/public/sections/_pricing.html
Normal file
116
app/modules/cms/templates/cms/public/sections/_pricing.html
Normal file
@@ -0,0 +1,116 @@
|
||||
{# app/templates/platform/sections/_pricing.html #}
|
||||
{# Pricing section partial with multi-language support #}
|
||||
{#
|
||||
Parameters:
|
||||
- pricing: PricingSection object (or dict)
|
||||
- lang: Current language code
|
||||
- default_lang: Fallback language
|
||||
- tiers: List of subscription tiers from DB (passed via context)
|
||||
#}
|
||||
|
||||
{% macro render_pricing(pricing, lang, default_lang, tiers) %}
|
||||
{% if pricing and pricing.enabled %}
|
||||
<section id="pricing" class="py-16 lg:py-24 bg-gray-50 dark:bg-gray-900">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
{# Section header #}
|
||||
<div class="text-center mb-12">
|
||||
{% set title = pricing.title.translations.get(lang) or pricing.title.translations.get(default_lang) or '' %}
|
||||
{% if title %}
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
{{ title }}
|
||||
</h2>
|
||||
{% endif %}
|
||||
|
||||
{% if pricing.subtitle and pricing.subtitle.translations %}
|
||||
{% set subtitle = pricing.subtitle.translations.get(lang) or pricing.subtitle.translations.get(default_lang) %}
|
||||
{% if subtitle %}
|
||||
<p class="text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Pricing toggle (monthly/annual) #}
|
||||
{% if pricing.use_subscription_tiers and tiers %}
|
||||
<div x-data="{ annual: false }" class="space-y-8">
|
||||
{# Billing toggle #}
|
||||
<div class="flex justify-center items-center space-x-4">
|
||||
<span :class="annual ? 'text-gray-400' : 'text-gray-900 dark:text-white font-semibold'">
|
||||
{{ _('pricing.monthly') or 'Monthly' }}
|
||||
</span>
|
||||
<button @click="annual = !annual"
|
||||
class="relative w-14 h-7 bg-gray-200 dark:bg-gray-700 rounded-full transition-colors"
|
||||
:class="annual && 'bg-indigo-600 dark:bg-indigo-500'">
|
||||
<span class="absolute top-1 left-1 w-5 h-5 bg-white rounded-full shadow transition-transform"
|
||||
:class="annual && 'translate-x-7'"></span>
|
||||
</button>
|
||||
<span :class="!annual ? 'text-gray-400' : 'text-gray-900 dark:text-white font-semibold'">
|
||||
{{ _('pricing.annual') or 'Annual' }}
|
||||
<span class="text-green-500 text-sm ml-1">{{ _('pricing.save_months') or 'Save 2 months!' }}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{# Pricing cards #}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-{{ [tiers|length, 4]|min }} gap-6">
|
||||
{% for tier in tiers %}
|
||||
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-sm hover:shadow-lg transition-shadow p-8 {% if tier.is_popular %}ring-2 ring-indigo-500 relative{% endif %}">
|
||||
{% if tier.is_popular %}
|
||||
<div class="absolute -top-4 left-1/2 -translate-x-1/2">
|
||||
<span class="bg-indigo-500 text-white text-sm font-semibold px-4 py-1 rounded-full">
|
||||
{{ _('pricing.most_popular') or 'Most Popular' }}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="text-center">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-2">
|
||||
{{ tier.name }}
|
||||
</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-sm mb-4">
|
||||
{{ tier.description or '' }}
|
||||
</p>
|
||||
|
||||
{# Price #}
|
||||
<div class="mb-6">
|
||||
<span class="text-4xl font-extrabold text-gray-900 dark:text-white"
|
||||
x-text="annual ? '{{ tier.price_annual or (tier.price_monthly * 10)|int }}' : '{{ tier.price_monthly }}'">
|
||||
{{ tier.price_monthly }}
|
||||
</span>
|
||||
<span class="text-gray-500 dark:text-gray-400">/{{ _('pricing.month') or 'mo' }}</span>
|
||||
</div>
|
||||
|
||||
{# CTA button #}
|
||||
<a href="/signup?tier={{ tier.code }}"
|
||||
class="block w-full py-3 px-6 rounded-xl font-semibold transition {% if tier.is_popular %}bg-indigo-600 text-white hover:bg-indigo-700{% else %}bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-gray-200 dark:hover:bg-gray-600{% endif %}">
|
||||
{{ _('pricing.get_started') or 'Get Started' }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{# Features list #}
|
||||
{% if tier.features %}
|
||||
<ul class="mt-8 space-y-3">
|
||||
{% for feature in tier.features %}
|
||||
<li class="flex items-start">
|
||||
<svg class="w-5 h-5 text-green-500 mr-3 mt-0.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span class="text-gray-600 dark:text-gray-400 text-sm">{{ feature }}</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{# Placeholder when no tiers available #}
|
||||
<div class="text-center text-gray-500 dark:text-gray-400 py-8">
|
||||
{{ _('pricing.coming_soon') or 'Pricing plans coming soon' }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
79
app/modules/cms/templates/cms/storefront/content-page.html
Normal file
79
app/modules/cms/templates/cms/storefront/content-page.html
Normal file
@@ -0,0 +1,79 @@
|
||||
{# app/templates/storefront/content-page.html #}
|
||||
{# Generic CMS content page template #}
|
||||
{% extends "storefront/base.html" %}
|
||||
|
||||
{# Dynamic title from CMS #}
|
||||
{% block title %}{{ page.title }}{% endblock %}
|
||||
|
||||
{# SEO from CMS #}
|
||||
{% block meta_description %}{{ page.meta_description or page.title }}{% endblock %}
|
||||
{% block meta_keywords %}{{ page.meta_keywords or vendor.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
|
||||
{# Breadcrumbs #}
|
||||
<div class="breadcrumb mb-6">
|
||||
<a href="{{ base_url }}" class="hover:text-primary">Home</a>
|
||||
<span>/</span>
|
||||
<span class="text-gray-900 dark:text-gray-200 font-medium">{{ page.title }}</span>
|
||||
</div>
|
||||
|
||||
{# Page Header #}
|
||||
<div class="mb-8">
|
||||
<h1 class="text-3xl md:text-4xl font-bold text-gray-800 dark:text-gray-200 mb-4">
|
||||
{{ page.title }}
|
||||
</h1>
|
||||
|
||||
{# Optional: Show vendor override badge for debugging #}
|
||||
{% if page.vendor_id %}
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400 mb-4">
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">
|
||||
Custom {{ vendor.name }} version
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Published date (optional) #}
|
||||
{% if page.published_at %}
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Published {{ page.published_at.strftime('%B %d, %Y') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Content #}
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm p-8">
|
||||
<div class="prose prose-lg dark:prose-invert max-w-none">
|
||||
{% if page.content_format == 'markdown' %}
|
||||
{# Markdown content - future enhancement: render with markdown library #}
|
||||
<div class="markdown-content">
|
||||
{{ page.content | safe }}{# sanitized: CMS content #}
|
||||
</div>
|
||||
{% else %}
|
||||
{# HTML content (default) #}
|
||||
{{ page.content | safe }}{# sanitized: CMS content #}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Last updated timestamp #}
|
||||
{% if page.updated_at %}
|
||||
<div class="mt-8 text-center text-sm text-gray-500 dark:text-gray-400">
|
||||
Last updated: {{ page.updated_at.strftime('%B %d, %Y') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script>
|
||||
// Future enhancement: Add any CMS-specific JavaScript here
|
||||
// For example:
|
||||
// - Table of contents generation
|
||||
// - Anchor link handling
|
||||
// - Image lightbox
|
||||
// - Copy code blocks
|
||||
</script>
|
||||
{% endblock %}
|
||||
126
app/modules/cms/templates/cms/storefront/landing-default.html
Normal file
126
app/modules/cms/templates/cms/storefront/landing-default.html
Normal file
@@ -0,0 +1,126 @@
|
||||
{# app/templates/vendor/landing-default.html #}
|
||||
{# standalone #}
|
||||
{# Default/Minimal Landing Page Template #}
|
||||
{% extends "shop/base.html" %}
|
||||
|
||||
{% block title %}{{ vendor.name }}{% endblock %}
|
||||
{% block meta_description %}{{ page.meta_description or vendor.description or vendor.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="min-h-screen">
|
||||
|
||||
{# Hero Section - Simple and Clean #}
|
||||
<section class="relative bg-gradient-to-br from-primary/10 to-primary/5 dark:from-primary/20 dark:to-primary/10 py-20">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="text-center">
|
||||
{# Logo #}
|
||||
{% if theme.branding.logo %}
|
||||
<div class="mb-8">
|
||||
<img src="{{ theme.branding.logo }}"
|
||||
alt="{{ vendor.name }}"
|
||||
class="h-20 w-auto mx-auto">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Title #}
|
||||
<h1 class="text-4xl md:text-6xl font-bold text-gray-900 dark:text-white mb-6">
|
||||
{{ page.title or vendor.name }}
|
||||
</h1>
|
||||
|
||||
{# Tagline #}
|
||||
{% if vendor.tagline %}
|
||||
<p class="text-xl md:text-2xl text-gray-600 dark:text-gray-300 mb-8 max-w-3xl mx-auto">
|
||||
{{ vendor.tagline }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{# CTA Button #}
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<a href="{{ base_url }}shop/"
|
||||
class="inline-flex items-center justify-center px-8 py-4 text-lg font-semibold rounded-lg text-white bg-primary hover:bg-primary-dark transition-colors shadow-lg hover:shadow-xl"
|
||||
style="background-color: var(--color-primary)">
|
||||
Browse Our Shop
|
||||
<span class="w-5 h-5 ml-2" x-html="$icon('arrow-right', 'w-5 h-5')"></span>
|
||||
</a>
|
||||
{% if page.content %}
|
||||
<a href="#about"
|
||||
class="inline-flex items-center justify-center px-8 py-4 text-lg font-semibold rounded-lg text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors border-2 border-gray-200 dark:border-gray-600">
|
||||
Learn More
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# Content Section (if provided) #}
|
||||
{% if page.content %}
|
||||
<section id="about" class="py-16 bg-white dark:bg-gray-900">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="prose prose-lg dark:prose-invert max-w-none">
|
||||
{{ page.content | safe }}{# sanitized: CMS content #}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{# Quick Links Section #}
|
||||
<section class="py-16 bg-gray-50 dark:bg-gray-800">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<h2 class="text-3xl font-bold text-center text-gray-900 dark:text-white mb-12">
|
||||
Explore
|
||||
</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<a href="{{ base_url }}shop/products"
|
||||
class="block p-8 bg-white dark:bg-gray-900 rounded-lg shadow-md hover:shadow-xl transition-shadow text-center group">
|
||||
<div class="text-4xl mb-4">🛍️</div>
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2 group-hover:text-primary">
|
||||
Shop Products
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Browse our complete catalog
|
||||
</p>
|
||||
</a>
|
||||
|
||||
{% if header_pages %}
|
||||
{% for page in header_pages[:2] %}
|
||||
<a href="{{ base_url }}shop/{{ page.slug }}"
|
||||
class="block p-8 bg-white dark:bg-gray-900 rounded-lg shadow-md hover:shadow-xl transition-shadow text-center group">
|
||||
<div class="text-4xl mb-4">📄</div>
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2 group-hover:text-primary">
|
||||
{{ page.title }}
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
{{ page.meta_description or 'Learn more' }}
|
||||
</p>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<a href="{{ base_url }}shop/about"
|
||||
class="block p-8 bg-white dark:bg-gray-900 rounded-lg shadow-md hover:shadow-xl transition-shadow text-center group">
|
||||
<div class="text-4xl mb-4">ℹ️</div>
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2 group-hover:text-primary">
|
||||
About Us
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Learn about our story
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a href="{{ base_url }}shop/contact"
|
||||
class="block p-8 bg-white dark:bg-gray-900 rounded-lg shadow-md hover:shadow-xl transition-shadow text-center group">
|
||||
<div class="text-4xl mb-4">📧</div>
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2 group-hover:text-primary">
|
||||
Contact
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Get in touch with us
|
||||
</p>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
258
app/modules/cms/templates/cms/storefront/landing-full.html
Normal file
258
app/modules/cms/templates/cms/storefront/landing-full.html
Normal file
@@ -0,0 +1,258 @@
|
||||
{# app/templates/vendor/landing-full.html #}
|
||||
{# standalone #}
|
||||
{# Full Landing Page Template - Maximum Features #}
|
||||
{% extends "shop/base.html" %}
|
||||
|
||||
{% block title %}{{ vendor.name }}{% endblock %}
|
||||
{% block meta_description %}{{ page.meta_description or vendor.description or vendor.name }}{% endblock %}
|
||||
|
||||
{# Alpine.js component #}
|
||||
{% block alpine_data %}shopLayoutData(){% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="min-h-screen">
|
||||
|
||||
{# Hero Section - Split Design #}
|
||||
<section class="relative overflow-hidden bg-gradient-to-br from-primary/10 to-accent/5 dark:from-primary/20 dark:to-accent/10">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center min-h-screen">
|
||||
{# Left - Content #}
|
||||
<div class="px-4 sm:px-6 lg:px-8 py-20">
|
||||
{% if theme.branding.logo %}
|
||||
<div class="mb-8">
|
||||
<img src="{{ theme.branding.logo }}"
|
||||
alt="{{ vendor.name }}"
|
||||
class="h-16 w-auto">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h1 class="text-4xl md:text-6xl font-bold text-gray-900 dark:text-white mb-6 leading-tight">
|
||||
{{ page.title or vendor.name }}
|
||||
</h1>
|
||||
|
||||
{% if vendor.tagline %}
|
||||
<p class="text-xl md:text-2xl text-gray-600 dark:text-gray-300 mb-8">
|
||||
{{ vendor.tagline }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if vendor.description %}
|
||||
<p class="text-lg text-gray-600 dark:text-gray-400 mb-10">
|
||||
{{ vendor.description }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-4">
|
||||
<a href="{{ base_url }}shop/"
|
||||
class="inline-flex items-center justify-center px-8 py-4 text-lg font-semibold rounded-lg text-white bg-primary hover:bg-primary-dark transition-colors shadow-lg"
|
||||
style="background-color: var(--color-primary)">
|
||||
Shop Now
|
||||
<span class="w-5 h-5 ml-2" x-html="$icon('arrow-right', 'w-5 h-5')"></span>
|
||||
</a>
|
||||
<a href="#about"
|
||||
class="inline-flex items-center justify-center px-8 py-4 text-lg font-semibold rounded-lg text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors border-2 border-gray-200 dark:border-gray-600">
|
||||
Learn More
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{# Stats/Badges #}
|
||||
<div class="grid grid-cols-3 gap-8 mt-16 pt-10 border-t border-gray-200 dark:border-gray-700">
|
||||
<div>
|
||||
<div class="text-3xl font-bold text-primary mb-2" style="color: var(--color-primary)">100+</div>
|
||||
<div class="text-sm text-gray-600 dark:text-gray-400">Products</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-3xl font-bold text-primary mb-2" style="color: var(--color-primary)">24/7</div>
|
||||
<div class="text-sm text-gray-600 dark:text-gray-400">Support</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-3xl font-bold text-primary mb-2" style="color: var(--color-primary)">⭐⭐⭐⭐⭐</div>
|
||||
<div class="text-sm text-gray-600 dark:text-gray-400">Rated</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Right - Visual #}
|
||||
<div class="hidden lg:flex items-center justify-center p-12">
|
||||
<div class="relative w-full max-w-lg">
|
||||
{# Decorative Circles #}
|
||||
<div class="absolute top-0 -left-4 w-72 h-72 bg-primary rounded-full mix-blend-multiply filter blur-3xl opacity-20 animate-pulse"></div>
|
||||
<div class="absolute -bottom-8 -right-4 w-72 h-72 bg-accent rounded-full mix-blend-multiply filter blur-3xl opacity-20 animate-pulse" style="animation-delay: 1s;"></div>
|
||||
|
||||
{# Image placeholder or icon #}
|
||||
<div class="relative z-10 bg-white dark:bg-gray-800 rounded-3xl shadow-2xl p-12 text-center">
|
||||
<div class="text-9xl mb-4">🛍️</div>
|
||||
<p class="text-2xl font-semibold text-gray-700 dark:text-gray-200">
|
||||
Your Shopping Destination
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# Features Grid #}
|
||||
<section class="py-24 bg-white dark:bg-gray-900">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="text-center mb-16">
|
||||
<h2 class="text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
What We Offer
|
||||
</h2>
|
||||
<p class="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
Everything you need for an exceptional shopping experience
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
<div class="p-6 rounded-xl bg-gray-50 dark:bg-gray-800 hover:shadow-lg transition-shadow">
|
||||
<div class="w-12 h-12 rounded-lg bg-primary/10 flex items-center justify-center mb-4" style="color: var(--color-primary)">
|
||||
<span class="w-6 h-6" x-html="$icon('check', 'w-6 h-6')"></span>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Premium Quality
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Top-tier products carefully selected for you
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="p-6 rounded-xl bg-gray-50 dark:bg-gray-800 hover:shadow-lg transition-shadow">
|
||||
<div class="w-12 h-12 rounded-lg bg-accent/10 flex items-center justify-center mb-4" style="color: var(--color-accent)">
|
||||
<span class="w-6 h-6" x-html="$icon('bolt', 'w-6 h-6')"></span>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Fast Shipping
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Quick delivery right to your door
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="p-6 rounded-xl bg-gray-50 dark:bg-gray-800 hover:shadow-lg transition-shadow">
|
||||
<div class="w-12 h-12 rounded-lg bg-primary/10 flex items-center justify-center mb-4" style="color: var(--color-primary)">
|
||||
<span class="w-6 h-6" x-html="$icon('currency-dollar', 'w-6 h-6')"></span>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Best Value
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Competitive prices and great deals
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="p-6 rounded-xl bg-gray-50 dark:bg-gray-800 hover:shadow-lg transition-shadow">
|
||||
<div class="w-12 h-12 rounded-lg bg-accent/10 flex items-center justify-center mb-4" style="color: var(--color-accent)">
|
||||
<span class="w-6 h-6" x-html="$icon('user-plus', 'w-6 h-6')"></span>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||
24/7 Support
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Always here to help you
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# About Section (with content) #}
|
||||
{% if page.content %}
|
||||
<section id="about" class="py-24 bg-gray-50 dark:bg-gray-800">
|
||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="prose prose-xl dark:prose-invert max-w-none">
|
||||
{{ page.content | safe }}{# sanitized: CMS content #}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{# Quick Navigation #}
|
||||
<section class="py-24 bg-white dark:bg-gray-900">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<h2 class="text-3xl font-bold text-center text-gray-900 dark:text-white mb-12">
|
||||
Explore More
|
||||
</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<a href="{{ base_url }}shop/products"
|
||||
class="group relative overflow-hidden rounded-2xl bg-gradient-to-br from-primary/10 to-primary/5 dark:from-primary/20 dark:to-primary/10 p-8 hover:shadow-xl transition-all">
|
||||
<div class="relative z-10">
|
||||
<div class="text-5xl mb-4">🛍️</div>
|
||||
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-2 group-hover:text-primary transition-colors">
|
||||
Shop Products
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Browse our complete collection
|
||||
</p>
|
||||
</div>
|
||||
<div class="absolute inset-0 bg-primary opacity-0 group-hover:opacity-5 transition-opacity"></div>
|
||||
</a>
|
||||
|
||||
{% if header_pages %}
|
||||
{% for page in header_pages[:2] %}
|
||||
<a href="{{ base_url }}shop/{{ page.slug }}"
|
||||
class="group relative overflow-hidden rounded-2xl bg-gradient-to-br from-accent/10 to-accent/5 dark:from-accent/20 dark:to-accent/10 p-8 hover:shadow-xl transition-all">
|
||||
<div class="relative z-10">
|
||||
<div class="text-5xl mb-4">📄</div>
|
||||
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-2 group-hover:text-accent transition-colors">
|
||||
{{ page.title }}
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
{{ page.meta_description or 'Learn more about us' }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="absolute inset-0 bg-accent opacity-0 group-hover:opacity-5 transition-opacity"></div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<a href="{{ base_url }}shop/about"
|
||||
class="group relative overflow-hidden rounded-2xl bg-gradient-to-br from-accent/10 to-accent/5 dark:from-accent/20 dark:to-accent/10 p-8 hover:shadow-xl transition-all">
|
||||
<div class="relative z-10">
|
||||
<div class="text-5xl mb-4">ℹ️</div>
|
||||
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-2 group-hover:text-accent transition-colors">
|
||||
About Us
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Learn about our story and mission
|
||||
</p>
|
||||
</div>
|
||||
<div class="absolute inset-0 bg-accent opacity-0 group-hover:opacity-5 transition-opacity"></div>
|
||||
</a>
|
||||
|
||||
<a href="{{ base_url }}shop/contact"
|
||||
class="group relative overflow-hidden rounded-2xl bg-gradient-to-br from-primary/10 to-primary/5 dark:from-primary/20 dark:to-primary/10 p-8 hover:shadow-xl transition-all">
|
||||
<div class="relative z-10">
|
||||
<div class="text-5xl mb-4">📧</div>
|
||||
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-2 group-hover:text-primary transition-colors">
|
||||
Contact Us
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Get in touch with our team
|
||||
</p>
|
||||
</div>
|
||||
<div class="absolute inset-0 bg-primary opacity-0 group-hover:opacity-5 transition-opacity"></div>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# Final CTA #}
|
||||
<section class="py-24 bg-gradient-to-r from-primary to-accent text-white">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<h2 class="text-4xl md:text-5xl font-bold mb-6">
|
||||
Ready to Start Shopping?
|
||||
</h2>
|
||||
<p class="text-xl mb-10 opacity-90">
|
||||
Join thousands of satisfied customers today
|
||||
</p>
|
||||
<a href="{{ base_url }}shop/products"
|
||||
class="inline-flex items-center justify-center px-10 py-5 text-lg font-bold rounded-xl text-primary bg-white hover:bg-gray-50 transition-all transform hover:scale-105 shadow-2xl">
|
||||
View All Products
|
||||
<span class="w-5 h-5 ml-2" x-html="$icon('arrow-right', 'w-5 h-5')"></span>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,66 @@
|
||||
{# app/templates/vendor/landing-minimal.html #}
|
||||
{# standalone #}
|
||||
{# Minimal Landing Page Template - Ultra Clean #}
|
||||
{% extends "shop/base.html" %}
|
||||
|
||||
{% block title %}{{ vendor.name }}{% endblock %}
|
||||
{% block meta_description %}{{ page.meta_description or vendor.description or vendor.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="min-h-screen flex items-center justify-center bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800">
|
||||
<div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 text-center py-20">
|
||||
|
||||
{# Logo #}
|
||||
{% if theme.branding.logo %}
|
||||
<div class="mb-12">
|
||||
<img src="{{ theme.branding.logo }}"
|
||||
alt="{{ vendor.name }}"
|
||||
class="h-24 w-auto mx-auto">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Title #}
|
||||
<h1 class="text-5xl md:text-7xl font-bold text-gray-900 dark:text-white mb-8">
|
||||
{{ page.title or vendor.name }}
|
||||
</h1>
|
||||
|
||||
{# Description/Content #}
|
||||
{% if page.content %}
|
||||
<div class="prose prose-lg dark:prose-invert max-w-2xl mx-auto mb-12 text-gray-600 dark:text-gray-300">
|
||||
{{ page.content | safe }}{# sanitized: CMS content #}
|
||||
</div>
|
||||
{% elif vendor.description %}
|
||||
<p class="text-xl md:text-2xl text-gray-600 dark:text-gray-300 mb-12 max-w-2xl mx-auto">
|
||||
{{ vendor.description }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{# Single CTA #}
|
||||
<div>
|
||||
<a href="{{ base_url }}shop/"
|
||||
class="inline-flex items-center justify-center px-10 py-5 text-xl font-semibold rounded-full text-white bg-primary hover:bg-primary-dark transition-all transform hover:scale-105 shadow-2xl"
|
||||
style="background-color: var(--color-primary)">
|
||||
Enter Shop
|
||||
<span class="w-6 h-6 ml-3" x-html="$icon('arrow-right', 'w-6 h-6')"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{# Optional Links Below #}
|
||||
{% if header_pages or footer_pages %}
|
||||
<div class="mt-16 pt-8 border-t border-gray-200 dark:border-gray-700">
|
||||
<div class="flex flex-wrap justify-center gap-6 text-sm">
|
||||
<a href="{{ base_url }}shop/products" class="text-gray-600 dark:text-gray-400 hover:text-primary transition-colors">
|
||||
Products
|
||||
</a>
|
||||
{% for page in (header_pages or footer_pages)[:4] %}
|
||||
<a href="{{ base_url }}shop/{{ page.slug }}" class="text-gray-600 dark:text-gray-400 hover:text-primary transition-colors">
|
||||
{{ page.title }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
194
app/modules/cms/templates/cms/storefront/landing-modern.html
Normal file
194
app/modules/cms/templates/cms/storefront/landing-modern.html
Normal file
@@ -0,0 +1,194 @@
|
||||
{# app/templates/vendor/landing-modern.html #}
|
||||
{# standalone #}
|
||||
{# Modern Landing Page Template - Feature Rich #}
|
||||
{% extends "shop/base.html" %}
|
||||
|
||||
{% block title %}{{ vendor.name }}{% endblock %}
|
||||
{% block meta_description %}{{ page.meta_description or vendor.description or vendor.name }}{% endblock %}
|
||||
|
||||
{# Alpine.js component #}
|
||||
{% block alpine_data %}shopLayoutData(){% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="min-h-screen">
|
||||
|
||||
{# Hero Section - Full Width with Overlay #}
|
||||
<section class="relative h-screen flex items-center justify-center bg-gradient-to-br from-primary/20 via-accent/10 to-primary/20 dark:from-primary/30 dark:via-accent/20 dark:to-primary/30">
|
||||
<div class="absolute inset-0 bg-grid-pattern opacity-5"></div>
|
||||
|
||||
<div class="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
{# Logo #}
|
||||
{% if theme.branding.logo %}
|
||||
<div class="mb-8 animate-fade-in">
|
||||
<img src="{{ theme.branding.logo }}"
|
||||
alt="{{ vendor.name }}"
|
||||
class="h-24 w-auto mx-auto">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Main Heading #}
|
||||
<h1 class="text-5xl md:text-7xl font-bold text-gray-900 dark:text-white mb-6 animate-slide-up">
|
||||
{{ page.title or vendor.name }}
|
||||
</h1>
|
||||
|
||||
{# Tagline #}
|
||||
{% if vendor.tagline %}
|
||||
<p class="text-xl md:text-3xl text-gray-700 dark:text-gray-200 mb-12 max-w-4xl mx-auto animate-slide-up animation-delay-200">
|
||||
{{ vendor.tagline }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{# CTAs #}
|
||||
<div class="flex flex-col sm:flex-row gap-6 justify-center animate-fade-in animation-delay-400">
|
||||
<a href="{{ base_url }}shop/"
|
||||
class="group inline-flex items-center justify-center px-10 py-5 text-lg font-bold rounded-xl text-white bg-primary hover:bg-primary-dark transition-all transform hover:scale-105 shadow-2xl hover:shadow-3xl"
|
||||
style="background-color: var(--color-primary)">
|
||||
<span>Start Shopping</span>
|
||||
<span class="w-5 h-5 ml-2 group-hover:translate-x-1 transition-transform" x-html="$icon('arrow-right', 'w-5 h-5')"></span>
|
||||
</a>
|
||||
<a href="#features"
|
||||
class="inline-flex items-center justify-center px-10 py-5 text-lg font-bold rounded-xl text-gray-700 dark:text-gray-200 bg-white/90 dark:bg-gray-800/90 backdrop-blur hover:bg-white dark:hover:bg-gray-800 transition-all border-2 border-gray-200 dark:border-gray-600">
|
||||
Discover More
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{# Scroll Indicator #}
|
||||
<div class="absolute bottom-10 left-1/2 transform -translate-x-1/2 animate-bounce">
|
||||
<span class="w-6 h-6 text-gray-400" x-html="$icon('arrow-down', 'w-6 h-6')"></span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# Features Section #}
|
||||
<section id="features" class="py-24 bg-white dark:bg-gray-900">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="text-center mb-16">
|
||||
<h2 class="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Why Choose Us
|
||||
</h2>
|
||||
<p class="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
{% if vendor.description %}{{ vendor.description }}{% else %}Experience excellence in every purchase{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-12">
|
||||
{# Feature 1 #}
|
||||
<div class="text-center group">
|
||||
<div class="inline-flex items-center justify-center w-20 h-20 rounded-full bg-primary/10 text-primary mb-6 group-hover:scale-110 transition-transform"
|
||||
style="color: var(--color-primary)">
|
||||
<span class="w-10 h-10" x-html="$icon('check', 'w-10 h-10')"></span>
|
||||
</div>
|
||||
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Quality Products
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Carefully curated selection of premium items
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{# Feature 2 #}
|
||||
<div class="text-center group">
|
||||
<div class="inline-flex items-center justify-center w-20 h-20 rounded-full bg-accent/10 text-accent mb-6 group-hover:scale-110 transition-transform"
|
||||
style="color: var(--color-accent)">
|
||||
<span class="w-10 h-10" x-html="$icon('bolt', 'w-10 h-10')"></span>
|
||||
</div>
|
||||
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Fast Delivery
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Quick and reliable shipping to your doorstep
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{# Feature 3 #}
|
||||
<div class="text-center group">
|
||||
<div class="inline-flex items-center justify-center w-20 h-20 rounded-full bg-primary/10 text-primary mb-6 group-hover:scale-110 transition-transform"
|
||||
style="color: var(--color-primary)">
|
||||
<span class="w-10 h-10" x-html="$icon('currency-dollar', 'w-10 h-10')"></span>
|
||||
</div>
|
||||
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Best Prices
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
Competitive pricing with great value
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# Content Section (if provided) #}
|
||||
{% if page.content %}
|
||||
<section class="py-24 bg-gray-50 dark:bg-gray-800">
|
||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="prose prose-xl dark:prose-invert max-w-none">
|
||||
{{ page.content | safe }}{# sanitized: CMS content #}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{# CTA Section #}
|
||||
<section class="py-24 bg-gradient-to-r from-primary to-accent text-white">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<h2 class="text-4xl md:text-5xl font-bold mb-6">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<p class="text-xl mb-10 opacity-90">
|
||||
Explore our collection and find what you're looking for
|
||||
</p>
|
||||
<a href="{{ base_url }}shop/products"
|
||||
class="inline-flex items-center justify-center px-10 py-5 text-lg font-bold rounded-xl text-primary bg-white hover:bg-gray-50 transition-all transform hover:scale-105 shadow-2xl">
|
||||
Browse Products
|
||||
<span class="w-5 h-5 ml-2" x-html="$icon('chevron-right', 'w-5 h-5')"></span>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Animation utilities */
|
||||
@keyframes fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes slide-up {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-fade-in {
|
||||
animation: fade-in 1s ease-out;
|
||||
}
|
||||
|
||||
.animate-slide-up {
|
||||
animation: slide-up 0.8s ease-out;
|
||||
}
|
||||
|
||||
.animation-delay-200 {
|
||||
animation-delay: 0.2s;
|
||||
animation-fill-mode: backwards;
|
||||
}
|
||||
|
||||
.animation-delay-400 {
|
||||
animation-delay: 0.4s;
|
||||
animation-fill-mode: backwards;
|
||||
}
|
||||
|
||||
/* Grid pattern */
|
||||
.bg-grid-pattern {
|
||||
background-image:
|
||||
linear-gradient(to right, currentColor 1px, transparent 1px),
|
||||
linear-gradient(to bottom, currentColor 1px, transparent 1px);
|
||||
background-size: 40px 40px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
445
app/modules/cms/templates/cms/vendor/media.html
vendored
Normal file
445
app/modules/cms/templates/cms/vendor/media.html
vendored
Normal file
@@ -0,0 +1,445 @@
|
||||
{# app/templates/vendor/media.html #}
|
||||
{% extends "vendor/base.html" %}
|
||||
{% from 'shared/macros/pagination.html' import pagination %}
|
||||
{% from 'shared/macros/headers.html' import page_header_flex, refresh_button %}
|
||||
{% from 'shared/macros/alerts.html' import loading_state, error_state %}
|
||||
{% from 'shared/macros/modals.html' import modal_simple %}
|
||||
|
||||
{% block title %}Media Library{% endblock %}
|
||||
|
||||
{% block alpine_data %}vendorMedia(){% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Page Header -->
|
||||
{% call page_header_flex(title='Media Library', subtitle='Upload and manage your images, videos, and documents') %}
|
||||
<div class="flex items-center gap-4">
|
||||
{{ refresh_button(loading_var='loading', onclick='loadMedia()', variant='secondary') }}
|
||||
<button
|
||||
@click="showUploadModal = true"
|
||||
class="flex items-center justify-between px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg active:bg-purple-600 hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple"
|
||||
>
|
||||
<span x-html="$icon('upload', 'w-4 h-4 mr-2')"></span>
|
||||
Upload Files
|
||||
</button>
|
||||
</div>
|
||||
{% endcall %}
|
||||
|
||||
{{ loading_state('Loading media library...') }}
|
||||
|
||||
{{ error_state('Error loading media') }}
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<div x-show="!loading" class="grid gap-6 mb-8 md:grid-cols-4">
|
||||
<!-- Total Files -->
|
||||
<div class="flex items-center p-4 bg-white rounded-lg shadow-xs dark:bg-gray-800">
|
||||
<div class="p-3 mr-4 text-blue-500 bg-blue-100 rounded-full dark:text-blue-100 dark:bg-blue-500">
|
||||
<span x-html="$icon('folder', 'w-5 h-5')"></span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">Total Files</p>
|
||||
<p class="text-lg font-semibold text-gray-700 dark:text-gray-200" x-text="stats.total">0</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Images -->
|
||||
<div class="flex items-center p-4 bg-white rounded-lg shadow-xs dark:bg-gray-800">
|
||||
<div class="p-3 mr-4 text-green-500 bg-green-100 rounded-full dark:text-green-100 dark:bg-green-500">
|
||||
<span x-html="$icon('photograph', 'w-5 h-5')"></span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">Images</p>
|
||||
<p class="text-lg font-semibold text-gray-700 dark:text-gray-200" x-text="stats.images">0</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Videos -->
|
||||
<div class="flex items-center p-4 bg-white rounded-lg shadow-xs dark:bg-gray-800">
|
||||
<div class="p-3 mr-4 text-purple-500 bg-purple-100 rounded-full dark:text-purple-100 dark:bg-purple-500">
|
||||
<span x-html="$icon('play', 'w-5 h-5')"></span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">Videos</p>
|
||||
<p class="text-lg font-semibold text-gray-700 dark:text-gray-200" x-text="stats.videos">0</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Documents -->
|
||||
<div class="flex items-center p-4 bg-white rounded-lg shadow-xs dark:bg-gray-800">
|
||||
<div class="p-3 mr-4 text-orange-500 bg-orange-100 rounded-full dark:text-orange-100 dark:bg-orange-500">
|
||||
<span x-html="$icon('document-text', 'w-5 h-5')"></span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">Documents</p>
|
||||
<p class="text-lg font-semibold text-gray-700 dark:text-gray-200" x-text="stats.documents">0</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filters -->
|
||||
<div x-show="!loading" class="bg-white rounded-lg shadow-md dark:bg-gray-800 p-4 mb-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<!-- Search -->
|
||||
<div class="md:col-span-2">
|
||||
<div class="relative">
|
||||
<span class="absolute inset-y-0 left-0 flex items-center pl-3 text-gray-500 dark:text-gray-400">
|
||||
<span x-html="$icon('search', 'w-5 h-5')"></span>
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
x-model="filters.search"
|
||||
@input.debounce.300ms="loadMedia()"
|
||||
placeholder="Search files..."
|
||||
class="w-full pl-10 pr-4 py-2 text-sm border rounded-lg dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Type Filter -->
|
||||
<div>
|
||||
<select
|
||||
x-model="filters.type"
|
||||
@change="loadMedia()"
|
||||
class="w-full px-4 py-2 text-sm border rounded-lg dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple"
|
||||
>
|
||||
<option value="">All Types</option>
|
||||
<option value="image">Images</option>
|
||||
<option value="video">Videos</option>
|
||||
<option value="document">Documents</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Folder Filter -->
|
||||
<div>
|
||||
<select
|
||||
x-model="filters.folder"
|
||||
@change="loadMedia()"
|
||||
class="w-full px-4 py-2 text-sm border rounded-lg dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple"
|
||||
>
|
||||
<option value="">All Folders</option>
|
||||
<option value="general">General</option>
|
||||
<option value="products">Products</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Media Grid -->
|
||||
<div x-show="!loading && !error">
|
||||
<!-- Empty State -->
|
||||
<div x-show="media.length === 0" class="bg-white rounded-lg shadow-md dark:bg-gray-800 p-12 text-center">
|
||||
<div class="text-gray-400 mb-4">
|
||||
<span x-html="$icon('photograph', 'w-16 h-16 mx-auto')"></span>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-gray-700 dark:text-gray-200 mb-2">No Media Files Yet</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-4">Upload your first file to get started</p>
|
||||
<button
|
||||
@click="showUploadModal = true"
|
||||
class="px-4 py-2 text-sm font-medium text-white bg-purple-600 rounded-lg hover:bg-purple-700"
|
||||
>
|
||||
<span x-html="$icon('upload', 'w-4 h-4 inline mr-2')"></span>
|
||||
Upload Files
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Media Grid -->
|
||||
<div x-show="media.length > 0" class="grid gap-6 md:grid-cols-4 lg:grid-cols-6">
|
||||
<template x-for="item in media" :key="item.id">
|
||||
<div
|
||||
class="bg-white rounded-lg shadow-md dark:bg-gray-800 overflow-hidden cursor-pointer hover:shadow-lg transition-shadow"
|
||||
@click="selectMedia(item)"
|
||||
>
|
||||
<!-- Thumbnail/Preview -->
|
||||
<div class="aspect-square bg-gray-100 dark:bg-gray-700 relative">
|
||||
<!-- Image preview -->
|
||||
<template x-if="item.media_type === 'image'">
|
||||
<img
|
||||
:src="item.thumbnail_url || item.file_url"
|
||||
:alt="item.original_filename"
|
||||
class="w-full h-full object-cover"
|
||||
@error="$el.src = '/static/vendor/img/placeholder.svg'"
|
||||
>
|
||||
</template>
|
||||
|
||||
<!-- Video icon -->
|
||||
<template x-if="item.media_type === 'video'">
|
||||
<div class="w-full h-full flex items-center justify-center text-gray-400">
|
||||
<span x-html="$icon('play', 'w-12 h-12')"></span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Document icon -->
|
||||
<template x-if="item.media_type === 'document'">
|
||||
<div class="w-full h-full flex items-center justify-center text-gray-400">
|
||||
<span x-html="$icon('document-text', 'w-12 h-12')"></span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Type badge -->
|
||||
<div class="absolute top-2 right-2">
|
||||
<span
|
||||
class="px-2 py-1 text-xs font-medium rounded"
|
||||
:class="{
|
||||
'bg-green-100 text-green-800 dark:bg-green-800 dark:text-green-100': item.media_type === 'image',
|
||||
'bg-purple-100 text-purple-800 dark:bg-purple-800 dark:text-purple-100': item.media_type === 'video',
|
||||
'bg-orange-100 text-orange-800 dark:bg-orange-800 dark:text-orange-100': item.media_type === 'document'
|
||||
}"
|
||||
x-text="item.media_type"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Info -->
|
||||
<div class="p-3">
|
||||
<p class="text-sm font-medium text-gray-700 dark:text-gray-200 truncate" x-text="item.original_filename"></p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400" x-text="formatFileSize(item.file_size)"></p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div x-show="pagination.pages > 1" class="mt-6">
|
||||
{{ pagination('pagination.pages > 1') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload Modal -->
|
||||
<div
|
||||
x-show="showUploadModal"
|
||||
x-cloak
|
||||
class="fixed inset-0 z-50 flex items-center justify-center overflow-y-auto bg-black bg-opacity-50"
|
||||
@click.self="showUploadModal = false"
|
||||
>
|
||||
<div class="relative w-full max-w-xl mx-4 bg-white rounded-lg shadow-lg dark:bg-gray-800" @click.stop>
|
||||
<!-- Modal Header -->
|
||||
<div class="flex items-center justify-between px-6 py-4 border-b dark:border-gray-700">
|
||||
<h3 class="text-lg font-semibold text-gray-700 dark:text-gray-200">Upload Files</h3>
|
||||
<button @click="showUploadModal = false" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
|
||||
<span x-html="$icon('x', 'w-5 h-5')"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Modal Body -->
|
||||
<div class="px-6 py-4">
|
||||
<!-- Folder Selection -->
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-400 mb-2">Upload to Folder</label>
|
||||
<select
|
||||
x-model="uploadFolder"
|
||||
class="w-full px-4 py-2 text-sm border rounded-lg dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300"
|
||||
>
|
||||
<option value="general">General</option>
|
||||
<option value="products">Products</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Drop Zone -->
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg p-8 text-center transition-colors"
|
||||
:class="isDragging ? 'border-purple-500 bg-purple-50 dark:bg-purple-900/20' : 'border-gray-300 dark:border-gray-600'"
|
||||
@dragover.prevent="isDragging = true"
|
||||
@dragleave.prevent="isDragging = false"
|
||||
@drop.prevent="handleDrop($event)"
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
multiple
|
||||
accept="image/*,video/*,.pdf,.doc,.docx,.xls,.xlsx,.csv,.txt"
|
||||
class="hidden"
|
||||
x-ref="fileInput"
|
||||
@change="handleFileSelect($event)"
|
||||
>
|
||||
|
||||
<div class="text-gray-400 mb-4">
|
||||
<span x-html="$icon('cloud-upload', 'w-12 h-12 mx-auto')"></span>
|
||||
</div>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-2">Drag and drop files here, or</p>
|
||||
<button
|
||||
@click="$refs.fileInput.click()"
|
||||
class="px-4 py-2 text-sm font-medium text-purple-600 border border-purple-600 rounded-lg hover:bg-purple-50 dark:hover:bg-purple-900/20"
|
||||
>
|
||||
Browse Files
|
||||
</button>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mt-4">
|
||||
Supported: Images (10MB), Videos (100MB), Documents (20MB)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Upload Progress -->
|
||||
<div x-show="uploadingFiles.length > 0" class="mt-4 space-y-2">
|
||||
<template x-for="file in uploadingFiles" :key="file.name">
|
||||
<div class="flex items-center gap-3 p-2 bg-gray-50 dark:bg-gray-700 rounded">
|
||||
<div class="flex-shrink-0">
|
||||
<span x-html="$icon(file.status === 'success' ? 'check-circle' : file.status === 'error' ? 'x-circle' : 'spinner', 'w-5 h-5')"
|
||||
:class="{
|
||||
'text-green-500': file.status === 'success',
|
||||
'text-red-500': file.status === 'error',
|
||||
'text-gray-400 animate-spin': file.status === 'uploading'
|
||||
}"></span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm text-gray-700 dark:text-gray-200 truncate" x-text="file.name"></p>
|
||||
<p x-show="file.error" class="text-xs text-red-500" x-text="file.error"></p>
|
||||
</div>
|
||||
<div class="text-xs text-gray-500" x-text="file.status === 'uploading' ? 'Uploading...' : file.status"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Footer -->
|
||||
<div class="flex justify-end gap-3 px-6 py-4 border-t dark:border-gray-700">
|
||||
<button
|
||||
@click="showUploadModal = false"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600 dark:hover:bg-gray-600"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Media Detail Modal -->
|
||||
<div
|
||||
x-show="showDetailModal"
|
||||
x-cloak
|
||||
class="fixed inset-0 z-50 flex items-center justify-center overflow-y-auto bg-black bg-opacity-50"
|
||||
@click.self="showDetailModal = false"
|
||||
>
|
||||
<div class="relative w-full max-w-2xl mx-4 bg-white rounded-lg shadow-lg dark:bg-gray-800" @click.stop>
|
||||
<!-- Modal Header -->
|
||||
<div class="flex items-center justify-between px-6 py-4 border-b dark:border-gray-700">
|
||||
<h3 class="text-lg font-semibold text-gray-700 dark:text-gray-200">Media Details</h3>
|
||||
<button @click="showDetailModal = false" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
|
||||
<span x-html="$icon('x', 'w-5 h-5')"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Modal Body -->
|
||||
<div class="px-6 py-4" x-show="selectedMedia">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- Preview -->
|
||||
<div class="bg-gray-100 dark:bg-gray-700 rounded-lg overflow-hidden">
|
||||
<template x-if="selectedMedia?.media_type === 'image'">
|
||||
<img :src="selectedMedia?.file_url" :alt="selectedMedia?.original_filename" class="w-full h-auto">
|
||||
</template>
|
||||
<template x-if="selectedMedia?.media_type !== 'image'">
|
||||
<div class="aspect-square flex items-center justify-center text-gray-400">
|
||||
<span x-html="$icon(selectedMedia?.media_type === 'video' ? 'play' : 'document-text', 'w-16 h-16')"></span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Details -->
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-400 mb-1">Filename</label>
|
||||
<input
|
||||
type="text"
|
||||
x-model="editingMedia.filename"
|
||||
class="w-full px-3 py-2 text-sm border rounded-lg dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-400 mb-1">Alt Text</label>
|
||||
<input
|
||||
type="text"
|
||||
x-model="editingMedia.alt_text"
|
||||
placeholder="Describe this image for accessibility"
|
||||
class="w-full px-3 py-2 text-sm border rounded-lg dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-400 mb-1">Description</label>
|
||||
<textarea
|
||||
x-model="editingMedia.description"
|
||||
rows="2"
|
||||
class="w-full px-3 py-2 text-sm border rounded-lg dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-400 mb-1">Folder</label>
|
||||
<select
|
||||
x-model="editingMedia.folder"
|
||||
class="w-full px-3 py-2 text-sm border rounded-lg dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300"
|
||||
>
|
||||
<option value="general">General</option>
|
||||
<option value="products">Products</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 text-sm text-gray-600 dark:text-gray-400">
|
||||
<div>
|
||||
<span class="font-medium">Type:</span>
|
||||
<span x-text="selectedMedia?.media_type"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-medium">Size:</span>
|
||||
<span x-text="formatFileSize(selectedMedia?.file_size)"></span>
|
||||
</div>
|
||||
<div x-show="selectedMedia?.width">
|
||||
<span class="font-medium">Dimensions:</span>
|
||||
<span x-text="`${selectedMedia?.width}x${selectedMedia?.height}`"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- File URL -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-400 mb-1">File URL</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
:value="selectedMedia?.file_url"
|
||||
readonly
|
||||
class="flex-1 px-3 py-2 text-sm border rounded-lg bg-gray-50 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300"
|
||||
>
|
||||
<button
|
||||
@click="copyToClipboard(selectedMedia?.file_url)"
|
||||
class="px-3 py-2 text-sm border rounded-lg hover:bg-gray-50 dark:border-gray-600 dark:hover:bg-gray-700"
|
||||
title="Copy URL"
|
||||
>
|
||||
<span x-html="$icon('clipboard-copy', 'w-4 h-4')"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Footer -->
|
||||
<div class="flex justify-between px-6 py-4 border-t dark:border-gray-700">
|
||||
<button
|
||||
@click="deleteMedia()"
|
||||
class="px-4 py-2 text-sm font-medium text-red-600 border border-red-600 rounded-lg hover:bg-red-50 dark:hover:bg-red-900/20"
|
||||
:disabled="saving"
|
||||
>
|
||||
<span x-html="$icon('trash', 'w-4 h-4 inline mr-1')"></span>
|
||||
Delete
|
||||
</button>
|
||||
<div class="flex gap-3">
|
||||
<button
|
||||
@click="showDetailModal = false"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600 dark:hover:bg-gray-600"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
@click="saveMediaDetails()"
|
||||
class="px-4 py-2 text-sm font-medium text-white bg-purple-600 rounded-lg hover:bg-purple-700"
|
||||
:disabled="saving"
|
||||
>
|
||||
<span x-show="saving" class="inline-block w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2"></span>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script src="{{ url_for('cms_static', path='vendor/js/media.js') }}"></script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user