Files
moto-adv-website/app/templates/community/index.html

381 lines
18 KiB
HTML

{% extends "base.html" %}
{% block title %}Motorcycle Adventures Romania{% endblock %}
{% block head %}
<style>
/* 3-row grid card layout */
.map-card {
display: flex;
flex-direction: column;
min-height: 800px;
background: rgba(255,255,255,0.07);
border-radius: 1.5rem;
box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25);
border: 2px solid #10b981;
padding: 0;
overflow: hidden;
}
.map-card-square {
width: 100%;
max-width: 700px;
aspect-ratio: 1 / 1;
margin: 0 auto;
background: rgba(255,255,255,0.07);
border-radius: 1.5rem;
box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25);
border: 2px solid #10b981;
display: flex;
flex-direction: column;
overflow: hidden;
}
.map-card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem 1.25rem 0.5rem 1.25rem;
}
.map-card-title {
font-size: 1.1rem;
font-weight: bold;
color: #fff;
}
.map-card-count {
font-size: 0.95rem;
color: #a5b4fc;
text-align: right;
}
.map-card-content {
flex: 1 1 0%;
display: flex;
align-items: center;
justify-content: center;
min-height: 0;
min-width: 0;
padding: 0;
}
.map-iframe-container {
width: 100%;
height: 100%;
aspect-ratio: 1 / 1;
background: #f0f0f0;
border-radius: 1rem;
box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25);
border: 2px solid #10b981;
position: relative;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
overflow: hidden;
}
.map-iframe {
width: 100%;
height: 100%;
aspect-ratio: 1 / 1;
border: none;
display: block;
border-radius: 1rem;
background: #f0f0f0;
}
/* Loading state for iframe */
.iframe-loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
background: rgba(255, 255, 255, 0.95);
padding: 20px;
border-radius: 12px;
text-align: center;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255,255,255,0.2);
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
min-width: 200px;
transition: opacity 0.3s ease;
}
.iframe-loading.hidden {
opacity: 0;
pointer-events: none;
}
.map-card-footer {
padding: 0.5rem 1.25rem 0.75rem 1.25rem;
background: transparent;
text-align: center;
}
@media (max-width: 900px) {
.map-iframe-container, .map-iframe {
height: 40vh;
min-height: 200px;
}
}
</style>
{% endblock %}
{% block content %}
<div class="min-h-screen bg-gradient-to-br from-blue-900 via-purple-900 to-teal-900">
<!-- Header Section -->
<div class="relative overflow-hidden">
<div class="absolute inset-0 bg-black/20"></div>
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-2 pb-2">
<div class="text-center mb-2">
<h1 class="text-2xl md:text-3xl font-bold text-white mb-1">
🏍️ Motorcycle Adventures Romania
</h1>
<p class="text-base text-blue-100 max-w-2xl mx-auto">
Discover epic motorcycle routes, share your adventures, and connect with fellow riders across Romania's stunning landscapes.
</p>
</div>
</div>
</div>
<!-- Interactive Map Section (Wide Rectangular Card) -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 mb-12">
<div class="w-11/12 md:w-10/12 lg:w-5/6 xl:w-11/12 mx-auto bg-white/10 backdrop-blur-sm rounded-2xl p-4 border border-white/20 flex flex-col" style="">
<div class="flex justify-between items-center mb-2">
<h2 class="text-xl font-bold text-white">🗺️ Interactive Route Map</h2>
<div class="text-sm text-blue-200">
<span id="route-count">{{ posts_with_routes|length }}</span> routes discovered
</div>
</div>
<div class="flex-1 flex items-center justify-center">
<div class="w-full aspect-[10/7] rounded-xl overflow-hidden border-2 border-emerald-500 bg-gray-100 relative">
<!-- Loading indicator -->
<div id="iframe-loading" class="absolute inset-0 flex flex-col items-center justify-center bg-white/80 z-10">
<div class="animate-spin rounded-full h-5 w-5 border-b-2 border-orange-600 mb-2"></div>
<span class="text-gray-700 text-sm">Loading interactive map...</span>
</div>
<iframe
id="map-iframe"
src="{{ url_for('static', filename='map_iframe.html') }}"
class="w-full h-full border-0 rounded-xl bg-gray-100 aspect-[10/7]"
title="Adventure Routes Map"
onload="hideIframeLoading()">
</iframe>
</div>
</div>
<p class="text-blue-200 text-xs mt-2 text-center">
Click on any route to view the adventure story • Routes are updated live as new trips are shared
</p>
</div>
</div>
<!-- Action Buttons -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 mb-8">
<div class="flex flex-wrap justify-center gap-4">
{% if current_user.is_authenticated %}
<a href="{{ url_for('community.new_post') }}"
class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-lg text-white bg-gradient-to-r from-orange-500 to-red-600 hover:from-orange-600 hover:to-red-700 transform hover:scale-105 transition-all duration-200 shadow-lg">
<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="M12 4v16m8-8H4"></path>
</svg>
Share Your Adventure
</a>
<a href="{{ url_for('auth.logout') }}"
class="inline-flex items-center px-6 py-3 border border-white/30 text-base font-medium rounded-lg text-white hover:bg-white/10 transition-all duration-200">
<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="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path>
</svg>
Logout
</a>
{% else %}
<a href="{{ url_for('auth.register') }}"
class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-lg text-white bg-gradient-to-r from-orange-500 to-red-600 hover:from-orange-600 hover:to-red-700 transform hover:scale-105 transition-all duration-200 shadow-lg">
<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="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"></path>
</svg>
Join Community
</a>
<a href="{{ url_for('auth.login') }}"
class="inline-flex items-center px-6 py-3 border border-white/30 text-base font-medium rounded-lg text-white hover:bg-white/10 transition-all duration-200">
<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="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"></path>
</svg>
Login
</a>
{% endif %}
</div>
</div>
<!-- Latest Adventures Grid -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div class="flex justify-between items-center mb-8">
<h2 class="text-3xl font-bold text-white">Latest Adventures</h2>
<div class="text-blue-200 text-sm">
Showing {{ posts.items|length }} of {{ posts.total }} stories
</div>
</div>
{% if posts.items %}
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{% for post in posts.items %}
<article class="bg-white/10 backdrop-blur-sm rounded-xl overflow-hidden shadow-xl hover:shadow-2xl transition-all duration-300 border border-white/20 hover:border-white/40 transform hover:-translate-y-1">
{% set cover_image = post.images.filter_by(is_cover=True).first() %}
{% if cover_image %}
<div class="aspect-w-16 aspect-h-9 bg-gray-900">
<img src="{{ cover_image.get_url() }}"
alt="{{ post.title }}"
class="w-full h-48 object-cover">
</div>
{% elif post.images %}
<div class="aspect-w-16 aspect-h-9 bg-gray-900">
<img src="{{ post.images[0].get_url() }}"
alt="{{ post.title }}"
class="w-full h-48 object-cover">
</div>
{% endif %}
<div class="p-5">
<div class="flex items-center mb-3">
<div class="flex-shrink-0">
<div class="w-8 h-8 bg-gradient-to-r from-orange-500 to-red-600 rounded-full flex items-center justify-center">
<span class="text-white font-bold text-xs">{{ post.author.nickname[0].upper() }}</span>
</div>
</div>
<div class="ml-2">
<p class="text-sm font-medium text-white">{{ post.author.nickname }}</p>
<p class="text-xs text-blue-200">{{ post.created_at.strftime('%b %d, %Y') }}</p>
</div>
</div>
<h3 class="text-lg font-bold text-white mb-2 line-clamp-2">
<a href="{{ url_for('community.post_detail', id=post.id) }}"
class="hover:text-orange-400 transition-colors">
{{ post.title }}
</a>
</h3>
{% if post.subtitle %}
<p class="text-sm text-blue-200 mb-2 line-clamp-1">{{ post.subtitle }}</p>
{% endif %}
<p class="text-blue-100 text-sm mb-4 line-clamp-2">
{{ post.content[:120] }}{% if post.content|length > 120 %}...{% endif %}
</p>
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3 text-xs text-blue-200">
{% if post.gpx_files %}
<span class="flex items-center bg-green-500/20 px-2 py-1 rounded-full">
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path>
</svg>
GPX
</span>
{% endif %}
<span class="flex items-center">
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
</svg>
{{ post.comments.count() }}
</span>
<span class="flex items-center">
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"></path>
</svg>
{{ post.likes.count() }}
</span>
</div>
<a href="{{ url_for('community.post_detail', id=post.id) }}"
class="text-orange-400 hover:text-orange-300 font-medium text-xs transition-colors">
Read More →
</a>
</div>
</div>
</article>
{% endfor %}
</div>
<!-- Pagination -->
{% if posts.pages > 1 %}
<div class="mt-12 flex justify-center">
<nav class="flex items-center space-x-2">
{% if posts.has_prev %}
<a href="{{ url_for('community.index', page=posts.prev_num) }}"
class="px-4 py-2 text-white bg-white/10 backdrop-blur-sm rounded-lg hover:bg-white/20 transition-colors">
← Previous
</a>
{% endif %}
{% for page_num in posts.iter_pages() %}
{% if page_num %}
{% if page_num != posts.page %}
<a href="{{ url_for('community.index', page=page_num) }}"
class="px-3 py-2 text-white bg-white/10 backdrop-blur-sm rounded-lg hover:bg-white/20 transition-colors">
{{ page_num }}
</a>
{% else %}
<span class="px-3 py-2 text-white bg-orange-500 rounded-lg">{{ page_num }}</span>
{% endif %}
{% else %}
<span class="px-3 py-2 text-blue-200"></span>
{% endif %}
{% endfor %}
{% if posts.has_next %}
<a href="{{ url_for('community.index', page=posts.next_num) }}"
class="px-4 py-2 text-white bg-white/10 backdrop-blur-sm rounded-lg hover:bg-white/20 transition-colors">
Next →
</a>
{% endif %}
</nav>
</div>
{% endif %}
{% else %}
<!-- Empty State -->
<div class="text-center py-16">
<div class="max-w-md mx-auto">
<svg class="w-16 h-16 text-blue-300 mx-auto mb-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9.5a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"></path>
</svg>
<h3 class="text-2xl font-bold text-white mb-4">No Adventures Yet</h3>
<p class="text-blue-200 mb-6">
Be the first to share your motorcycle adventure and map your route across Romania!
</p>
{% if current_user.is_authenticated %}
<a href="{{ url_for('community.new_post') }}"
class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-lg text-white bg-gradient-to-r from-orange-500 to-red-600 hover:from-orange-600 hover:to-red-700 transform hover:scale-105 transition-all duration-200">
Share Your First Adventure
</a>
{% else %}
<a href="{{ url_for('auth.register') }}"
class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-lg text-white bg-gradient-to-r from-orange-500 to-red-600 hover:from-orange-600 hover:to-red-700 transform hover:scale-105 transition-all duration-200">
Join to Share Adventures
</a>
{% endif %}
</div>
</div>
{% endif %}
</div>
</div>
<script>
// Function to hide iframe loading indicator
function hideIframeLoading() {
const loadingEl = document.getElementById('iframe-loading');
if (loadingEl) {
loadingEl.classList.add('hidden');
setTimeout(() => {
loadingEl.style.display = 'none';
}, 300);
}
}
// Fallback to hide loading after 5 seconds if iframe doesn't trigger onload
setTimeout(() => {
const loadingEl = document.getElementById('iframe-loading');
if (loadingEl && !loadingEl.classList.contains('hidden')) {
console.log('Iframe loading timeout, hiding loading indicator');
hideIframeLoading();
}
}, 5000);
</script>
{% endblock %}