Files
moto-adv-website/app/templates/community/profile.html
ske087 60ef02ced9 Major UI/UX redesign and feature enhancements
🎨 Complete Tailwind CSS conversion
- Redesigned post detail page with modern gradient backgrounds
- Updated profile page with consistent design language
- Converted from Bootstrap to Tailwind CSS throughout

 New Features & Improvements
- Enhanced community post management system
- Added admin panel with analytics dashboard
- Improved post creation and editing workflows
- Interactive GPS map integration with Leaflet.js
- Photo gallery with modal view and hover effects
- Adventure statistics and metadata display
- Like system and community engagement features

🔧 Technical Improvements
- Fixed template syntax errors and CSRF token issues
- Updated database models and relationships
- Enhanced media file management
- Improved responsive design patterns
- Added proper error handling and validation

📱 Mobile-First Design
- Responsive grid layouts
- Touch-friendly interactions
- Optimized for all screen sizes
- Modern card-based UI components

🏍️ Adventure Platform Features
- GPS track visualization and statistics
- Photo uploads with thumbnail generation
- GPX file downloads for registered users
- Community comments and discussions
- Post approval workflow for admins
- Difficulty rating system with star indicators
2025-07-24 02:44:25 +03:00

298 lines
15 KiB
HTML

{% extends "base.html" %}
{% block title %}My Profile - {{ current_user.nickname }}{% endblock %}
{% block content %}
<div class="min-h-screen bg-gradient-to-br from-blue-900 via-purple-900 to-teal-900 pt-16">
<!-- Profile Header -->
<div class="relative overflow-hidden py-16">
<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">
<div class="bg-white/10 backdrop-blur-sm rounded-2xl p-8 border border-white/20">
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
<div class="flex items-center space-x-6">
<div class="w-20 h-20 bg-gradient-to-r from-orange-500 to-red-600 rounded-full flex items-center justify-center text-white font-bold text-3xl">
{{ current_user.nickname[0].upper() }}
</div>
<div>
<h1 class="text-3xl font-bold text-white mb-2">{{ current_user.nickname }}</h1>
<p class="text-blue-200 mb-1">
<i class="fas fa-envelope mr-2"></i>{{ current_user.email }}
</p>
<p class="text-blue-200">
<i class="fas fa-calendar mr-2"></i>Riding since {{ current_user.created_at.strftime('%B %Y') }}
</p>
</div>
</div>
<div>
<a href="{{ url_for('community.new_post') }}"
class="inline-flex items-center px-6 py-3 bg-gradient-to-r from-green-600 to-emerald-600 text-white font-semibold rounded-lg hover:from-green-700 hover:to-emerald-700 transition-all duration-200 transform hover:scale-105">
<i class="fas fa-plus mr-2"></i>Share New Adventure
</a>
</div>
</div>
</div>
</div>
</div>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-12 -mt-8">
<!-- Adventure Statistics -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
<div class="bg-white rounded-2xl shadow-xl overflow-hidden">
<div class="bg-gradient-to-r from-green-600 to-emerald-600 p-6">
<div class="flex items-center text-white">
<i class="fas fa-check-circle text-3xl mr-4"></i>
<div>
<div class="text-3xl font-bold">{{ published_count }}</div>
<div class="text-green-100">Published Adventures</div>
</div>
</div>
</div>
<div class="p-4">
<p class="text-gray-600 text-sm">Visible to the community</p>
</div>
</div>
<div class="bg-white rounded-2xl shadow-xl overflow-hidden">
<div class="bg-gradient-to-r from-yellow-600 to-orange-600 p-6">
<div class="flex items-center text-white">
<i class="fas fa-clock text-3xl mr-4"></i>
<div>
<div class="text-3xl font-bold">{{ pending_count }}</div>
<div class="text-yellow-100">Awaiting Review</div>
</div>
</div>
</div>
<div class="p-4">
<p class="text-gray-600 text-sm">Pending admin approval</p>
</div>
</div>
</div>
<!-- Adventures Collection Header -->
<div class="bg-white rounded-2xl shadow-xl p-6 mb-8">
<div class="flex items-center">
<i class="fas fa-mountain text-3xl text-blue-600 mr-4"></i>
<div>
<h2 class="text-2xl font-bold text-gray-900">My Adventure Collection</h2>
<p class="text-gray-600">Manage and share your motorcycle adventures</p>
</div>
</div>
</div>
<!-- Adventures Grid -->
{% if posts.items %}
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{% for post in posts.items %}
<div class="bg-white rounded-2xl shadow-xl overflow-hidden transition-all duration-300 hover:shadow-2xl hover:scale-105">
<!-- Adventure Image -->
{% set cover_image = post.images | selectattr('is_cover', 'equalto', True) | first %}
{% if cover_image %}
<div class="relative">
<img src="{{ cover_image.get_thumbnail_url() }}"
alt="{{ post.title }}"
class="w-full h-48 object-cover">
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div>
<div class="absolute top-3 right-3">
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-semibold
{{ 'bg-green-500 text-white' if post.published else 'bg-yellow-500 text-black' }}">
{% if post.published %}
<i class="fas fa-check-circle mr-1"></i>Live
{% else %}
<i class="fas fa-clock mr-1"></i>Review
{% endif %}
</span>
</div>
</div>
{% else %}
<div class="h-48 bg-gradient-to-br from-blue-600 to-purple-600 flex items-center justify-center relative">
<i class="fas fa-mountain text-white text-6xl opacity-50"></i>
<div class="absolute top-3 right-3">
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-semibold
{{ 'bg-green-500 text-white' if post.published else 'bg-yellow-500 text-black' }}">
{% if post.published %}
<i class="fas fa-check-circle mr-1"></i>Live
{% else %}
<i class="fas fa-clock mr-1"></i>Review
{% endif %}
</span>
</div>
</div>
{% endif %}
<div class="p-6">
<!-- Title and Subtitle -->
<h3 class="text-xl font-bold text-gray-900 mb-2">{{ post.title }}</h3>
{% if post.subtitle %}
<p class="text-gray-600 text-sm mb-3">{{ post.subtitle }}</p>
{% endif %}
<!-- Difficulty Badge -->
<div class="mb-4">
<span class="inline-flex items-center px-3 py-1 rounded-full bg-gradient-to-r from-yellow-500 to-orange-500 text-white text-sm font-semibold">
{% for i in range(post.difficulty) %}
<i class="fas fa-star mr-1"></i>
{% endfor %}
{{ post.get_difficulty_label() }}
</span>
</div>
<!-- Content Preview -->
<p class="text-gray-600 text-sm mb-4 h-12 overflow-hidden">
{{ (post.content[:100] + '...') if post.content|length > 100 else post.content }}
</p>
<!-- Adventure Metadata -->
<div class="bg-gray-50 rounded-lg p-4 mb-4">
<div class="grid grid-cols-3 gap-4 text-center">
<div>
<i class="fas fa-calendar text-blue-500 mb-1"></i>
<div class="text-sm font-semibold">{{ post.created_at.strftime('%m/%d') }}</div>
<div class="text-xs text-gray-500">Created</div>
</div>
<div>
<i class="fas fa-images text-green-500 mb-1"></i>
<div class="text-sm font-semibold">{{ post.images.count() }}</div>
<div class="text-xs text-gray-500">Photos</div>
</div>
<div>
<i class="fas fa-route text-orange-500 mb-1"></i>
<div class="text-sm font-semibold">{{ post.gpx_files.count() }}</div>
<div class="text-xs text-gray-500">Routes</div>
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="space-y-2">
{% if post.published %}
<a href="{{ url_for('community.post_detail', id=post.id) }}"
class="block w-full text-center px-4 py-2 bg-blue-600 text-white font-semibold rounded-lg hover:bg-blue-700 transition-all duration-200">
<i class="fas fa-eye mr-2"></i>View Live
</a>
{% endif %}
<div class="grid grid-cols-2 gap-2">
<a href="{{ url_for('community.edit_post', id=post.id) }}"
class="text-center px-3 py-2 bg-yellow-500 text-white font-semibold rounded-lg hover:bg-yellow-600 transition-all duration-200">
<i class="fas fa-edit mr-1"></i>Edit
</a>
<button type="button"
class="px-3 py-2 bg-red-500 text-white font-semibold rounded-lg hover:bg-red-600 transition-all duration-200"
data-post-id="{{ post.id }}"
data-post-title="{{ post.title }}"
onclick="confirmDelete(this)">
<i class="fas fa-trash mr-1"></i>Delete
</button>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<!-- No Adventures State -->
<div class="bg-white rounded-2xl shadow-xl p-12 text-center">
<i class="fas fa-mountain text-6xl text-gray-400 mb-6"></i>
<h3 class="text-2xl font-bold text-gray-900 mb-4">Your Adventure Journey Awaits!</h3>
<p class="text-gray-600 mb-8 max-w-md mx-auto">
You haven't shared any motorcycle adventures yet. Every great ride has a story worth telling!
</p>
<a href="{{ url_for('community.new_post') }}"
class="inline-flex items-center px-8 py-4 bg-gradient-to-r from-green-600 to-emerald-600 text-white font-semibold rounded-lg hover:from-green-700 hover:to-emerald-700 transition-all duration-200 transform hover:scale-105">
<i class="fas fa-plus mr-2"></i>Share Your First Adventure
</a>
<div class="mt-6">
<p class="text-sm text-gray-500">
<i class="fas fa-lightbulb mr-1"></i>
Share photos, GPS tracks, and stories of your rides to inspire the community
</p>
</div>
</div>
{% endif %}
<!-- Pagination -->
{% if posts.pages > 1 %}
<div class="flex justify-center mt-8">
<div class="bg-white rounded-lg shadow-lg px-6 py-4">
<div class="flex items-center space-x-4">
{% if posts.has_prev %}
<a href="{{ url_for('community.profile', page=posts.prev_num) }}"
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-200">
<i class="fas fa-chevron-left mr-1"></i>Previous
</a>
{% endif %}
<span class="text-gray-600">
Page {{ posts.page }} of {{ posts.pages }}
</span>
{% if posts.has_next %}
<a href="{{ url_for('community.profile', page=posts.next_num) }}"
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-200">
Next<i class="fas fa-chevron-right ml-1"></i>
</a>
{% endif %}
</div>
</div>
</div>
{% endif %}
</div>
</div>
<!-- Delete Confirmation Modal -->
<div id="deleteModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-2xl p-8 max-w-md mx-4">
<div class="text-center">
<i class="fas fa-exclamation-triangle text-red-500 text-4xl mb-4"></i>
<h3 class="text-xl font-bold text-gray-900 mb-4">Delete Adventure</h3>
<p class="text-gray-600 mb-6">
Are you sure you want to delete "<span id="deletePostTitle" class="font-semibold"></span>"?
This action cannot be undone.
</p>
<div class="flex space-x-4">
<button onclick="closeDeleteModal()"
class="flex-1 px-4 py-2 bg-gray-300 text-gray-700 rounded-lg hover:bg-gray-400 transition-all duration-200">
Cancel
</button>
<form id="deleteForm" method="POST" class="flex-1">
<button type="submit"
class="w-full px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-all duration-200">
Delete
</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
function confirmDelete(button) {
const postId = button.getAttribute('data-post-id');
const postTitle = button.getAttribute('data-post-title');
document.getElementById('deletePostTitle').textContent = postTitle;
document.getElementById('deleteForm').action = `/community/delete-post/${postId}`;
document.getElementById('deleteModal').classList.remove('hidden');
}
function closeDeleteModal() {
document.getElementById('deleteModal').classList.add('hidden');
}
// Close modal when clicking outside
document.getElementById('deleteModal').addEventListener('click', function(e) {
if (e.target === this) {
closeDeleteModal();
}
});
// Close modal on escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeDeleteModal();
}
});
</script>
{% endblock %}