Phase 1: Responsive tables and Tailwind CSS standardization
- 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)
This commit is contained in:
parent
1b28021134
commit
06da5bdf2f
15 changed files with 1766 additions and 1229 deletions
|
|
@ -3,144 +3,165 @@
|
|||
{% block title %}{{ gettext('Edit Student') }} - {{ student.full_name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-8 offset-lg-2">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ url_for('list_students') }}">{{ gettext('Students') }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ url_for('student_detail', student_id=student.id) }}">{{ student.full_name }}</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{{ gettext('Edit') }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h1 class="page-title">{{ gettext('Edit Student') }}: {{ student.full_name }}</h1>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">{{ gettext('Student Information') }}</h5>
|
||||
<div class="max-w-2xl mx-auto space-y-6">
|
||||
{# Breadcrumb #}
|
||||
<nav class="flex" aria-label="Breadcrumb">
|
||||
<ol class="flex items-center space-x-2">
|
||||
<li>
|
||||
<a href="{{ url_for('list_students') }}" class="text-cobalt-600 hover:text-cobalt-800">{{ gettext('Students') }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url_for('student_detail', student_id=student.id) }}" class="text-cobalt-600 hover:text-cobalt-800">{{ student.full_name }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-gray-500">{{ gettext('Edit') }}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{# Page Header #}
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-gray-900">{{ gettext('Edit Student') }}: {{ student.full_name }}</h1>
|
||||
<p class="text-gray-600 mt-1">{{ gettext('Update student information') }}</p>
|
||||
</div>
|
||||
|
||||
{# Student Form #}
|
||||
<div class="bg-white rounded-lg shadow overflow-hidden">
|
||||
<div class="bg-cobalt-600 px-6 py-4">
|
||||
<h2 class="text-lg font-semibold text-white">{{ gettext('Student Information') }}</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<form method="POST" action="{{ url_for('edit_student', student_id=student.id) }}" class="space-y-6">
|
||||
{# Identification Section #}
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b border-gray-200 pb-2">{{ gettext('Identification') }}</h3>
|
||||
|
||||
<div>
|
||||
<label for="cial_code" class="block text-sm font-medium text-gray-700 mb-1">{{ gettext('CIAL Code') }} *</label>
|
||||
<input type="text" id="cial_code" name="cial_code" required autofocus
|
||||
value="{{ request.form.cial_code if request.method == 'POST' else student.cial_code }}"
|
||||
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"
|
||||
placeholder="{{ gettext('Unique internal identification code') }}">
|
||||
<p class="mt-1 text-sm text-gray-500">{{ gettext('Unique internal identification code') }}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="nif_nie_passport" class="block text-sm font-medium text-gray-700 mb-1">{{ gettext('NIF/NIE/Passport') }}</label>
|
||||
<input type="text" id="nif_nie_passport" name="nif_nie_passport"
|
||||
value="{{ request.form.nif_nie_passport if request.method == 'POST' else (student.nif_nie_passport or '') }}"
|
||||
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"
|
||||
placeholder="{{ gettext('National ID, Foreign ID, or Passport number') }}">
|
||||
<p class="mt-1 text-sm text-gray-500">{{ gettext('National ID, Foreign ID, or Passport number') }}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="registration_number" class="block text-sm font-medium text-gray-700 mb-1">{{ gettext('Registration Number') }}</label>
|
||||
<input type="number" id="registration_number" name="registration_number"
|
||||
value="{{ request.form.registration_number if request.method == 'POST' else (student.registration_number or '') }}"
|
||||
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"
|
||||
placeholder="{{ gettext('Optional registration number') }}">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="file_number" class="block text-sm font-medium text-gray-700 mb-1">{{ gettext('File Number') }}</label>
|
||||
<input type="text" id="file_number" name="file_number"
|
||||
value="{{ request.form.file_number if request.method == 'POST' else (student.file_number or '') }}"
|
||||
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"
|
||||
placeholder="{{ gettext('Optional file number') }}">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="order_number" class="block text-sm font-medium text-gray-700 mb-1">{{ gettext('Order Number') }}</label>
|
||||
<input type="number" id="order_number" name="order_number"
|
||||
value="{{ request.form.order_number if request.method == 'POST' else (student.order_number or '') }}"
|
||||
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"
|
||||
placeholder="{{ gettext('Optional order number') }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ url_for('edit_student', student_id=student.id) }}">
|
||||
|
||||
<!-- Identification Section -->
|
||||
<fieldset class="mb-4">
|
||||
<legend class="text-primary">{{ gettext('Identification') }}</legend>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="cial_code" class="col-sm-3 col-form-label">{{ gettext('CIAL Code') }} *</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="cial_code" name="cial_code"
|
||||
value="{{ request.form.cial_code if request.method == 'POST' else student.cial_code }}"
|
||||
required autofocus>
|
||||
<div class="form-text">{{ gettext('Unique internal identification code') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="nif_nie_passport" class="col-sm-3 col-form-label">{{ gettext('NIF/NIE/Passport') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="nif_nie_passport" name="nif_nie_passport"
|
||||
value="{{ request.form.nif_nie_passport if request.method == 'POST' else (student.nif_nie_passport or '') }}">
|
||||
<div class="form-text">{{ gettext('National ID, Foreign ID, or Passport number') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="registration_number" class="col-sm-3 col-form-label">{{ gettext('Registration Number') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="number" class="form-control" id="registration_number" name="registration_number"
|
||||
value="{{ request.form.registration_number if request.method == 'POST' else (student.registration_number or '') }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="file_number" class="col-sm-3 col-form-label">{{ gettext('File Number') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="file_number" name="file_number"
|
||||
value="{{ request.form.file_number if request.method == 'POST' else (student.file_number or '') }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="order_number" class="col-sm-3 col-form-label">{{ gettext('Order Number') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="number" class="form-control" id="order_number" name="order_number"
|
||||
value="{{ request.form.order_number if request.method == 'POST' else (student.order_number or '') }}">
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<!-- Personal Information Section -->
|
||||
<fieldset class="mb-4">
|
||||
<legend class="text-primary">{{ gettext('Personal Information') }}</legend>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="last_name" class="col-sm-3 col-form-label">{{ gettext('Last Name') }} *</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="last_name" name="last_name"
|
||||
value="{{ request.form.last_name if request.method == 'POST' else student.last_name }}"
|
||||
required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="first_name" class="col-sm-3 col-form-label">{{ gettext('First Name') }} *</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="first_name" name="first_name"
|
||||
value="{{ request.form.first_name if request.method == 'POST' else student.first_name }}"
|
||||
required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="birth_date" class="col-sm-3 col-form-label">{{ gettext('Birth Date') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="date" class="form-control" id="birth_date" name="birth_date"
|
||||
value="{{ request.form.birth_date if request.method == 'POST' else (student.birth_date or '') }}">
|
||||
<div class="form-text">{{ gettext('Format: YYYY-MM-DD') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="gender" class="col-sm-3 col-form-label">{{ gettext('Gender') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-select" id="gender" name="gender">
|
||||
<option value="">{{ gettext('Select...') }}</option>
|
||||
<option value="M" {% if request.method == 'POST' and request.form.gender == 'M' %}selected{% elif student.gender == 'M' %}selected{% endif %}>{{ gettext('Male') }}</option>
|
||||
<option value="F" {% if request.method == 'POST' and request.form.gender == 'F' %}selected{% elif student.gender == 'F' %}selected{% endif %}>{{ gettext('Female') }}</option>
|
||||
<option value="O" {% if request.method == 'POST' and request.form.gender == 'O' %}selected{% elif student.gender == 'O' %}selected{% endif %}>{{ gettext('Other') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<!-- Study Information Section -->
|
||||
<fieldset class="mb-4">
|
||||
<legend class="text-primary">{{ gettext('Study Information') }}</legend>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="study_group" class="col-sm-3 col-form-label">{{ gettext('Study Group') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="study_group" name="study_group"
|
||||
value="{{ request.form.study_group if request.method == 'POST' else (student.study_group or '') }}">
|
||||
<div class="form-text">{{ gettext('E.g., 1º FPB BÁSICA') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<!-- Form Actions -->
|
||||
<div class="d-flex justify-content-end gap-2">
|
||||
<a href="{{ url_for('student_detail', student_id=student.id) }}" class="btn btn-secondary">
|
||||
<i class="bi bi-x-circle"></i> {{ gettext('Cancel') }}
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-circle"></i> {{ gettext('Update Student') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{# Personal Information Section #}
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b border-gray-200 pb-2">{{ gettext('Personal Information') }}</h3>
|
||||
|
||||
<div>
|
||||
<label for="first_name" class="block text-sm font-medium text-gray-700 mb-1">{{ gettext('First Name') }} *</label>
|
||||
<input type="text" id="first_name" name="first_name" required
|
||||
value="{{ request.form.first_name if request.method == 'POST' else student.first_name }}"
|
||||
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"
|
||||
placeholder="{{ gettext('Student first name') }}">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="last_name" class="block text-sm font-medium text-gray-700 mb-1">{{ gettext('Last Name') }} *</label>
|
||||
<input type="text" id="last_name" name="last_name" required
|
||||
value="{{ request.form.last_name if request.method == 'POST' else student.last_name }}"
|
||||
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"
|
||||
placeholder="{{ gettext('Student last name') }}">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="full_name" class="block text-sm font-medium text-gray-700 mb-1">{{ gettext('Full Name') }} *</label>
|
||||
<input type="text" id="full_name" name="full_name" required
|
||||
value="{{ request.form.full_name if request.method == 'POST' else student.full_name }}"
|
||||
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"
|
||||
placeholder="{{ gettext('Complete name') }}">
|
||||
<p class="mt-1 text-sm text-gray-500">{{ gettext('Full name for display purposes') }}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="birth_date" class="block text-sm font-medium text-gray-700 mb-1">{{ gettext('Birth Date') }}</label>
|
||||
<input type="date" id="birth_date" name="birth_date"
|
||||
value="{{ request.form.birth_date if request.method == 'POST' else (student.birth_date or '') }}"
|
||||
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">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="gender" class="block text-sm font-medium text-gray-700 mb-1">{{ gettext('Gender') }}</label>
|
||||
<select id="gender" name="gender"
|
||||
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">
|
||||
<option value="">{{ gettext('Select gender') }}</option>
|
||||
<option value="M" {% if request.form.gender == 'M' or student.gender == 'M' %}selected{% endif %}>M</option>
|
||||
<option value="F" {% if request.form.gender == 'F' or student.gender == 'F' %}selected{% endif %}>F</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="study_group" class="block text-sm font-medium text-gray-700 mb-1">{{ gettext('Study Group') }}</label>
|
||||
<input type="text" id="study_group" name="study_group"
|
||||
value="{{ request.form.study_group if request.method == 'POST' else (student.study_group or '') }}"
|
||||
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"
|
||||
placeholder="{{ gettext('e.g., 2º ESO A, 3º ESO B') }}">
|
||||
<p class="mt-1 text-sm text-gray-500">{{ gettext('Class or study group') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-3 pt-4 border-t border-gray-200">
|
||||
<a href="{{ url_for('student_detail', student_id=student.id) }}"
|
||||
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="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
{{ gettext('Cancel') }}
|
||||
</a>
|
||||
<button type="submit"
|
||||
class="inline-flex items-center gap-2 px-4 py-2 bg-cobalt-600 text-white rounded-lg hover:bg-cobalt-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>
|
||||
{{ gettext('Save Changes') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue