- messages.js: Add missing `error` property required by error_state macro - platform-homepage.html: Use `<template x-if>` instead of `x-show` to prevent Alpine from evaluating `page.template` when `page` is null 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
223 lines
11 KiB
HTML
223 lines
11 KiB
HTML
{# app/templates/admin/platform-homepage.html #}
|
|
{% extends "admin/base.html" %}
|
|
{% from 'shared/macros/alerts.html' import loading_state, error_state, alert_dynamic %}
|
|
{% from 'shared/macros/headers.html' import page_header_flex, action_button %}
|
|
|
|
{% block title %}Platform Homepage Manager{% endblock %}
|
|
|
|
{% block alpine_data %}platformHomepageManager(){% endblock %}
|
|
|
|
{% block content %}
|
|
{# Note: Subtitle has inline HTML link, so using page_header_flex with custom structure #}
|
|
<div class="flex items-center justify-between my-6">
|
|
<div>
|
|
<h2 class="text-2xl font-semibold text-gray-700 dark:text-gray-200">Platform Homepage</h2>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
|
Manage your platform's main landing page at <a href="/" target="_blank" class="text-purple-600 hover:underline">localhost:8000</a>
|
|
</p>
|
|
</div>
|
|
<div class="flex items-center space-x-3">
|
|
<a href="/" target="_blank"
|
|
class="flex items-center px-4 py-2 text-sm font-medium leading-5 text-gray-700 dark:text-gray-300 transition-colors duration-150 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:shadow-outline-gray">
|
|
<span x-html="$icon('eye', 'w-4 h-4 mr-2')"></span>
|
|
Preview
|
|
</a>
|
|
{{ action_button('Save Changes', 'Saving...', 'saving', 'savePage()') }}
|
|
</div>
|
|
</div>
|
|
|
|
{{ loading_state('Loading homepage...') }}
|
|
|
|
{{ error_state('Error loading homepage') }}
|
|
|
|
{{ alert_dynamic(type='success', message_var='successMessage', show_condition='successMessage') }}
|
|
|
|
<!-- Main Form -->
|
|
<template x-if="!loading && page">
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden">
|
|
<form @submit.prevent="savePage()">
|
|
<!-- Template Selection -->
|
|
<div class="p-6 border-b border-gray-200 dark:border-gray-700">
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">
|
|
Template Selection
|
|
</h3>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
|
|
Choose the visual style for your homepage. Each template offers a different layout and design.
|
|
</p>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<!-- Default Template -->
|
|
<label class="cursor-pointer">
|
|
<input type="radio" name="template" value="default" x-model="page.template" class="sr-only">
|
|
<div
|
|
class="border-2 rounded-lg p-4 transition-all"
|
|
:class="page.template === 'default' ? 'border-purple-600 bg-purple-50 dark:bg-purple-900/20' : 'border-gray-300 dark:border-gray-600 hover:border-gray-400'"
|
|
>
|
|
<div class="flex items-center justify-between mb-2">
|
|
<span class="font-semibold text-gray-900 dark:text-white">Default</span>
|
|
<span x-show="page.template === 'default'" x-html="$icon('check-circle', 'w-5 h-5 text-purple-600')"></span>
|
|
</div>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Full-featured with hero section, features grid, vendor cards, and call-to-action.
|
|
</p>
|
|
<div class="mt-3 h-24 bg-gradient-to-r from-purple-400 to-pink-400 rounded"></div>
|
|
</div>
|
|
</label>
|
|
|
|
<!-- Minimal Template -->
|
|
<label class="cursor-pointer">
|
|
<input type="radio" name="template" value="minimal" x-model="page.template" class="sr-only">
|
|
<div
|
|
class="border-2 rounded-lg p-4 transition-all"
|
|
:class="page.template === 'minimal' ? 'border-purple-600 bg-purple-50 dark:bg-purple-900/20' : 'border-gray-300 dark:border-gray-600 hover:border-gray-400'"
|
|
>
|
|
<div class="flex items-center justify-between mb-2">
|
|
<span class="font-semibold text-gray-900 dark:text-white">Minimal</span>
|
|
<span x-show="page.template === 'minimal'" x-html="$icon('check-circle', 'w-5 h-5 text-purple-600')"></span>
|
|
</div>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Clean and simple design with emoji icons and essential information only.
|
|
</p>
|
|
<div class="mt-3 h-24 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded"></div>
|
|
</div>
|
|
</label>
|
|
|
|
<!-- Modern Template -->
|
|
<label class="cursor-pointer">
|
|
<input type="radio" name="template" value="modern" x-model="page.template" class="sr-only">
|
|
<div
|
|
class="border-2 rounded-lg p-4 transition-all"
|
|
:class="page.template === 'modern' ? 'border-purple-600 bg-purple-50 dark:bg-purple-900/20' : 'border-gray-300 dark:border-gray-600 hover:border-gray-400'"
|
|
>
|
|
<div class="flex items-center justify-between mb-2">
|
|
<span class="font-semibold text-gray-900 dark:text-white">Modern</span>
|
|
<span x-show="page.template === 'modern'" x-html="$icon('check-circle', 'w-5 h-5 text-purple-600')"></span>
|
|
</div>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Trendy design with animated gradients, stats, and modern UI elements.
|
|
</p>
|
|
<div class="mt-3 h-24 bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 rounded"></div>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Page Content -->
|
|
<div class="p-6 border-b border-gray-200 dark:border-gray-700">
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">
|
|
Page Content
|
|
</h3>
|
|
|
|
<!-- Title -->
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
Page Title
|
|
</label>
|
|
<input
|
|
type="text"
|
|
x-model="page.title"
|
|
required
|
|
maxlength="200"
|
|
class="w-full px-3 py-2 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:border-purple-500 dark:bg-gray-700"
|
|
placeholder="Welcome to Our Multi-Vendor Marketplace"
|
|
>
|
|
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
|
Main heading displayed on the homepage
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Content (HTML) -->
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
Content (HTML)
|
|
</label>
|
|
<textarea
|
|
x-model="page.content"
|
|
rows="6"
|
|
class="w-full px-3 py-2 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:border-purple-500 dark:bg-gray-700 font-mono text-sm"
|
|
placeholder="<p>Your platform description here...</p>"
|
|
></textarea>
|
|
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
|
HTML content shown below the title. Basic HTML tags are supported.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SEO Settings -->
|
|
<div class="p-6 border-b border-gray-200 dark:border-gray-700">
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">
|
|
SEO Settings
|
|
</h3>
|
|
|
|
<!-- Meta Description -->
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
Meta Description
|
|
</label>
|
|
<textarea
|
|
x-model="page.meta_description"
|
|
rows="2"
|
|
maxlength="300"
|
|
class="w-full px-3 py-2 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:border-purple-500 dark:bg-gray-700"
|
|
placeholder="A brief description for search engines (150-160 characters recommended)"
|
|
></textarea>
|
|
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
|
<span x-text="(page.meta_description || '').length"></span>/300 characters
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Meta Keywords -->
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
Meta Keywords
|
|
</label>
|
|
<input
|
|
type="text"
|
|
x-model="page.meta_keywords"
|
|
maxlength="300"
|
|
class="w-full px-3 py-2 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:border-purple-500 dark:bg-gray-700"
|
|
placeholder="marketplace, multi-vendor, e-commerce"
|
|
>
|
|
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
|
Comma-separated keywords (optional)
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Publishing Settings -->
|
|
<div class="p-6 bg-gray-50 dark:bg-gray-700/50">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<label class="flex items-center cursor-pointer">
|
|
<input
|
|
type="checkbox"
|
|
x-model="page.is_published"
|
|
class="w-5 h-5 text-purple-600 border-gray-300 rounded focus:ring-purple-500"
|
|
>
|
|
<span class="ml-3 text-sm font-medium text-gray-900 dark:text-white">
|
|
Published
|
|
</span>
|
|
</label>
|
|
<p class="ml-8 text-xs text-gray-500 dark:text-gray-400">
|
|
Make this homepage visible to the public
|
|
</p>
|
|
</div>
|
|
|
|
<button
|
|
type="submit"
|
|
:disabled="saving"
|
|
class="px-6 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
<span x-text="saving ? 'Saving...' : 'Save Changes'"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</template>
|
|
{% endblock %}
|
|
|
|
{% block extra_scripts %}
|
|
<script src="{{ url_for('static', path='admin/js/platform-homepage.js') }}"></script>
|
|
{% endblock %}
|