- Added responsive table styles with mobile card layouts to base.html - Converted all templates from Bootstrap/plain CSS to Tailwind CSS - Implemented responsive tables with horizontal scroll on desktop - Added mobile card layouts for better readability on small screens - Standardized form layouts with Tailwind responsive grid - Updated all 15 templates for consistent styling: * base.html (responsive table CSS) * index.html (responsive tables + mobile cards) * students.html (Bootstrap -> Tailwind) * student_detail.html (Bootstrap -> Tailwind) * add_student.html (Bootstrap -> Tailwind) * edit_student.html (Bootstrap -> Tailwind) * import_students.html (Bootstrap -> Tailwind) * loan_tablet.html (Bootstrap -> Tailwind) * history.html (plain CSS -> Tailwind) * non_loanable_devices.html (plain CSS -> Tailwind) * add_non_loanable_device.html (plain CSS -> Tailwind) * edit_non_loanable_device.html (plain CSS -> Tailwind) * add_tablet.html (plain CSS -> Tailwind) * add_user.html (plain CSS -> Tailwind) * project_management.html (plain CSS -> Tailwind)
122 lines
5.3 KiB
HTML
122 lines
5.3 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block content %}
|
|
<div class="max-w-6xl mx-auto space-y-6">
|
|
{# Page Header #}
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-gray-900">{{ _('Project Management - Development Notes') }}</h1>
|
|
<p class="text-gray-600 mt-1">{{ _('Internal development notes and project documentation') }}</p>
|
|
</div>
|
|
|
|
{# Editor Section #}
|
|
<div class="bg-white rounded-lg shadow overflow-hidden">
|
|
<div class="bg-cobalt-600 px-6 py-4 flex justify-between items-center">
|
|
<h2 class="text-lg font-semibold text-white">{{ _('Editor') }}</h2>
|
|
<div class="flex gap-2">
|
|
<button onclick="saveNotes()"
|
|
class="inline-flex items-center gap-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
|
</svg>
|
|
{{ _('Save Notes') }}
|
|
</button>
|
|
<button onclick="loadNotes()"
|
|
class="inline-flex items-center gap-2 px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
|
</svg>
|
|
{{ _('Reload') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="p-6">
|
|
<div id="status" class="text-sm text-gray-500 italic mb-4"></div>
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
<div>
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3">{{ _('Editor') }}</h3>
|
|
<textarea id="markdown-editor" rows="20"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-cobalt-500 focus:border-cobalt-500 font-mono text-sm"
|
|
placeholder="{{ _('Write your markdown notes here...') }}"></textarea>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-3">{{ _('Preview') }}</h3>
|
|
<div id="markdown-preview"
|
|
class="w-full min-h-[400px] p-4 border border-gray-300 rounded-md bg-gray-50 overflow-y-auto prose prose-sm max-w-none"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
<script>
|
|
const NOTES_FILE = 'notes_development/project_notes.md';
|
|
|
|
// Initialize: load and render notes
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
loadNotes();
|
|
|
|
// Set up live preview
|
|
const editor = document.getElementById('markdown-editor');
|
|
const preview = document.getElementById('markdown-preview');
|
|
|
|
editor.addEventListener('input', function() {
|
|
preview.innerHTML = marked.parse(editor.value);
|
|
});
|
|
});
|
|
|
|
function loadNotes() {
|
|
fetch('/get_notes/' + NOTES_FILE)
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('File not found, using default');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
document.getElementById('markdown-editor').value = data.content;
|
|
document.getElementById('markdown-preview').innerHTML = marked.parse(data.content);
|
|
showStatus('{{ _("Notes loaded successfully") }}');
|
|
})
|
|
.catch(error => {
|
|
console.error('Error loading notes:', error);
|
|
showStatus('{{ _("Error loading notes") }}', true);
|
|
});
|
|
}
|
|
|
|
function saveNotes() {
|
|
const content = document.getElementById('markdown-editor').value;
|
|
fetch('/save_notes/' + NOTES_FILE, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ content: content })
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
showStatus('{{ _("Notes saved successfully") }}');
|
|
} else {
|
|
showStatus('{{ _("Error saving notes") }}: ' + data.error, true);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error saving notes:', error);
|
|
showStatus('{{ _("Error saving notes") }}', true);
|
|
});
|
|
}
|
|
|
|
function showStatus(message, isError = false) {
|
|
const status = document.getElementById('status');
|
|
status.textContent = message;
|
|
status.className = 'text-sm italic ' + (isError ? 'text-red-600' : 'text-green-600');
|
|
|
|
// Clear status after 3 seconds
|
|
setTimeout(() => {
|
|
status.textContent = '';
|
|
status.className = 'text-sm text-gray-500 italic';
|
|
}, 3000);
|
|
}
|
|
</script>
|
|
{% endblock %}
|