Files
devplacepy/devplacepy/templates/messages.html
T
retoor 97eb58fc19 feat: add project file system with CRUD, upload, inline editing, and video attachment support
- 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
2026-06-08 20:51:09 +00:00

89 lines
3.7 KiB
HTML

{% extends "base.html" %}
{% block extra_head %}
<link rel="stylesheet" href="/static/css/messages.css">
{% endblock %}
{% block content %}
<h1 class="sr-only">Messages</h1>
<div class="page-messages">
<div class="messages-layout">
<div class="messages-list">
<div class="messages-list-header">
<input type="text" id="message-search" placeholder="Search conversations..." value="{{ search }}">
</div>
<div class="messages-conversations">
{% for conv in conversations %}
<a href="/messages?with_uid={{ conv.other_user['uid'] }}" class="conversation-item {% if current_conversation == conv.other_user['uid'] %}active{% endif %}">
<img src="{{ avatar_url('multiavatar', conv.other_user['username'], 32) }}" class="avatar-img avatar-sm" alt="{{ conv.other_user['username'] }}" loading="lazy">
<div class="conversation-info">
<div class="conversation-name">{{ conv.other_user['username'] }}</div>
<div class="conversation-preview">{{ conv.last_message[:60] }}</div>
</div>
<span class="conversation-time">{{ format_date(conv.last_message_at) }}</span>
</a>
{% else %}
<div class="empty-state" style="border: none;">No conversations yet</div>
{% endfor %}
</div>
</div>
<div class="messages-main">
{% if other_user %}
<div class="messages-main-header">
<button type="button" class="messages-back-btn" id="messages-back-btn" aria-label="Back to conversations">&#x2190;</button>
<a href="/profile/{{ other_user['username'] }}">
<img src="{{ avatar_url('multiavatar', other_user['username'], 32) }}" class="avatar-img avatar-sm" alt="{{ other_user['username'] }}" loading="lazy">
</a>
<h3>{% set _user = other_user %}{% set _class = none %}{% include "_user_link.html" %}</h3>
</div>
<div class="messages-thread">
{% for msg in messages %}
<div class="message-bubble {% if msg.is_mine %}mine{% else %}theirs{% endif %}">
<div class="rendered-content" data-render>{{ msg.message['content'] }}</div>
{% if msg.attachments %}
{% with attachments=msg.attachments %}
{% include "_attachment_display.html" %}
{% endwith %}
{% endif %}
<span class="message-time">{{ msg.time_ago }}</span>
</div>
{% endfor %}
</div>
<form class="messages-input-area" method="POST" action="/messages/send">
<input type="hidden" name="receiver_uid" value="{{ other_user['uid'] }}">
<input type="text" name="content" placeholder="Type a message..." required maxlength="2000" autocomplete="off" autofocus data-mention>
<dp-upload multiple
max-size="{{ max_upload_size_mb() }}"
max-files="5"
allowed-types="{{ allowed_file_types() }}"></dp-upload>
<button type="submit" class="messages-send-btn">&#x27A4;</button>
</form>
{% else %}
<div class="messages-empty">
<p>Select a conversation to start chatting</p>
</div>
{% endif %}
</div>
</div>
</div>
{% block extra_js %}
{% if other_user %}
<script>
document.addEventListener("DOMContentLoaded", function() {
var input = document.querySelector('.messages-input-area input[name="content"]');
if (input) {
var scrollTarget = document.querySelector('.messages-thread');
if (scrollTarget) {
scrollTarget.scrollTop = scrollTarget.scrollHeight;
}
input.focus();
}
});
</script>
{% endif %}
{% endblock %}
{% endblock %}