File size: 9,743 Bytes
cb18dab 75ba54e cb18dab 75ba54e cb18dab | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | {% extends 'base.html' %}
{% block title %}/{{ board.slug }}/ - {{ board.name }}{% endblock %}
{% block content %}
<div class="mb-6 px-4 pt-4">
<h1 class="text-2xl font-bold text-gray-900 tracking-tight">/{{ board.slug }}/ - {{ board.name }}</h1>
<p class="text-gray-500 text-sm mt-1">{{ board.description }}</p>
</div>
<!-- Threads List -->
<div class="space-y-4 px-2 pb-24">
{% for thread in threads %}
<div class="bg-white p-4 rounded-xl border border-gray-100 shadow-sm" id="post-{{ thread.id }}">
<div class="flex gap-4">
<!-- Thumbnails -->
{% if thread.files %}
<div class="flex-shrink-0 flex flex-col gap-2">
{% for file in thread.files[:1] %} <!-- Show only first file as thumbnail -->
{% if file.filename.endswith(('.mp4', '.webm')) %}
<video controls class="w-24 h-24 sm:w-32 sm:h-32 object-cover rounded-lg bg-black">
<source src="{{ url_for('static', filename='uploads/' + file.filename) }}" type="video/{{ file.filename.split('.')[-1] }}">
</video>
{% else %}
<img
src="{{ url_for('static', filename='uploads/' + file.filename) }}"
data-thumb="{{ url_for('static', filename='uploads/' + file.filename) }}"
data-full="{{ url_for('static', filename='uploads/' + file.filename) }}"
alt="Post image"
class="post-image w-24 h-24 sm:w-32 sm:h-32 object-cover rounded-lg cursor-pointer hover:opacity-90 transition-opacity bg-gray-100"
>
{% endif %}
{% endfor %}
{% if thread.files|length > 1 %}
<span class="text-xs text-gray-500 text-center">+ {{ thread.files|length - 1 }} autres</span>
{% endif %}
</div>
{% endif %}
<div class="flex-grow min-w-0"> <!-- min-w-0 for truncation -->
<div class="flex items-center text-xs text-gray-500 mb-2 space-x-2">
<span class="font-bold text-gray-900">{{ thread.nickname }}</span>
<span>{{ thread.created_at.strftime('%d/%m %H:%M') }}</span>
<a href="{{ url_for('thread', thread_id=thread.id) }}" class="text-blue-500 hover:underline">N° {{ thread.id }}</a>
</div>
<div class="text-gray-800 text-base leading-relaxed break-words line-clamp-4 mb-3">
{{ thread.content|default('', true)|truncate(300)|format_post(post_context) }}
</div>
<div class="flex items-center justify-between">
<a href="{{ url_for('thread', thread_id=thread.id) }}" class="text-sm font-medium text-blue-600 hover:text-blue-800 bg-blue-50 px-3 py-1 rounded-full">
Voir le fil
{% if thread.replies|length > 0 %}
<span class="ml-1 text-blue-800">({{ thread.replies|length }})</span>
{% endif %}
</a>
<button class="text-green-600 hover:text-green-800 p-2 rounded-full hover:bg-green-50" onclick="sharePost('{{ thread.id }}', '{{ url_for('thread', thread_id=thread.id, _external=True) }}')" title="Partager">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z" />
</svg>
</button>
</div>
<!-- Latest replies preview (Desktop only maybe? Or simplified) -->
{% set recent_replies = thread.replies[-2:] %}
{% if recent_replies %}
<div class="mt-4 space-y-2 border-l-2 border-gray-100 pl-3">
{% for reply in recent_replies %}
<div class="text-sm text-gray-600">
<span class="text-xs text-gray-400">>> {{ reply.created_at.strftime('%H:%M') }}</span>
<span class="line-clamp-1">{{ reply.content|truncate(100) }}</span>
</div>
{% endfor %}
</div>
{% endif %}
</div>
</div>
</div>
{% else %}
<div class="text-center text-gray-400 py-12 bg-white rounded-xl border border-gray-100 border-dashed">
<p>C'est calme ici. Lancez une conversation.</p>
</div>
{% endfor %}
</div>
<!-- Floating Action Button -->
<button id="fab-button" onclick="togglePostForm()" class="fixed bottom-6 right-6 bg-blue-600 hover:bg-blue-700 text-white rounded-full p-4 shadow-lg transition-transform hover:scale-105 active:scale-95 z-40 flex items-center justify-center w-14 h-14">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
</svg>
</button>
<!-- Hidden Modal Form -->
<div id="post-form-container" class="hidden fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-gray-900 bg-opacity-40 backdrop-blur-sm p-0 sm:p-4">
<!-- Overlay click to close -->
<div class="absolute inset-0" onclick="togglePostForm()"></div>
<div class="bg-white w-full max-w-lg rounded-t-2xl sm:rounded-2xl shadow-2xl transform transition-all relative z-10 flex flex-col max-h-[90vh]">
<div class="flex justify-between items-center p-4 border-b border-gray-100">
<h3 class="text-lg font-bold text-gray-900">Nouveau fil</h3>
<button onclick="togglePostForm()" class="text-gray-400 hover:text-gray-600 p-2 rounded-full hover:bg-gray-100">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="p-6 overflow-y-auto">
<form method="POST" enctype="multipart/form-data" class="space-y-5">
{{ form.hidden_tag() }}
<div class="hidden">
{{ form.honeypot() }}
</div>
<div id="nickname-field">
<label class="block text-gray-700 text-sm font-semibold mb-2" for="nickname">Pseudo</label>
{{ form.nickname(class="w-full bg-gray-50 text-gray-900 border border-gray-200 rounded-lg py-3 px-4 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent", placeholder="Pseudo (Optionnel)") }}
</div>
<div>
<label class="block text-gray-700 text-sm font-semibold mb-2" for="content">Message</label>
{{ form.content(class="w-full bg-gray-50 text-gray-900 border border-gray-200 rounded-lg py-3 px-4 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent h-40 resize-none text-base", placeholder="Écrivez quelque chose...") }}
{% for error in form.content.errors %}
<p class="text-red-500 text-xs mt-1">{{ error }}</p>
{% endfor %}
</div>
<div>
<label class="block text-gray-700 text-sm font-semibold mb-2" for="files">Images ou Vidéos</label>
<div class="flex items-center justify-center w-full">
<label for="files" class="flex flex-col items-center justify-center w-full h-32 border-2 border-gray-200 border-dashed rounded-lg cursor-pointer bg-gray-50 hover:bg-gray-100">
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<svg class="w-8 h-8 mb-4 text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 16">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"/>
</svg>
<p class="text-sm text-gray-500"><span class="font-semibold">Cliquez pour uploader</span></p>
</div>
{{ form.files(class="hidden", multiple=True, accept="image/*,video/*", onchange="previewFiles(this, 'preview-board')") }}
</label>
</div>
<div id="preview-board" class="flex flex-wrap gap-2 mt-2"></div>
{% for error in form.files.errors %}
<p class="text-red-500 text-xs mt-1">{{ error }}</p>
{% endfor %}
</div>
<div class="pt-2">
{{ form.submit(class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg cursor-pointer shadow-md active:scale-95 transition-transform") }}
</div>
</form>
</div>
</div>
</div>
{% endblock %}
|