feat: Redesign post detail page as blog-style adventure story
Major UI/UX improvements for better storytelling: Story Layout: - Convert adventure story into blog-style sequential sections - Extract keywords from **bold** text and display as highlight tags - Show sections with keywords → text → images flow - Create continuous narrative experience with section separators Photo Gallery Enhancement: - Move photo gallery to compact sidebar widget - Reduce gallery size to focus attention on story - Show 2x2 grid with hover effects and cover indicators - Add 'click to view gallery' hint for better UX Features: - Parse content sections separated by double newlines - Extract **keyword** patterns as section highlights - Distribute section images across story sections - Maintain image modal functionality - Clean, readable typography with proper spacing - Visual hierarchy that guides reader through adventure This creates a much more engaging blog-post experience where the story takes center stage and images support the narrative rather than competing for attention.
This commit is contained in:
@@ -85,59 +85,96 @@
|
||||
<!-- Main Content Grid -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
<!-- Main Content -->
|
||||
<div class="lg:col-span-2 space-y-8">
|
||||
<!-- Adventure Story -->
|
||||
<div class="lg:col-span-2">
|
||||
<!-- Adventure Story Blog Post -->
|
||||
<div class="bg-white rounded-2xl shadow-xl overflow-hidden">
|
||||
<div class="bg-gradient-to-r from-blue-600 to-purple-600 p-6">
|
||||
<div class="flex items-center text-white">
|
||||
<i class="fas fa-book-open text-2xl mr-3"></i>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold">Adventure Story</h2>
|
||||
<p class="text-blue-100">Discover the journey through the author's words</p>
|
||||
<p class="text-blue-100">Follow the journey step by step</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="prose prose-lg max-w-none text-gray-700">
|
||||
{{ post.content | safe | nl2br }}
|
||||
<div class="p-8">
|
||||
<div class="prose prose-lg max-w-none">
|
||||
{% set content_sections = post.content.split('\n\n') %}
|
||||
{% set section_images = post.images.filter_by(is_cover=False).all() %}
|
||||
{% set images_per_section = (section_images|length / (content_sections|length))|round|int if content_sections|length > 0 else 0 %}
|
||||
|
||||
{% for section in content_sections %}
|
||||
{% if section.strip() %}
|
||||
<div class="mb-8 pb-6 {% if not loop.last %}border-b border-gray-200{% endif %}">
|
||||
{% set section_text = section.strip() %}
|
||||
|
||||
<!-- Extract keywords from **bold** text -->
|
||||
{% set keywords = [] %}
|
||||
{% set clean_text = section_text %}
|
||||
|
||||
<!-- Simple keyword extraction for **word** patterns -->
|
||||
{% if '**' in section_text %}
|
||||
{% set parts = section_text.split('**') %}
|
||||
{% set clean_parts = [] %}
|
||||
{% for i in range(parts|length) %}
|
||||
{% if i % 2 == 1 %}
|
||||
{% set _ = keywords.append(parts[i]) %}
|
||||
{% set _ = clean_parts.append(parts[i]) %}
|
||||
{% else %}
|
||||
{% set _ = clean_parts.append(parts[i]) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% set clean_text = clean_parts|join('') %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Section Keywords -->
|
||||
{% if keywords %}
|
||||
<div class="mb-4">
|
||||
{% for keyword in keywords %}
|
||||
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-gradient-to-r from-amber-500 to-orange-500 text-white mr-2 mb-2">
|
||||
<i class="fas fa-tag mr-1 text-xs"></i>
|
||||
{{ keyword }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Section Text -->
|
||||
<div class="text-gray-700 leading-relaxed mb-6 text-lg">
|
||||
{{ clean_text | safe | nl2br }}
|
||||
</div>
|
||||
|
||||
<!-- Section Images -->
|
||||
{% if section_images %}
|
||||
{% set start_idx = loop.index0 * images_per_section %}
|
||||
{% set end_idx = start_idx + images_per_section %}
|
||||
{% set current_section_images = section_images[start_idx:end_idx] %}
|
||||
|
||||
{% if current_section_images %}
|
||||
<div class="grid grid-cols-1 {% if current_section_images|length > 1 %}md:grid-cols-2{% endif %} gap-4 mb-6">
|
||||
{% for image in current_section_images %}
|
||||
<div class="relative rounded-xl overflow-hidden cursor-pointer group transition-all duration-300 hover:shadow-lg"
|
||||
onclick="openImageModal('{{ image.get_url() }}', '{{ image.description or image.original_name }}')">
|
||||
<img src="{{ image.get_url() }}" alt="{{ image.description or image.original_name }}"
|
||||
class="w-full h-64 object-cover transition-transform duration-300 group-hover:scale-105">
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
||||
{% if image.description %}
|
||||
<div class="absolute bottom-0 left-0 right-0 p-3 text-white text-sm opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||
{{ image.description }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Photo Gallery -->
|
||||
{% if post.images.count() > 0 %}
|
||||
<div class="bg-white rounded-2xl shadow-xl overflow-hidden">
|
||||
<div class="bg-gradient-to-r from-green-600 to-teal-600 p-6">
|
||||
<div class="flex items-center text-white">
|
||||
<i class="fas fa-camera-retro text-2xl mr-3"></i>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold">Photo Gallery</h2>
|
||||
<p class="text-green-100">Visual highlights from this adventure</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{% for image in post.images %}
|
||||
<div class="relative rounded-lg overflow-hidden cursor-pointer group transition-transform duration-300 hover:scale-105"
|
||||
onclick="openImageModal('{{ image.get_url() }}', '{{ image.description or image.original_name }}')">
|
||||
<img src="{{ image.get_url() }}" alt="{{ image.description or image.original_name }}"
|
||||
class="w-full h-64 object-cover">
|
||||
{% if image.description %}
|
||||
<div class="absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-end">
|
||||
<p class="text-white p-4 text-sm">{{ image.description }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if image.is_cover %}
|
||||
<div class="absolute top-2 left-2">
|
||||
<span class="inline-flex items-center px-2 py-1 rounded bg-yellow-500 text-white text-xs font-semibold">
|
||||
<i class="fas fa-star mr-1"></i> Cover
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -319,6 +356,45 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Photo Gallery (Compact) -->
|
||||
{% if post.images.count() > 0 %}
|
||||
<div class="bg-white rounded-2xl shadow-xl overflow-hidden">
|
||||
<div class="bg-gradient-to-r from-green-600 to-teal-600 p-4">
|
||||
<div class="flex items-center text-white">
|
||||
<i class="fas fa-camera-retro text-xl mr-2"></i>
|
||||
<div>
|
||||
<h2 class="text-lg font-bold">Photo Gallery</h2>
|
||||
<p class="text-green-100 text-sm">{{ post.images.count() }} photos</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
{% for image in post.images %}
|
||||
<div class="relative rounded-lg overflow-hidden cursor-pointer group"
|
||||
onclick="openImageModal('{{ image.get_url() }}', '{{ image.description or image.original_name }}')">
|
||||
<img src="{{ image.get_url() }}" alt="{{ image.description or image.original_name }}"
|
||||
class="w-full h-20 object-cover transition-transform duration-300 group-hover:scale-110">
|
||||
{% if image.is_cover %}
|
||||
<div class="absolute top-1 left-1">
|
||||
<span class="inline-flex items-center px-1 py-0.5 rounded text-xs font-semibold bg-yellow-500 text-white">
|
||||
<i class="fas fa-star"></i>
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="absolute inset-0 bg-black/30 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if post.images.count() > 4 %}
|
||||
<div class="mt-3 text-center">
|
||||
<span class="text-sm text-gray-500">Click any photo to view gallery</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user