- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
76 lines
3.7 KiB
HTML
76 lines
3.7 KiB
HTML
{% extends "base.html" %}
|
|
{% block extra_head %}
|
|
<link rel="stylesheet" href="/static/css/projects.css">
|
|
<link rel="stylesheet" href="/static/css/post.css">
|
|
{% endblock %}
|
|
{% block content %}
|
|
<div class="project-detail-page">
|
|
<a href="/projects" class="back-link">← Back to Projects</a>
|
|
|
|
<article class="project-detail">
|
|
<div class="project-detail-header">
|
|
<h1 class="project-detail-title">{{ project['title'] }}</h1>
|
|
<div class="project-status {% if project.get('status') == 'Released' %}released{% else %}dev{% endif %}">
|
|
● {{ project.get('status', 'In Development') }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="project-detail-meta">
|
|
<span class="badge badge-type">{{ project.get('project_type', 'software').replace('_', ' ') }}</span>
|
|
{% if project.get('release_date') %}
|
|
<span>📅 Released: {{ project['release_date'] }}</span>
|
|
{% endif %}
|
|
{% if project.get('demo_date') %}
|
|
<span>🎭 Demo: {{ project['demo_date'] }}</span>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="project-detail-author">
|
|
{% set _size = 32 %}{% set _size_class = "sm" %}{% set _user = author %}{% include "_avatar_link.html" %}
|
|
<div>
|
|
{% set _user = author %}{% set _class = none %}{% include "_user_link.html" %}
|
|
{% if is_admin(user) and author and author.get('role') %}
|
|
<span style="font-size: 0.75rem; color: var(--text-muted);">· {{ author['role'] }}</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="project-detail-desc rendered-content" data-render>{{ project.get('description', '') }}</div>
|
|
|
|
{% if attachments %}
|
|
{% include "_attachment_display.html" %}
|
|
{% endif %}
|
|
|
|
{% if platforms %}
|
|
<div style="margin-bottom: 1.5rem;">
|
|
<h4 style="font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-muted); margin-bottom: 0.5rem;">Platforms</h4>
|
|
<div class="project-card-platforms">
|
|
{% for plat in platforms %}
|
|
<span class="platform-tag">{{ plat.strip() }}</span>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="project-detail-actions">
|
|
<a href="/projects/{{ project['slug'] or project['uid'] }}/files" class="project-star-btn">📁 Files</a>
|
|
<button type="button" class="project-star-btn" data-share="/projects/{{ project['slug'] or project['uid'] }}">🔗 Share</button>
|
|
{% if user %}
|
|
{% set _type = "project" %}{% set _uid = project['uid'] %}{% set _my_vote = my_vote %}{% set _count = star_count %}{% set _btn_class = "project-star-btn" %}{% include "_star_vote.html" %}
|
|
{% endif %}
|
|
{% set _type = "project" %}{% set _uid = project['uid'] %}{% set _bookmarked = bookmarked %}{% include "_bookmark_button.html" %}
|
|
{% if is_owner %}
|
|
<form method="POST" action="/projects/delete/{{ project['slug'] or project['uid'] }}" style="display:inline;">
|
|
<button type="submit" class="project-star-btn" data-confirm="Delete this project?"><span class="icon">🗑️</span> Delete</button>
|
|
</form>
|
|
{% endif %}
|
|
{% set _type = "project" %}{% set _uid = project['uid'] %}{% set _reactions = reactions %}{% include "_reaction_bar.html" %}
|
|
</div>
|
|
</article>
|
|
|
|
{% with target_uid=project['uid'], target_type="project" %}
|
|
{% include "_comment_section.html" %}
|
|
{% endwith %}
|
|
</div>
|
|
{% endblock %}
|