mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-23 06:11:09 -05:00
Implement wiki and parks plugin architecture: add initial app configurations, models, and update dependencies
This commit is contained in:
87
templates/base_wiki.html
Normal file
87
templates/base_wiki.html
Normal file
@@ -0,0 +1,87 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load sekizai_tags %}
|
||||
|
||||
{% block title %}
|
||||
{% block wiki_pagetitle %}{% endblock %} - ThrillWiki
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
{% render_block "css" %}
|
||||
<!-- Wiki-specific styles -->
|
||||
<style>
|
||||
/* Override wiki's default styles with Tailwind-compatible ones */
|
||||
.wiki-article img {
|
||||
@apply max-w-full h-auto;
|
||||
}
|
||||
.wiki-article pre {
|
||||
@apply bg-gray-50 p-4 rounded-lg overflow-x-auto;
|
||||
}
|
||||
.wiki-article blockquote {
|
||||
@apply border-l-4 border-gray-300 pl-4 italic my-4;
|
||||
}
|
||||
.wiki-article ul {
|
||||
@apply list-disc list-inside;
|
||||
}
|
||||
.wiki-article ol {
|
||||
@apply list-decimal list-inside;
|
||||
}
|
||||
.wiki-article table {
|
||||
@apply min-w-full divide-y divide-gray-200;
|
||||
}
|
||||
.wiki-article th {
|
||||
@apply px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider;
|
||||
}
|
||||
.wiki-article td {
|
||||
@apply px-6 py-4 whitespace-nowrap text-sm text-gray-900;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="min-h-screen bg-gray-50">
|
||||
<!-- Wiki Navigation -->
|
||||
<nav class="bg-white shadow-sm border-b border-gray-200">
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="flex justify-between items-center py-3">
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="{% url 'wiki:root' %}" class="text-gray-900 hover:text-blue-600">
|
||||
Wiki Home
|
||||
</a>
|
||||
{% if article and not article.current_revision.deleted %}
|
||||
<span class="text-gray-400">/</span>
|
||||
<a href="{% url 'wiki:get' path=article.get_absolute_url %}" class="text-gray-900 hover:text-blue-600">
|
||||
{{ article.current_revision.title }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
{% if user.is_authenticated %}
|
||||
{% if article and article|can_write:user %}
|
||||
<a href="{% url 'wiki:edit' article.id %}"
|
||||
class="text-sm text-gray-700 hover:text-blue-600">
|
||||
Edit
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if article %}
|
||||
<a href="{% url 'wiki:history' article.id %}"
|
||||
class="text-sm text-gray-700 hover:text-blue-600">
|
||||
History
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main Content -->
|
||||
{% block wiki_body %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
{% render_block "js" %}
|
||||
<!-- Any additional wiki-specific scripts -->
|
||||
{% endblock %}
|
||||
101
templates/wiki/base.html
Normal file
101
templates/wiki/base.html
Normal file
@@ -0,0 +1,101 @@
|
||||
{% extends "base_wiki.html" %}
|
||||
{% load static %}
|
||||
{% load sekizai_tags %}
|
||||
{% load wiki_tags %}
|
||||
|
||||
{% block wiki_body %}
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="flex flex-wrap -mx-4">
|
||||
<!-- Sidebar -->
|
||||
<div class="w-full lg:w-1/4 px-4 mb-8 lg:mb-0">
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
{% block wiki_sidebar %}
|
||||
<div class="space-y-4">
|
||||
{% wiki_sidebar %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="w-full lg:w-3/4 px-4">
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
{% if messages %}
|
||||
<div class="messages mb-6">
|
||||
{% for message in messages %}
|
||||
<div class="p-4 mb-4 rounded-lg {% if message.tags == 'error' %}bg-red-100 text-red-700{% else %}bg-green-100 text-green-700{% endif %}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Article Title -->
|
||||
{% block wiki_page_header %}
|
||||
<div class="border-b border-gray-200 pb-4 mb-6">
|
||||
<h1 class="text-3xl font-bold text-gray-900">
|
||||
{% block wiki_header_title %}{% endblock %}
|
||||
</h1>
|
||||
{% block wiki_header_actions %}{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
<!-- Article Content -->
|
||||
{% block wiki_contents %}
|
||||
<div class="prose max-w-none">
|
||||
{% block wiki_content %}{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Actions -->
|
||||
{% block wiki_footer_actions %}
|
||||
<div class="container mx-auto px-4 py-4">
|
||||
<div class="flex justify-end space-x-4">
|
||||
{% if article|can_write:user %}
|
||||
<a href="{% url 'wiki:edit' article.id %}"
|
||||
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">
|
||||
Edit Article
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if article|can_delete:user %}
|
||||
<a href="{% url 'wiki:delete' article.id %}"
|
||||
class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors">
|
||||
Delete Article
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block wiki_footer %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block wiki_scripts %}
|
||||
{% addtoblock "js" %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
// Add Tailwind classes to wiki-generated content
|
||||
const wikiContent = document.querySelector('.wiki-article');
|
||||
if (wikiContent) {
|
||||
// Add prose styling to article content
|
||||
wikiContent.classList.add('prose', 'max-w-none');
|
||||
|
||||
// Style tables
|
||||
wikiContent.querySelectorAll('table').forEach(table => {
|
||||
table.classList.add('min-w-full', 'divide-y', 'divide-gray-200');
|
||||
});
|
||||
|
||||
// Style links
|
||||
wikiContent.querySelectorAll('a').forEach(link => {
|
||||
link.classList.add('text-blue-600', 'hover:text-blue-800');
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endaddtoblock %}
|
||||
{% endblock %}
|
||||
106
templates/wiki/parks/park_article.html
Normal file
106
templates/wiki/parks/park_article.html
Normal file
@@ -0,0 +1,106 @@
|
||||
{% extends "wiki/base.html" %}
|
||||
{% load wiki_tags %}
|
||||
{% load static %}
|
||||
|
||||
{% block wiki_header_title %}
|
||||
{{ article.current_revision.title }}
|
||||
{% endblock %}
|
||||
|
||||
{% block wiki_content %}
|
||||
<article class="park-article">
|
||||
<!-- Park Header -->
|
||||
<div class="mb-8">
|
||||
{% if article.image %}
|
||||
<div class="mb-4">
|
||||
<img src="{{ article.image.url }}" alt="{{ article.current_revision.title }}"
|
||||
class="w-full h-64 object-cover rounded-lg shadow-md">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Park Quick Info -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 bg-gray-50 p-4 rounded-lg">
|
||||
{% if article.metadata.location %}
|
||||
<div class="park-info-item">
|
||||
<span class="text-gray-600 font-medium">Location:</span>
|
||||
<span class="text-gray-900">{{ article.metadata.location }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if article.metadata.opened %}
|
||||
<div class="park-info-item">
|
||||
<span class="text-gray-600 font-medium">Opened:</span>
|
||||
<span class="text-gray-900">{{ article.metadata.opened }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if article.metadata.operator %}
|
||||
<div class="park-info-item">
|
||||
<span class="text-gray-600 font-medium">Operator:</span>
|
||||
<span class="text-gray-900">{{ article.metadata.operator }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Park Content -->
|
||||
<div class="park-content prose max-w-none">
|
||||
{{ article.render|safe }}
|
||||
</div>
|
||||
|
||||
<!-- Featured Rides -->
|
||||
{% if article.related_articles.rides %}
|
||||
<div class="mt-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Featured Rides</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{% for ride in article.related_articles.rides %}
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
{% if ride.image %}
|
||||
<img src="{{ ride.image.url }}" alt="{{ ride.title }}"
|
||||
class="w-full h-48 object-cover">
|
||||
{% endif %}
|
||||
<div class="p-4">
|
||||
<h3 class="text-lg font-semibold text-gray-900">
|
||||
<a href="{{ ride.get_absolute_url }}" class="hover:text-blue-600">
|
||||
{{ ride.title }}
|
||||
</a>
|
||||
</h3>
|
||||
<p class="text-gray-600 text-sm mt-2">
|
||||
{{ ride.description|truncatewords:30 }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Park Stats and Info -->
|
||||
{% if article.metadata.stats %}
|
||||
<div class="mt-8 bg-gray-50 rounded-lg p-6">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Park Statistics</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{% for stat, value in article.metadata.stats.items %}
|
||||
<div class="stat-item">
|
||||
<span class="text-gray-600 font-medium">{{ stat|title }}:</span>
|
||||
<span class="text-gray-900">{{ value }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</article>
|
||||
{% endblock %}
|
||||
|
||||
{% block wiki_sidebar %}
|
||||
{{ block.super }}
|
||||
<!-- Additional park-specific sidebar content -->
|
||||
<div class="mt-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-3">Quick Links</h3>
|
||||
<ul class="space-y-2">
|
||||
<li><a href="#rides" class="text-gray-600 hover:text-blue-600">Rides</a></li>
|
||||
<li><a href="#attractions" class="text-gray-600 hover:text-blue-600">Attractions</a></li>
|
||||
<li><a href="#dining" class="text-gray-600 hover:text-blue-600">Dining</a></li>
|
||||
<li><a href="#hotels" class="text-gray-600 hover:text-blue-600">Hotels</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock %}
|
||||
84
templates/wiki/plugins/parks/park_actions.html
Normal file
84
templates/wiki/plugins/parks/park_actions.html
Normal file
@@ -0,0 +1,84 @@
|
||||
{% load wiki_tags %}
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<div class="flex justify-end gap-2 mb-2">
|
||||
<!-- Wiki Article Actions -->
|
||||
{% if article|can_write:user %}
|
||||
<a href="{% url 'wiki:edit' article.id %}"
|
||||
class="transition-transform btn-secondary hover:scale-105">
|
||||
<i class="mr-1 fas fa-pencil-alt"></i>Edit Article
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<!-- Park Metadata Actions -->
|
||||
{% if park_metadata or article|can_write:user %}
|
||||
<a href="{% url 'wiki:parks_metadata' article.id %}"
|
||||
class="transition-transform btn-secondary hover:scale-105">
|
||||
<i class="mr-1 fas fa-info-circle"></i>Park Info
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<!-- Statistics Management -->
|
||||
{% if park_metadata and article|can_write:user %}
|
||||
<a href="{% url 'wiki:parks_statistics' article.id %}"
|
||||
class="transition-transform btn-secondary hover:scale-105">
|
||||
<i class="mr-1 fas fa-chart-bar"></i>Statistics
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<!-- Media Management -->
|
||||
{% if article|can_write:user %}
|
||||
<button class="transition-transform btn-secondary hover:scale-105"
|
||||
@click="$dispatch('show-wiki-media-upload')">
|
||||
<i class="mr-1 fas fa-camera"></i>Add Media
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
<!-- Article Tools -->
|
||||
<div class="dropdown relative inline-block">
|
||||
<button class="transition-transform btn-secondary hover:scale-105">
|
||||
<i class="mr-1 fas fa-ellipsis-v"></i>More
|
||||
</button>
|
||||
<div class="dropdown-content hidden absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg">
|
||||
<!-- History -->
|
||||
<a href="{% url 'wiki:history' article.id %}"
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="mr-1 fas fa-history"></i>History
|
||||
</a>
|
||||
|
||||
<!-- Discussion -->
|
||||
<a href="{% url 'wiki:discussion' article.id %}"
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="mr-1 fas fa-comments"></i>Discussion
|
||||
</a>
|
||||
|
||||
<!-- Settings -->
|
||||
{% if article|can_moderate:user %}
|
||||
<a href="{% url 'wiki:settings' article.id %}"
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="mr-1 fas fa-cog"></i>Settings
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<!-- Permissions -->
|
||||
{% if article|can_moderate:user %}
|
||||
<a href="{% url 'wiki:permissions' article.id %}"
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="mr-1 fas fa-lock"></i>Permissions
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notification Area -->
|
||||
{% if messages %}
|
||||
<div class="mt-4">
|
||||
{% for message in messages %}
|
||||
<div class="p-4 mb-4 rounded-lg {% if message.tags == 'error' %}bg-red-100 text-red-700{% else %}bg-green-100 text-green-700{% endif %}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
200
templates/wiki/plugins/parks/park_metadata.html
Normal file
200
templates/wiki/plugins/parks/park_metadata.html
Normal file
@@ -0,0 +1,200 @@
|
||||
{% extends "wiki/article.html" %}
|
||||
{% load i18n %}
|
||||
{% load wiki_tags %}
|
||||
{% load static %}
|
||||
|
||||
{% block wiki_contents_tab %}
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
<h2 class="text-2xl font-bold mb-6">{% trans "Park Metadata" %}</h2>
|
||||
|
||||
<form method="POST" class="space-y-6">
|
||||
{% csrf_token %}
|
||||
|
||||
<!-- Basic Information -->
|
||||
<div class="bg-gray-50 p-4 rounded-lg">
|
||||
<h3 class="text-lg font-semibold mb-4">{% trans "Basic Information" %}</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="form-group">
|
||||
{{ form.operator.label_tag }}
|
||||
{{ form.operator }}
|
||||
{{ form.operator.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.owner.label_tag }}
|
||||
{{ form.owner }}
|
||||
{{ form.owner.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.opened_date.label_tag }}
|
||||
{{ form.opened_date }}
|
||||
{{ form.opened_date.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.park_size.label_tag }}
|
||||
{{ form.park_size }}
|
||||
{{ form.park_size.errors }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Location Information -->
|
||||
<div class="bg-gray-50 p-4 rounded-lg">
|
||||
<h3 class="text-lg font-semibold mb-4">{% trans "Location" %}</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="form-group">
|
||||
{{ form.latitude.label_tag }}
|
||||
{{ form.latitude }}
|
||||
{{ form.latitude.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.longitude.label_tag }}
|
||||
{{ form.longitude }}
|
||||
{{ form.longitude.errors }}
|
||||
</div>
|
||||
<div class="form-group col-span-2">
|
||||
{{ form.address.label_tag }}
|
||||
{{ form.address }}
|
||||
{{ form.address.errors }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Operating Information -->
|
||||
<div class="bg-gray-50 p-4 rounded-lg">
|
||||
<h3 class="text-lg font-semibold mb-4">{% trans "Operating Information" %}</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="form-group">
|
||||
{{ form.seasonal.label_tag }}
|
||||
{{ form.seasonal }}
|
||||
{{ form.seasonal.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.season_start.label_tag }}
|
||||
{{ form.season_start }}
|
||||
{{ form.season_start.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.season_end.label_tag }}
|
||||
{{ form.season_end }}
|
||||
{{ form.season_end.errors }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Attractions -->
|
||||
<div class="bg-gray-50 p-4 rounded-lg">
|
||||
<h3 class="text-lg font-semibold mb-4">{% trans "Attractions" %}</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="form-group">
|
||||
{{ form.total_rides.label_tag }}
|
||||
{{ form.total_rides }}
|
||||
{{ form.total_rides.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.total_roller_coasters.label_tag }}
|
||||
{{ form.total_roller_coasters }}
|
||||
{{ form.total_roller_coasters.errors }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contact Information -->
|
||||
<div class="bg-gray-50 p-4 rounded-lg">
|
||||
<h3 class="text-lg font-semibold mb-4">{% trans "Contact Information" %}</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="form-group">
|
||||
{{ form.phone.label_tag }}
|
||||
{{ form.phone }}
|
||||
{{ form.phone.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.email.label_tag }}
|
||||
{{ form.email }}
|
||||
{{ form.email.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.website.label_tag }}
|
||||
{{ form.website }}
|
||||
{{ form.website.errors }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Social Media -->
|
||||
<div class="bg-gray-50 p-4 rounded-lg">
|
||||
<h3 class="text-lg font-semibold mb-4">{% trans "Social Media" %}</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="form-group">
|
||||
{{ form.facebook.label_tag }}
|
||||
{{ form.facebook }}
|
||||
{{ form.facebook.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.twitter.label_tag }}
|
||||
{{ form.twitter }}
|
||||
{{ form.twitter.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.instagram.label_tag }}
|
||||
{{ form.instagram }}
|
||||
{{ form.instagram.errors }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Additional Information -->
|
||||
<div class="bg-gray-50 p-4 rounded-lg">
|
||||
<h3 class="text-lg font-semibold mb-4">{% trans "Additional Information" %}</h3>
|
||||
<div class="space-y-4">
|
||||
<div class="form-group">
|
||||
{{ form.amenities_text.label_tag }}
|
||||
{{ form.amenities_text }}
|
||||
{{ form.amenities_text.errors }}
|
||||
<p class="text-sm text-gray-600 mt-1">{{ form.amenities_text.help_text }}</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.ticket_info_text.label_tag }}
|
||||
{{ form.ticket_info_text }}
|
||||
{{ form.ticket_info_text.errors }}
|
||||
<p class="text-sm text-gray-600 mt-1">{{ form.ticket_info_text.help_text }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<div class="flex justify-end space-x-4">
|
||||
<a href="{% url 'wiki:get' path=article.get_absolute_url %}"
|
||||
class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50">
|
||||
{% trans "Cancel" %}
|
||||
</a>
|
||||
<button type="submit"
|
||||
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
|
||||
{% trans "Save Changes" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block wiki_footer_script %}
|
||||
{{ block.super }}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Handle seasonal checkbox toggling season dates
|
||||
const seasonalCheckbox = document.getElementById('id_seasonal');
|
||||
const seasonStartInput = document.getElementById('id_season_start');
|
||||
const seasonEndInput = document.getElementById('id_season_end');
|
||||
|
||||
function toggleSeasonDates() {
|
||||
const isDisabled = !seasonalCheckbox.checked;
|
||||
seasonStartInput.disabled = isDisabled;
|
||||
seasonEndInput.disabled = isDisabled;
|
||||
}
|
||||
|
||||
if (seasonalCheckbox) {
|
||||
toggleSeasonDates();
|
||||
seasonalCheckbox.addEventListener('change', toggleSeasonDates);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
146
templates/wiki/plugins/parks/park_statistics.html
Normal file
146
templates/wiki/plugins/parks/park_statistics.html
Normal file
@@ -0,0 +1,146 @@
|
||||
{% extends "wiki/article.html" %}
|
||||
{% load i18n %}
|
||||
{% load wiki_tags %}
|
||||
{% load static %}
|
||||
|
||||
{% block wiki_contents_tab %}
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
<h2 class="text-2xl font-bold mb-6">{% trans "Park Statistics" %}</h2>
|
||||
|
||||
<!-- Add New Statistics -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-lg font-semibold mb-4">{% trans "Add New Statistics" %}</h3>
|
||||
<form method="POST" class="bg-gray-50 p-4 rounded-lg">
|
||||
{% csrf_token %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<div class="form-group">
|
||||
{{ form.year.label_tag }}
|
||||
{{ form.year }}
|
||||
{{ form.year.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.attendance.label_tag }}
|
||||
{{ form.attendance }}
|
||||
{{ form.attendance.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.revenue.label_tag }}
|
||||
{{ form.revenue }}
|
||||
{{ form.revenue.errors }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.investment.label_tag }}
|
||||
{{ form.investment }}
|
||||
{{ form.investment.errors }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button type="submit"
|
||||
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
|
||||
{% trans "Add Statistics" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Statistics History -->
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold mb-4">{% trans "Historical Statistics" %}</h3>
|
||||
{% if statistics %}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
{% trans "Year" %}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
{% trans "Attendance" %}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
{% trans "Revenue" %}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
{% trans "Investment" %}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
{% trans "Actions" %}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
{% for stat in statistics %}
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
||||
{{ stat.year }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ stat.attendance|default:"-" }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{% if stat.revenue %}
|
||||
${{ stat.revenue }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{% if stat.investment %}
|
||||
${{ stat.investment }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
<form method="POST" action="{% url 'wiki:parks_delete_statistic' article.id stat.id %}"
|
||||
class="inline-block">
|
||||
{% csrf_token %}
|
||||
<button type="submit"
|
||||
class="text-red-600 hover:text-red-900"
|
||||
onclick="return confirm('{% trans "Are you sure you want to delete this statistic?" %}')">
|
||||
{% trans "Delete" %}
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-gray-500 italic">{% trans "No statistics available." %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Back to Article -->
|
||||
<div class="mt-8">
|
||||
<a href="{% url 'wiki:get' path=article.get_absolute_url %}"
|
||||
class="inline-block px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50">
|
||||
{% trans "Back to Article" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block wiki_footer_script %}
|
||||
{{ block.super }}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Auto-fill current year if empty
|
||||
const yearInput = document.getElementById('id_year');
|
||||
if (yearInput && !yearInput.value) {
|
||||
yearInput.value = new Date().getFullYear();
|
||||
}
|
||||
|
||||
// Format number inputs
|
||||
const numberInputs = document.querySelectorAll('input[type="number"]');
|
||||
numberInputs.forEach(input => {
|
||||
input.addEventListener('blur', function() {
|
||||
if (this.value) {
|
||||
this.value = parseInt(this.value).toLocaleString();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
146
templates/wiki/plugins/parks/sidebar.html
Normal file
146
templates/wiki/plugins/parks/sidebar.html
Normal file
@@ -0,0 +1,146 @@
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
|
||||
<div class="park-sidebar">
|
||||
<!-- Quick Stats -->
|
||||
<div class="bg-gray-50 p-4 rounded-lg mb-4">
|
||||
{% if article.park_metadata %}
|
||||
<div class="space-y-3">
|
||||
{% if article.park_metadata.operator %}
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-gray-600">{% trans "Operator" %}</span>
|
||||
<span class="text-sm font-medium">{{ article.park_metadata.operator }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if article.park_metadata.opened_date %}
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-gray-600">{% trans "Opened" %}</span>
|
||||
<span class="text-sm font-medium">{{ article.park_metadata.opened_date|date:"Y" }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if article.park_metadata.total_rides %}
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-gray-600">{% trans "Total Rides" %}</span>
|
||||
<span class="text-sm font-medium">{{ article.park_metadata.total_rides }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if article.park_metadata.total_roller_coasters %}
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-gray-600">{% trans "Roller Coasters" %}</span>
|
||||
<span class="text-sm font-medium">{{ article.park_metadata.total_roller_coasters }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if article.park_metadata.park_size %}
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-gray-600">{% trans "Size" %}</span>
|
||||
<span class="text-sm font-medium">{{ article.park_metadata.park_size }} {% trans "acres" %}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Season Info -->
|
||||
{% if article.park_metadata.seasonal %}
|
||||
<div class="mt-4 pt-4 border-t border-gray-200">
|
||||
<h4 class="text-sm font-medium text-gray-900 mb-2">{% trans "Season" %}</h4>
|
||||
<div class="text-sm text-gray-600">
|
||||
{% if article.park_metadata.season_start and article.park_metadata.season_end %}
|
||||
{{ article.park_metadata.season_start|date:"M j" }} - {{ article.park_metadata.season_end|date:"M j" }}
|
||||
{% else %}
|
||||
{% trans "Seasonal operation" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Contact -->
|
||||
{% if article.park_metadata.phone or article.park_metadata.email or article.park_metadata.website %}
|
||||
<div class="mt-4 pt-4 border-t border-gray-200">
|
||||
<h4 class="text-sm font-medium text-gray-900 mb-2">{% trans "Contact" %}</h4>
|
||||
<div class="space-y-2">
|
||||
{% if article.park_metadata.phone %}
|
||||
<div class="text-sm">
|
||||
<a href="tel:{{ article.park_metadata.phone }}"
|
||||
class="text-blue-600 hover:text-blue-800">
|
||||
{{ article.park_metadata.phone }}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if article.park_metadata.website %}
|
||||
<div class="text-sm">
|
||||
<a href="{{ article.park_metadata.website }}"
|
||||
class="text-blue-600 hover:text-blue-800"
|
||||
target="_blank" rel="noopener">
|
||||
{% trans "Official Website" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Social Media -->
|
||||
{% if article.park_metadata.facebook or article.park_metadata.twitter or article.park_metadata.instagram %}
|
||||
<div class="mt-4 pt-4 border-t border-gray-200">
|
||||
<h4 class="text-sm font-medium text-gray-900 mb-2">{% trans "Social Media" %}</h4>
|
||||
<div class="flex space-x-4">
|
||||
{% if article.park_metadata.facebook %}
|
||||
<a href="{{ article.park_metadata.facebook }}"
|
||||
class="text-gray-400 hover:text-blue-600"
|
||||
target="_blank" rel="noopener">
|
||||
<i class="fab fa-facebook"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if article.park_metadata.twitter %}
|
||||
<a href="{{ article.park_metadata.twitter }}"
|
||||
class="text-gray-400 hover:text-blue-400"
|
||||
target="_blank" rel="noopener">
|
||||
<i class="fab fa-twitter"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if article.park_metadata.instagram %}
|
||||
<a href="{{ article.park_metadata.instagram }}"
|
||||
class="text-gray-400 hover:text-pink-600"
|
||||
target="_blank" rel="noopener">
|
||||
<i class="fab fa-instagram"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<p class="text-sm text-gray-500 italic">
|
||||
{% trans "No park metadata available." %}
|
||||
{% if article|can_write:user %}
|
||||
<a href="{% url 'wiki:parks_metadata' article.id %}"
|
||||
class="text-blue-600 hover:text-blue-800">
|
||||
{% trans "Add metadata" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Admin Actions -->
|
||||
{% if article|can_write:user %}
|
||||
<div class="space-y-2">
|
||||
<a href="{% url 'wiki:parks_metadata' article.id %}"
|
||||
class="block w-full px-4 py-2 text-sm text-center bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200">
|
||||
{% trans "Edit Park Information" %}
|
||||
</a>
|
||||
{% if article.park_metadata %}
|
||||
<a href="{% url 'wiki:parks_statistics' article.id %}"
|
||||
class="block w-full px-4 py-2 text-sm text-center bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200">
|
||||
{% trans "Manage Statistics" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
126
templates/wiki/rides/ride_article.html
Normal file
126
templates/wiki/rides/ride_article.html
Normal file
@@ -0,0 +1,126 @@
|
||||
{% extends "wiki/base.html" %}
|
||||
{% load wiki_tags %}
|
||||
{% load static %}
|
||||
|
||||
{% block wiki_header_title %}
|
||||
{{ article.current_revision.title }}
|
||||
{% endblock %}
|
||||
|
||||
{% block wiki_content %}
|
||||
<article class="ride-article">
|
||||
<!-- Ride Header -->
|
||||
<div class="mb-8">
|
||||
{% if article.image %}
|
||||
<div class="mb-4">
|
||||
<img src="{{ article.image.url }}" alt="{{ article.current_revision.title }}"
|
||||
class="w-full h-64 object-cover rounded-lg shadow-md">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Ride Quick Info -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 bg-gray-50 p-4 rounded-lg">
|
||||
{% if article.metadata.park %}
|
||||
<div class="ride-info-item">
|
||||
<span class="text-gray-600 font-medium">Park:</span>
|
||||
<a href="{{ article.metadata.park.get_absolute_url }}"
|
||||
class="text-blue-600 hover:text-blue-800">
|
||||
{{ article.metadata.park.name }}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if article.metadata.opened %}
|
||||
<div class="ride-info-item">
|
||||
<span class="text-gray-600 font-medium">Opened:</span>
|
||||
<span class="text-gray-900">{{ article.metadata.opened }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if article.metadata.manufacturer %}
|
||||
<div class="ride-info-item">
|
||||
<span class="text-gray-600 font-medium">Manufacturer:</span>
|
||||
<span class="text-gray-900">{{ article.metadata.manufacturer }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if article.metadata.type %}
|
||||
<div class="ride-info-item">
|
||||
<span class="text-gray-600 font-medium">Type:</span>
|
||||
<span class="text-gray-900">{{ article.metadata.type }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ride Content -->
|
||||
<div class="ride-content prose max-w-none">
|
||||
{{ article.render|safe }}
|
||||
</div>
|
||||
|
||||
<!-- Technical Specifications -->
|
||||
{% if article.metadata.specs %}
|
||||
<div class="mt-8 bg-gray-50 rounded-lg p-6">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Technical Specifications</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{% for spec, value in article.metadata.specs.items %}
|
||||
<div class="spec-item">
|
||||
<span class="text-gray-600 font-medium">{{ spec|title }}:</span>
|
||||
<span class="text-gray-900">{{ value }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Records and Statistics -->
|
||||
{% if article.metadata.records %}
|
||||
<div class="mt-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Records & Achievements</h2>
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
<ul class="space-y-3">
|
||||
{% for record in article.metadata.records %}
|
||||
<li class="flex items-start">
|
||||
<svg class="w-6 h-6 text-blue-600 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
<span>{{ record }}</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</article>
|
||||
{% endblock %}
|
||||
|
||||
{% block wiki_sidebar %}
|
||||
{{ block.super }}
|
||||
<!-- Additional ride-specific sidebar content -->
|
||||
<div class="mt-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-3">Quick Links</h3>
|
||||
<ul class="space-y-2">
|
||||
<li><a href="#specifications" class="text-gray-600 hover:text-blue-600">Specifications</a></li>
|
||||
<li><a href="#history" class="text-gray-600 hover:text-blue-600">History</a></li>
|
||||
<li><a href="#experience" class="text-gray-600 hover:text-blue-600">Ride Experience</a></li>
|
||||
<li><a href="#records" class="text-gray-600 hover:text-blue-600">Records</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Related Rides -->
|
||||
{% if article.related_articles.similar_rides %}
|
||||
<div class="mt-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-3">Similar Rides</h3>
|
||||
<ul class="space-y-2">
|
||||
{% for ride in article.related_articles.similar_rides %}
|
||||
<li>
|
||||
<a href="{{ ride.get_absolute_url }}"
|
||||
class="text-gray-600 hover:text-blue-600">
|
||||
{{ ride.title }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user