Files
moto-adv-website/app/templates/community/edit_post.html
ske087 f2530a1c5b Update edit_post.html to match modern gradient design of new_post.html
- Applied consistent gradient background styling
- Updated form layout to match new_post design
- Modernized UI components with backdrop blur effects
- Enhanced JavaScript functionality for file uploads
- Improved preview modal styling
- Updated button styling to match site theme
2025-08-09 15:34:40 +03:00

547 lines
27 KiB
HTML

{% extends "base.html" %}
{% block title %}Edit Adventure - {{ post.title }}{% endblock %}
{% block head %}
<style>
.content-section {
border: 2px dashed #d1d5db;
border-radius: 0.75rem;
padding: 1.5rem;
margin-bottom: 1rem;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.05);
}
.content-section.editing {
border-color: #3b82f6;
background: rgba(59, 130, 246, 0.1);
}
.content-section.saved {
border-color: #10b981;
border-style: solid;
background: rgba(16, 185, 129, 0.1);
}
.cover-upload-area {
transition: all 0.3s ease;
cursor: pointer;
}
.cover-upload-area:hover {
background: rgba(255, 255, 255, 0.05);
}
/* Dropdown styling */
select option {
background-color: #1f2937;
color: #ffffff;
}
select option:checked {
background-color: #0891b2;
}
/* Section styling */
.section-actions-frame {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.2);
}
</style>
{% endblock %}
{% block content %}
<div class="min-h-screen bg-gradient-to-br from-blue-900 via-purple-900 to-teal-900 py-12">
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- Header -->
<div class="text-center mb-8">
<h1 class="text-4xl font-bold text-white mb-4">
<i class="fas fa-edit"></i> Edit Your Adventure
</h1>
<p class="text-blue-200 text-lg">
Update your motorcycle journey story - "{{ post.title }}"
</p>
</div>
<!-- Main Form -->
<form id="editPostForm" method="POST" action="{{ url_for('community.edit_post', id=post.id) }}" enctype="multipart/form-data" class="space-y-6">
<!-- Basic Information Section -->
<div class="bg-white/10 backdrop-blur-sm rounded-2xl p-6 border border-white/20">
<h2 class="text-2xl font-bold text-white mb-6">📝 Basic Information</h2>
<!-- Current Cover Image Display -->
{% if post.images %}
{% set cover_image = post.images | selectattr('is_cover', 'equalto', True) | first %}
{% if cover_image %}
<div class="mb-6">
<label class="block text-white font-semibold mb-2">
<i class="fas fa-image text-cyan-400"></i> Current Cover Photo
</label>
<div class="current-cover-preview bg-white/5 rounded-lg p-4 border border-white/20">
<img src="{{ cover_image.get_thumbnail_url() }}" alt="Current cover"
class="max-h-48 mx-auto rounded-lg border-2 border-white/20">
<p class="text-white/80 text-center mt-2 text-sm">{{ cover_image.original_name }}</p>
</div>
</div>
{% endif %}
{% endif %}
<!-- Cover Picture Upload -->
<div class="mb-6">
<label for="cover_picture" class="block text-white font-semibold mb-2">
{% if post.images and post.images | selectattr('is_cover', 'equalto', True) | first %}
Replace Cover Picture
{% else %}
Set Cover Picture for the Post
{% endif %}
</label>
<div class="cover-upload-area border-2 border-dashed border-white/30 rounded-lg p-6 text-center hover:border-white/50 transition-all duration-300">
<input type="file" id="cover_picture" name="cover_picture" accept="image/*" class="hidden">
<div class="cover-upload-content">
<div class="text-4xl mb-2">📸</div>
<p class="text-white/80 mb-2">Click to upload new cover image</p>
<p class="text-sm text-white/60">Recommended: 1920x1080 pixels</p>
</div>
<div class="cover-preview hidden">
<img class="cover-preview-image max-h-48 mx-auto rounded-lg" alt="Cover preview">
<button type="button" class="cover-remove-btn mt-2 px-3 py-1 bg-red-500/80 text-white rounded hover:bg-red-600 transition-colors">Remove</button>
</div>
</div>
</div>
<!-- Title -->
<div class="mb-6">
<label for="title" class="block text-white font-semibold mb-2">Adventure Title *</label>
<input type="text" id="title" name="title" required value="{{ post.title }}"
class="w-full px-4 py-3 rounded-lg bg-white/10 backdrop-blur-sm border border-white/20
text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-cyan-400
focus:border-transparent transition-all duration-300"
placeholder="Give your adventure a captivating title..." maxlength="100">
</div>
<!-- Subtitle -->
<div class="mb-6">
<label for="subtitle" class="block text-white font-semibold mb-2">Subtitle</label>
<input type="text" id="subtitle" name="subtitle" value="{{ post.subtitle or '' }}"
class="w-full px-4 py-3 rounded-lg bg-white/10 backdrop-blur-sm border border-white/20
text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-cyan-400
focus:border-transparent transition-all duration-300"
placeholder="A brief description of your adventure" maxlength="200">
</div>
<!-- Difficulty Rating -->
<div class="mb-6">
<label for="difficulty" class="block text-white font-semibold mb-2">Route Difficulty *</label>
<select id="difficulty" name="difficulty" required
class="w-full px-4 py-3 rounded-lg bg-white/10 backdrop-blur-sm border border-white/20
text-white focus:outline-none focus:ring-2 focus:ring-cyan-400
focus:border-transparent transition-all duration-300">
<option value="" class="bg-gray-800 text-gray-300">Select difficulty level...</option>
<option value="1" {% if post.difficulty == 1 %}selected{% endif %} class="bg-gray-800 text-green-400">🟢 Easy - Beginner friendly roads</option>
<option value="2" {% if post.difficulty == 2 %}selected{% endif %} class="bg-gray-800 text-yellow-400">🟡 Moderate - Some experience needed</option>
<option value="3" {% if post.difficulty == 3 %}selected{% endif %} class="bg-gray-800 text-orange-400">🟠 Challenging - Experienced riders</option>
<option value="4" {% if post.difficulty == 4 %}selected{% endif %} class="bg-gray-800 text-red-400">🔴 Difficult - Advanced skills required</option>
<option value="5" {% if post.difficulty == 5 %}selected{% endif %} class="bg-gray-800 text-purple-400">🟣 Expert - Only for experts</option>
</select>
</div>
</div>
<!-- Adventure Story Section -->
<div class="bg-white/10 backdrop-blur-sm rounded-2xl p-6 border border-white/20">
<h2 class="text-2xl font-bold text-white mb-6">📖 Adventure Story</h2>
<!-- Adventure Story/Content -->
<div class="mb-6">
<label for="content" class="block text-white font-semibold mb-2">
<i class="fas fa-book text-cyan-400"></i> Your Adventure Story *
</label>
<textarea id="content" name="content" rows="8" required
class="w-full px-4 py-3 rounded-lg bg-white/10 backdrop-blur-sm border border-white/20
text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-cyan-400
focus:border-transparent transition-all duration-300"
placeholder="Tell us about your adventure... Where did you go? What did you see? Any challenges or highlights?">{{ post.content }}</textarea>
<div class="text-blue-200 text-sm mt-2">
<i class="fas fa-info-circle"></i>
You can use **bold text** and *italic text* in your story!
</div>
</div>
</div>
<!-- Route File Section -->
<div class="bg-white/10 backdrop-blur-sm rounded-2xl p-6 border border-white/20">
<h2 class="text-2xl font-bold text-white mb-6">🗺️ Route File</h2>
<!-- Current GPX File Display -->
{% if post.gpx_files %}
<div class="mb-6">
<label class="block text-white font-semibold mb-2">
<i class="fas fa-route text-cyan-400"></i> Current GPS Track
</label>
{% for gpx_file in post.gpx_files %}
<div class="current-gpx-file bg-white/5 rounded-lg p-4 border border-white/20">
<div class="flex items-center justify-between">
<div class="flex items-center">
<i class="fas fa-file-alt text-cyan-400 mr-3 text-xl"></i>
<div>
<div class="text-white font-semibold">{{ gpx_file.original_name }}</div>
<div class="text-white/60 text-sm">
Size: {{ "%.1f"|format(gpx_file.size / 1024) }} KB
• Uploaded: {{ gpx_file.created_at.strftime('%Y-%m-%d') }}
</div>
</div>
</div>
<a href="{{ url_for('community.serve_gpx', post_folder=post.media_folder, filename=gpx_file.filename) }}"
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition-colors">
<i class="fas fa-download"></i> Download
</a>
</div>
</div>
{% endfor %}
</div>
{% endif %}
<!-- GPX File Upload -->
<div class="border-2 border-dashed border-white/30 rounded-lg p-8 text-center">
<i class="fas fa-route text-4xl text-blue-300 mb-4"></i>
<div class="text-white font-semibold mb-2">
{% if post.gpx_files %}
Replace GPX Route File
{% else %}
Upload GPX Route File
{% endif %}
</div>
<div class="text-blue-200 text-sm mb-4">
Share your exact route so others can follow your adventure
</div>
<input type="file" id="gpx_file" name="gpx_file" accept=".gpx" class="hidden">
<label for="gpx_file" class="inline-flex items-center px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 cursor-pointer transition">
<i class="fas fa-upload mr-2"></i>
Choose GPX File
</label>
<div id="gpx_info" class="mt-4 text-green-300 hidden"></div>
</div>
</div>
<!-- Guidelines Section -->
<div class="bg-white/10 backdrop-blur-sm rounded-2xl p-6 border border-white/20">
<h2 class="text-2xl font-bold text-white mb-6">
<i class="fas fa-info-circle text-cyan-400"></i> Editing Guidelines
</h2>
<div class="grid md:grid-cols-2 gap-6">
<div>
<h3 class="text-lg font-semibold text-cyan-300 mb-3">
<i class="fas fa-edit"></i> What happens after editing?
</h3>
<p class="text-white/80 text-sm">Your updated post will be resubmitted for admin review before being published again.</p>
</div>
<div>
<h3 class="text-lg font-semibold text-cyan-300 mb-3">
<i class="fas fa-image"></i> Photo Guidelines
</h3>
<ul class="text-white/80 text-sm space-y-1">
<li>• Use high-quality images (JPEG, PNG)</li>
<li>• Landscape orientation works best</li>
<li>• Maximum file size: 10MB</li>
</ul>
</div>
<div>
<h3 class="text-lg font-semibold text-cyan-300 mb-3">
<i class="fas fa-route"></i> GPX File Tips
</h3>
<ul class="text-white/80 text-sm space-y-1">
<li>• Export from your GPS device or app</li>
<li>• Should contain track points</li>
<li>• Will be displayed on the community map</li>
</ul>
</div>
<div>
<h3 class="text-lg font-semibold text-cyan-300 mb-3">
<i class="fas fa-star"></i> Difficulty Levels
</h3>
<div class="text-white/80 text-sm space-y-1">
<div><strong>Easy:</strong> Paved roads, good weather</div>
<div><strong>Moderate:</strong> Some gravel, hills</div>
<div><strong>Challenging:</strong> Off-road, technical</div>
<div><strong>Hard:</strong> Extreme conditions</div>
<div><strong>Expert:</strong> Dangerous, experts only</div>
</div>
</div>
</div>
<div class="mt-6 p-4 bg-yellow-500/20 border border-yellow-400/50 rounded-lg">
<div class="flex items-center text-yellow-300">
<i class="fas fa-exclamation-triangle mr-2"></i>
<strong>Note:</strong> Updating your post will reset its status to "pending review."
</div>
</div>
</div>
<!-- Submit Buttons -->
<div class="text-center space-x-4">
<a href="{{ url_for('community.profile') }}" class="bg-gray-600 hover:bg-gray-700 text-white px-8 py-4 rounded-lg font-bold text-lg transition-all duration-200 shadow-lg inline-block">
<i class="fas fa-arrow-left mr-3"></i>
Cancel
</a>
<button type="button" onclick="previewPost()" class="bg-gradient-to-r from-blue-500 to-indigo-600 text-white px-8 py-4 rounded-lg font-bold text-lg hover:from-blue-600 hover:to-indigo-700 transform hover:scale-105 transition-all duration-200 shadow-lg">
<i class="fas fa-eye mr-3"></i>
Preview Changes
</button>
<button type="submit" class="bg-gradient-to-r from-orange-500 to-red-600 text-white px-12 py-4 rounded-lg font-bold text-lg hover:from-orange-600 hover:to-red-700 transform hover:scale-105 transition-all duration-200 shadow-lg">
<i class="fas fa-paper-plane mr-3"></i>
Update Adventure
</button>
</div>
</form>
</div>
</div>
<!-- Preview Modal -->
<div class="modal fade" id="previewModal" tabindex="-1" aria-labelledby="previewModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content bg-gray-900 text-white border-0">
<div class="modal-header border-gray-700">
<h5 class="modal-title text-white" id="previewModalLabel">
<i class="fas fa-eye text-cyan-400"></i> Adventure Preview
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body bg-gradient-to-br from-blue-900 via-purple-900 to-teal-900">
<div id="previewContent">
<!-- Preview content will be loaded here -->
</div>
</div>
<div class="modal-footer border-gray-700">
<button type="button" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg transition-colors" data-bs-dismiss="modal">Close Preview</button>
<button type="button" class="bg-gradient-to-r from-orange-500 to-red-600 text-white px-6 py-2 rounded-lg hover:from-orange-600 hover:to-red-700 transition-all duration-200" onclick="submitForm()">
<i class="fas fa-paper-plane mr-2"></i> Looks Good - Update Post
</button>
</div>
</div>
</div>
</div>
<!-- JavaScript -->
<script>
// Cover image preview functionality
document.addEventListener('DOMContentLoaded', function() {
const coverInput = document.getElementById('cover_picture');
const coverUploadArea = document.querySelector('.cover-upload-area');
const coverUploadContent = document.querySelector('.cover-upload-content');
const coverPreview = document.querySelector('.cover-preview');
const coverPreviewImage = document.querySelector('.cover-preview-image');
const coverRemoveBtn = document.querySelector('.cover-remove-btn');
// Cover upload click handler
coverUploadArea.addEventListener('click', function() {
coverInput.click();
});
// Cover file change handler
coverInput.addEventListener('change', function(e) {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
coverPreviewImage.src = e.target.result;
coverUploadContent.classList.add('hidden');
coverPreview.classList.remove('hidden');
};
reader.readAsDataURL(file);
}
});
// Cover remove button
coverRemoveBtn.addEventListener('click', function(e) {
e.stopPropagation();
coverInput.value = '';
coverUploadContent.classList.remove('hidden');
coverPreview.classList.add('hidden');
});
// GPX file handler
const gpxInput = document.getElementById('gpx_file');
const gpxInfo = document.getElementById('gpx_info');
gpxInput.addEventListener('change', function(e) {
const file = e.target.files[0];
if (file) {
if (file.name.toLowerCase().endsWith('.gpx')) {
gpxInfo.innerHTML = `
<div class="text-green-300">
<i class="fas fa-check-circle mr-2"></i>
GPX file selected: ${file.name} (${(file.size / 1024).toFixed(1)} KB)
</div>
`;
gpxInfo.classList.remove('hidden');
} else {
gpxInfo.innerHTML = `
<div class="text-red-300">
<i class="fas fa-exclamation-triangle mr-2"></i>
Please select a valid GPX file
</div>
`;
gpxInfo.classList.remove('hidden');
gpxInput.value = '';
}
} else {
gpxInfo.classList.add('hidden');
}
});
});
function previewPost() {
// Get form data
const title = document.getElementById('title').value;
const subtitle = document.getElementById('subtitle').value;
const content = document.getElementById('content').value;
const difficulty = document.getElementById('difficulty').value;
// Get difficulty display
const difficultyOptions = {
'1': { emoji: '🟢', text: 'Easy - Beginner friendly roads' },
'2': { emoji: '🟡', text: 'Moderate - Some experience needed' },
'3': { emoji: '🟠', text: 'Challenging - Experienced riders' },
'4': { emoji: '🔴', text: 'Difficult - Advanced skills required' },
'5': { emoji: '🟣', text: 'Expert - Only for experts' }
};
const difficultyDisplay = difficultyOptions[difficulty] || { emoji: '', text: 'Select difficulty' };
// Format content (simple markdown-like formatting)
const formattedContent = content
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
.replace(/\*(.*?)\*/g, '<em>$1</em>')
.replace(/\n/g, '<br>');
// Generate preview HTML
const previewHTML = `
<div class="post-preview">
<!-- Hero Section -->
<div class="bg-gradient-to-r from-blue-600 to-purple-600 text-white p-8 rounded-2xl mb-6">
<div class="max-w-4xl mx-auto">
<h1 class="text-4xl font-bold mb-4">${title || 'Your Adventure Title'}</h1>
${subtitle ? `<p class="text-xl mb-4 text-blue-100">${subtitle}</p>` : ''}
<div class="flex items-center space-x-4">
<span class="inline-flex items-center px-3 py-1 bg-white/20 rounded-full text-sm font-medium">
${difficultyDisplay.emoji} ${difficultyDisplay.text}
</span>
<span class="text-blue-200">Updated today</span>
</div>
</div>
</div>
<!-- Content Section -->
<div class="max-w-4xl mx-auto">
<div class="grid lg:grid-cols-3 gap-8">
<div class="lg:col-span-2">
<div class="bg-white/10 backdrop-blur-sm rounded-2xl p-6 border border-white/20">
<h3 class="text-2xl font-bold text-white mb-4">Adventure Story</h3>
<div class="text-white/90 leading-relaxed">
${formattedContent || '<em class="text-white/60">No content provided yet...</em>'}
</div>
</div>
</div>
<div class="lg:col-span-1">
<div class="bg-white/10 backdrop-blur-sm rounded-2xl p-6 border border-white/20">
<h5 class="text-xl font-bold text-white mb-4">Adventure Details</h5>
<div class="space-y-3 text-white/80">
<div><strong>Difficulty:</strong> ${difficultyDisplay.emoji} ${difficultyDisplay.text}</div>
<div><strong>Status:</strong> <span class="inline-flex items-center px-2 py-1 bg-yellow-500/20 text-yellow-300 rounded-full text-sm">Pending Review</span></div>
<div><strong>Last Updated:</strong> Today</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
// Show preview in modal
document.getElementById('previewContent').innerHTML = previewHTML;
const modal = new bootstrap.Modal(document.getElementById('previewModal'));
modal.show();
}
function submitForm() {
document.getElementById('editPostForm').submit();
}
// Form submission with enhanced feedback
document.getElementById('editPostForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
const submitButton = this.querySelector('button[type="submit"]');
const originalText = submitButton.innerHTML;
// Show loading state
submitButton.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Updating...';
submitButton.disabled = true;
fetch(this.action, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Show success message
const alert = document.createElement('div');
alert.className = 'fixed top-4 right-4 bg-green-500 text-white p-4 rounded-lg shadow-lg z-50';
alert.innerHTML = `
<div class="flex items-center">
<i class="fas fa-check-circle mr-2"></i>
${data.message}
</div>
`;
document.body.appendChild(alert);
// Remove alert and redirect after delay
setTimeout(() => {
alert.remove();
window.location.href = data.redirect_url;
}, 2000);
} else {
// Show error message
const alert = document.createElement('div');
alert.className = 'fixed top-4 right-4 bg-red-500 text-white p-4 rounded-lg shadow-lg z-50';
alert.innerHTML = `
<div class="flex items-center">
<i class="fas fa-exclamation-triangle mr-2"></i>
${data.error}
<button onclick="this.parentElement.parentElement.remove()" class="ml-4 text-white hover:text-gray-300">
<i class="fas fa-times"></i>
</button>
</div>
`;
document.body.appendChild(alert);
}
})
.catch(error => {
console.error('Error:', error);
const alert = document.createElement('div');
alert.className = 'fixed top-4 right-4 bg-red-500 text-white p-4 rounded-lg shadow-lg z-50';
alert.innerHTML = `
<div class="flex items-center">
<i class="fas fa-exclamation-triangle mr-2"></i>
An error occurred while updating your post.
<button onclick="this.parentElement.parentElement.remove()" class="ml-4 text-white hover:text-gray-300">
<i class="fas fa-times"></i>
</button>
</div>
`;
document.body.appendChild(alert);
})
.finally(() => {
// Restore button state
submitButton.innerHTML = originalText;
submitButton.disabled = false;
});
});
</script>
{% endblock %}