247 lines
12 KiB
HTML
247 lines
12 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
{% load markdown %}
|
|
|
|
{% block title %}{{ project.title }} - Packs Site{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="project-header card">
|
|
<div class="project-avatar">
|
|
{% if project.thumbnail %}
|
|
<img src="{{ project.thumbnail_url }}" alt="{{ project.title }}">
|
|
{% else %}
|
|
<div class="default-avatar large">{{ project.title|first|upper }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="project-header-main">
|
|
<div class="project-title-row">
|
|
<h1>{{ project.title }}</h1>
|
|
<span class="category-badge">{{ project.get_category_display }}</span>
|
|
<span class="project-id-badge" title="Project ID">#{{ project.pk }}</span>
|
|
</div>
|
|
{% if project.summary %}<p class="project-summary">{{ project.summary }}</p>{% endif %}
|
|
<div class="project-meta">
|
|
<span class="project-owner"><i class="fas fa-user"></i>
|
|
<a href="{% url 'profiles:user_profile' project.owner.username %}">{{ project.owner.username }}</a>
|
|
</span>
|
|
<span class="project-stat"><i class="fas fa-download"></i> {{ project.downloads }}</span>
|
|
<span class="project-stat"><i class="fas fa-tag"></i> {{ versions|length }} version{{ versions|length|pluralize }}</span>
|
|
</div>
|
|
{% if can_edit %}
|
|
<div class="project-actions">
|
|
<a href="{% url 'library:version_upload' project.slug %}" class="btn btn-primary"><i class="fas fa-upload"></i> New version</a>
|
|
<a href="{% url 'library:asset_upload' project.slug %}" class="btn btn-secondary"><i class="fas fa-images"></i> Add media</a>
|
|
<a href="{% url 'library:project_edit' project.slug %}" class="btn btn-secondary"><i class="fas fa-pen"></i> Edit</a>
|
|
{% if request.user == project.owner %}
|
|
<a href="{% url 'library:contributors' project.slug %}" class="btn btn-secondary"><i class="fas fa-users"></i> Contributors</a>
|
|
<a href="{% url 'library:project_delete' project.slug %}" class="btn btn-danger"><i class="fas fa-trash"></i></a>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
{% if tags %}
|
|
<div class="project-tags card">
|
|
{% regroup tags by tag.category as tag_groups %}
|
|
{% for group in tag_groups %}
|
|
<div class="tag-group">
|
|
<span class="tag-group-label">
|
|
<span class="tag-dot" style="background: {{ group.grouper.color }};"></span>
|
|
{{ group.grouper.name }}
|
|
</span>
|
|
{% for link in group.list %}
|
|
<a href="{% url 'library:browse' %}?tag={{ link.tag.name }}" class="tag-chip"
|
|
style="border-color: {{ group.grouper.color }}; color: {{ group.grouper.color }};">{{ link.tag.name }}</a>
|
|
{% endfor %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="tab-bar" role="tablist">
|
|
<button class="tab-btn active" data-tab="{% if project.category == 'guide' %}guide{% else %}description{% endif %}" role="tab">
|
|
{% if project.category == 'guide' %}Guide{% else %}Description{% endif %}
|
|
</button>
|
|
<button class="tab-btn" data-tab="versions" role="tab">Versions</button>
|
|
{% if project.category == 'modpack' %}<button class="tab-btn" data-tab="mods" role="tab">Mods</button>{% endif %}
|
|
<button class="tab-btn" data-tab="gallery" role="tab">Gallery</button>
|
|
</div>
|
|
|
|
<section class="tab-panel active" id="tab-{% if project.category == 'guide' %}guide{% else %}description{% endif %}">
|
|
<div class="card">
|
|
{% if project.category == 'guide' %}
|
|
<div class="guide-docs">
|
|
{% if guide_docs %}
|
|
<div class="guide-switcher" role="tablist">
|
|
{% for doc in guide_docs %}
|
|
<button type="button" class="guide-switch-btn{% if forloop.first %} active{% endif %}"
|
|
data-url="{% url 'library:guide_doc' project.slug doc.version.pk doc.file.uuid %}">{{ doc.filename }}</button>
|
|
{% endfor %}
|
|
</div>
|
|
<div class="markdown-body guide-content" id="guide-content">
|
|
<p class="empty-hint">Loading…</p>
|
|
</div>
|
|
{% else %}
|
|
<p class="empty-hint">No guide documents uploaded yet.</p>
|
|
{% endif %}
|
|
</div>
|
|
{% elif project.description %}
|
|
<div class="markdown-body project-description">{{ project.description|markdown }}</div>
|
|
{% else %}
|
|
<p class="empty-hint">No description yet.</p>
|
|
{% endif %}
|
|
</div>
|
|
</section>
|
|
|
|
<section class="tab-panel" id="tab-versions">
|
|
<div class="card">
|
|
<h2><i class="fas fa-history"></i> Versions</h2>
|
|
{% for version in versions %}
|
|
<div class="version-row">
|
|
<div class="version-info">
|
|
<div class="version-name-row">
|
|
<strong class="version-name">{{ version.version_name }}</strong>
|
|
{% if forloop.first %}<span class="latest-badge">latest</span>{% endif %}
|
|
{% if version.pack_format %}<span class="pack-format-badge">pack format {{ version.pack_format }}</span>{% endif %}
|
|
</div>
|
|
<span class="version-date"><i class="fas fa-clock"></i> {{ version.created_at|date:"M j, Y" }}</span>
|
|
<span class="version-downloads"><i class="fas fa-download"></i> {{ version.downloads }}</span>
|
|
</div>
|
|
{% if version.pack_description %}
|
|
<p class="pack-description"><i class="fas fa-info-circle"></i> {{ version.pack_description }}</p>
|
|
{% endif %}
|
|
{% if version.changelog %}
|
|
<div class="markdown-body version-changelog">{{ version.changelog|markdown }}</div>
|
|
{% endif %}
|
|
<div class="version-files">
|
|
{% for vf in version.files.all %}
|
|
<div class="version-file">
|
|
{% if vf.is_png %}
|
|
<img class="version-file-thumb" src="{% url 'library:file_request' vf.file.uuid %}" alt="{{ vf.filename }}">
|
|
{% elif vf.is_markdown %}
|
|
<i class="fas fa-file-lines version-file-icon"></i>
|
|
{% else %}
|
|
<i class="fas fa-file-archive version-file-icon"></i>
|
|
{% endif %}
|
|
<span class="version-file-name">{{ vf.filename }}</span>
|
|
<a class="btn btn-primary btn-sm" href="{% url 'library:version_file_download' project.slug version.pk vf.file.uuid %}" title="Download {{ vf.filename }}">
|
|
<i class="fas fa-download"></i>
|
|
</a>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<p class="empty-hint">No versions yet.</p>
|
|
{% endfor %}
|
|
</div>
|
|
</section>
|
|
|
|
{% if project.category == 'modpack' %}
|
|
<section class="tab-panel" id="tab-mods">
|
|
<div class="card">
|
|
<h2><i class="fas fa-cubes"></i> Mods</h2>
|
|
{% for version in versions %}
|
|
{% if version.mods_manifest.files %}
|
|
<div class="mods-version">
|
|
<h3>{{ version.version_name }} <span class="mods-source-badge">{{ version.mods_manifest.source }}</span></h3>
|
|
<ul class="mods-list">
|
|
{% for mod in version.mods_manifest.files %}
|
|
<li><i class="fas fa-cube"></i> {{ mod.name }}</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
{% empty %}
|
|
<p class="empty-hint">No mods detected in the uploaded packs.</p>
|
|
{% endfor %}
|
|
</div>
|
|
</section>
|
|
{% endif %}
|
|
|
|
<section class="tab-panel" id="tab-gallery">
|
|
<div class="card">
|
|
<h2><i class="fas fa-images"></i> Gallery</h2>
|
|
<div class="gallery-grid">
|
|
{% for asset in assets %}
|
|
<figure class="gallery-item">
|
|
{% if asset.is_video %}
|
|
<video controls preload="metadata" src="{{ asset.file_url }}"></video>
|
|
{% else %}
|
|
<a href="{{ asset.file_url }}" target="_blank"><img src="{{ asset.file_url }}" alt="{{ asset.caption }}"></a>
|
|
{% endif %}
|
|
{% if asset.caption %}<figcaption>{{ asset.caption }}</figcaption>{% endif %}
|
|
{% if can_edit %}
|
|
<a href="{% url 'library:asset_delete' project.slug asset.pk %}" class="gallery-delete" title="Delete media"><i class="fas fa-trash"></i></a>
|
|
{% endif %}
|
|
</figure>
|
|
{% empty %}
|
|
<p class="empty-hint">No media yet.</p>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
(function () {
|
|
const buttons = document.querySelectorAll('.tab-btn');
|
|
buttons.forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
buttons.forEach(b => b.classList.remove('active'));
|
|
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
document.getElementById('tab-' + btn.dataset.tab).classList.add('active');
|
|
});
|
|
});
|
|
|
|
// Gallery deletion without a page reload, behind a confirmation dialog.
|
|
document.querySelectorAll('.gallery-delete').forEach(link => {
|
|
link.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
if (!confirm('Delete this media? This cannot be undone.')) return;
|
|
const xhr = new XMLHttpRequest();
|
|
xhr.open('POST', link.getAttribute('href'));
|
|
xhr.setRequestHeader('X-CSRFToken', getCookie('csrftoken'));
|
|
xhr.onload = function () {
|
|
if (xhr.status === 200) {
|
|
const figure = link.closest('figure.gallery-item');
|
|
if (figure) figure.remove();
|
|
} else {
|
|
alert('Could not delete media.');
|
|
}
|
|
};
|
|
xhr.onerror = function () {
|
|
alert('Network error while deleting media.');
|
|
};
|
|
xhr.send();
|
|
});
|
|
});
|
|
|
|
// Guide document file-switcher (fetches + renders the selected .md).
|
|
const guideContent = document.getElementById('guide-content');
|
|
if (guideContent) {
|
|
const guideBtns = document.querySelectorAll('.guide-switch-btn');
|
|
function loadGuide(url) {
|
|
guideContent.innerHTML = '<p class="empty-hint">Loading…</p>';
|
|
fetch(url, { headers: { 'Accept': 'text/html' } })
|
|
.then(r => { if (!r.ok) throw new Error('http'); return r.text(); })
|
|
.then(html => { guideContent.innerHTML = html; })
|
|
.catch(() => { guideContent.innerHTML = '<p class="empty-hint">Could not load this document.</p>'; });
|
|
}
|
|
guideBtns.forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
guideBtns.forEach(b => b.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
loadGuide(btn.dataset.url);
|
|
});
|
|
});
|
|
const first = guideBtns[0];
|
|
if (first) loadGuide(first.dataset.url);
|
|
}
|
|
})();
|
|
</script>
|
|
{% endblock %}
|