205 lines
8.2 KiB
HTML
205 lines
8.2 KiB
HTML
{% load i18n crispy_forms_tags %}
|
|
|
|
<div class="p-4">
|
|
<form hx-boost="true" id="noteform" action="{{ url }}" method="post" hx-select=".note-table-body" hx-target=".note-table-body" hx-swap="outerHTML" hx-push-url="false">
|
|
{% csrf_token %}
|
|
|
|
<!-- Crispy Form for rendering -->
|
|
<div class="space-y-4">
|
|
<div>
|
|
{{ form|crispy }}
|
|
</div>
|
|
|
|
<!-- Form Actions -->
|
|
<div class="flex justify-end gap-2 pt-4 border-t-2 border-gray-200">
|
|
|
|
<button type="submit" class="px-4 py-2 bg-temple-red text-white rounded-lg hover:bg-temple-red/90 transition text-sm font-medium" id="saveNoteBtn">
|
|
<i data-lucide="save" class="w-4 h-4 inline mr-1"></i>
|
|
{% trans "Save Note" %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Notes Table Section -->
|
|
<div class="mt-6">
|
|
<!-- Table Header -->
|
|
<div class="bg-gray-50 border border-gray-200 rounded-xl overflow-hidden">
|
|
<table class="w-full border-collapse" id="notesTable">
|
|
<thead>
|
|
<tr class="border-b-2 border-temple-red">
|
|
<th class="px-4 py-3 text-left text-xs font-semibold text-temple-dark">
|
|
<i data-lucide="user" class="w-3 h-3 inline mr-1"></i>
|
|
{% trans "Author" %}
|
|
</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold text-temple-dark" style="width: 60%;">
|
|
<i data-lucide="sticky-note" class="w-3 h-3 inline mr-1"></i>
|
|
{% trans "Note" %}
|
|
</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold text-temple-dark">
|
|
<i data-lucide="calendar" class="w-3 h-3 inline mr-1"></i>
|
|
{% trans "Created" %}
|
|
</th>
|
|
<th class="px-4 py-3 text-right text-xs font-semibold text-temple-dark">
|
|
<i data-lucide="trash-2" class="w-3 h-3 inline mr-1"></i>
|
|
{% trans "Actions" %}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="note-table-body">
|
|
{% if notes %}
|
|
{% for note in notes %}
|
|
<tr id="note-{{ note.id }}" class="hover:bg-gray-50 transition-colors border-b border-gray-200">
|
|
<td class="px-4 py-3">
|
|
<div class="flex items-center gap-2">
|
|
<div class="w-8 h-8 rounded-full bg-temple-red text-white flex items-center justify-center text-sm font-bold">
|
|
{{ note.author.first_name.0|default:note.author.username.0|upper }}
|
|
</div>
|
|
<div>
|
|
<div class="font-medium text-temple-dark text-sm">
|
|
{{ note.author.get_full_name|default:note.author.username }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td class="px-4 py-3">
|
|
<div class="text-sm text-gray-700 bg-white p-3 rounded-lg border border-gray-200 shadow-sm">
|
|
{{ note.content|linebreaksbr }}
|
|
</div>
|
|
</td>
|
|
<td class="px-4 py-3 whitespace-nowrap">
|
|
<div class="text-xs text-gray-500">
|
|
<i data-lucide="clock" class="w-3 h-3 inline mr-1"></i>
|
|
{{ note.created_at|date:"SHORT_DATETIME_FORMAT" }}
|
|
</div>
|
|
</td>
|
|
<td class="px-4 py-3 text-right">
|
|
<button hx-delete="{% url 'delete_note' note.slug %}"
|
|
hx-target="#note-{{ note.id }}"
|
|
hx-swap="delete"
|
|
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
|
hx-confirm="{% trans 'Are you sure you want to delete this note?' %}"
|
|
type="button"
|
|
class="px-3 py-1.5 border-2 border-red-500 text-red-500 rounded-lg hover:bg-red-500 hover:text-white transition text-xs font-medium delete-note-btn inline-flex items-center gap-1"
|
|
title="{% trans 'Delete Note' %}">
|
|
<i data-lucide="trash-2" class="w-3 h-3"></i>
|
|
{% trans "Delete" %}
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="4" class="text-center py-8 text-gray-500">
|
|
<div class="flex flex-col items-center gap-2">
|
|
<i data-lucide="sticky-note" class="w-12 h-12 text-gray-400"></i>
|
|
<span class="text-sm">{% trans "No notes yet." %}</span>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endif %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add custom styling for crispy form -->
|
|
<style>
|
|
#noteform textarea {
|
|
width: 100%;
|
|
padding:1rem 1.25rem;
|
|
background-color: white;
|
|
border: 2px solid #e5e7eb;
|
|
border-radius: 1rem;
|
|
font-size: 0.875rem;
|
|
color: #374151;
|
|
transition: all 0.3s;
|
|
resize: none;
|
|
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
#noteform textarea:focus {
|
|
border-color: #dc2626;
|
|
outline: none;
|
|
box-shadow: 0 0 0 4px rgba(220, 38, 38, 0.1);
|
|
background-color: #fef2f2;
|
|
}
|
|
|
|
#noteform textarea::placeholder {
|
|
color: #9ca3af;
|
|
}
|
|
|
|
#noteform textarea:hover {
|
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
border-color: #d1d5db;
|
|
}
|
|
|
|
#noteform label {
|
|
display: block;
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
color: #1f2937;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
#noteform .help-block,
|
|
#noteform .helptext {
|
|
font-size: 0.75rem;
|
|
color: #6b7280;
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
#noteform .text-danger,
|
|
#noteform .errorlist {
|
|
font-size: 0.75rem;
|
|
color: #dc2626;
|
|
background-color: #fef2f2;
|
|
border: 2px solid #fca5a5;
|
|
border-radius: 0.75rem;
|
|
padding: 0.75rem;
|
|
margin-top: 0.75rem;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
// Reinitialize Lucide icons after HTMX updates
|
|
document.addEventListener('htmx:afterSwap', function(evt) {
|
|
if (typeof lucide !== 'undefined') {
|
|
lucide.createIcons();
|
|
}
|
|
});
|
|
|
|
// Function to close the modal
|
|
function closeModal() {
|
|
const modal = document.getElementById('noteModal');
|
|
if (modal) {
|
|
const modalInstance = bootstrap.Modal.getInstance(modal);
|
|
if (modalInstance) {
|
|
modalInstance.hide();
|
|
} else {
|
|
new bootstrap.Modal(modal).hide();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cancel button click handler - attached to document to catch dynamically added buttons
|
|
document.body.addEventListener('click', function(e) {
|
|
const cancelBtn = e.target.closest('#cancelNoteBtn')
|
|
if (cancelBtn) {
|
|
e.preventDefault();
|
|
closeModal();
|
|
}
|
|
});
|
|
|
|
// Re-attach cancel button listener after HTMX updates (for the form submit cancel)
|
|
document.addEventListener('htmx:afterSwap', function(evt) {
|
|
const cancelBtn = document.getElementById('cancelNoteBtn');
|
|
if (cancelBtn) {
|
|
cancelBtn.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
closeModal();
|
|
});
|
|
}
|
|
});
|
|
</script> |