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:
ijuanes 2026-06-24 15:53:55 +01:00
parent 1b28021134
commit 06da5bdf2f
15 changed files with 1766 additions and 1229 deletions

View file

@ -3,136 +3,140 @@
{% block title %}{{ gettext('Add Student') }}{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-12 col-lg-8 offset-lg-2">
<h1 class="page-title">{{ gettext('Add Student') }}</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">
{# Page Header #}
<div>
<h1 class="text-2xl font-bold text-gray-900">{{ gettext('Add Student') }}</h1>
<p class="text-gray-600 mt-1">{{ gettext('Register a new student in the system') }}</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('add_student') }}" 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 '' }}"
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 '' }}"
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 '' }}"
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 '' }}"
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 '' }}"
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('add_student') }}">
<!-- 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 '' }}"
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 '' }}">
<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 '' }}">
</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 '' }}">
</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 '' }}">
</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 '' }}"
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 '' }}"
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 '' }}">
<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{% endif %}>{{ gettext('Male') }}</option>
<option value="F" {% if request.method == 'POST' and request.form.gender == 'F' %}selected{% endif %}>{{ gettext('Female') }}</option>
<option value="O" {% if request.method == 'POST' and request.form.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 '' }}">
<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('list_students') }}" 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('Save 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 '' }}"
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 '' }}"
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 '' }}"
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 '' }}"
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' %}selected{% endif %}>M</option>
<option value="F" {% if request.form.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 '' }}"
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('list_students') }}"
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="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
{{ gettext('Add Student') }}
</button>
</div>
</form>
</div>
</div>
</div>