feat: dark mode and python 3.14
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# Use Python 3.13 slim image as base
|
||||
FROM python:3.13-slim AS builder
|
||||
FROM python:3.14-slim AS builder
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
@@ -17,7 +17,7 @@ RUN --mount=type=cache,id=pip,target=/root/.cache/pip \
|
||||
--target=/app/site-packages \
|
||||
-r requirements.txt
|
||||
|
||||
FROM python:3.13-slim
|
||||
FROM python:3.14-slim
|
||||
|
||||
COPY --from=builder /app/site-packages /app/site-packages
|
||||
|
||||
|
||||
@@ -5,17 +5,42 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Générateur d'Exercices de Mathématiques</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bs-body-bg: #ffffff;
|
||||
--bs-body-color: #212529;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-secondary-bg: #f8f9fa;
|
||||
--bs-tertiary-bg: #ffffff;
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] {
|
||||
--bs-body-bg: #121212;
|
||||
--bs-body-color: #e9ecef;
|
||||
--bs-border-color: #495057;
|
||||
--bs-secondary-bg: #212529;
|
||||
--bs-tertiary-bg: #343a40;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--bs-body-bg);
|
||||
color: var(--bs-body-color);
|
||||
transition: background-color 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
|
||||
.card {
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
transition: 0.3s;
|
||||
margin-bottom: 20px;
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
border-color: var(--bs-border-color);
|
||||
}
|
||||
.card:hover {
|
||||
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
|
||||
}
|
||||
.exercise-result {
|
||||
background-color: #f8f9fa;
|
||||
background-color: var(--bs-secondary-bg);
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-top: 20px;
|
||||
@@ -25,9 +50,81 @@
|
||||
height: 3rem;
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
|
||||
.dark-mode-toggle {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 1000;
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: none;
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
color: var(--bs-body-color);
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.dark-mode-toggle:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .bg-light {
|
||||
background-color: var(--bs-secondary-bg) !important;
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .text-muted {
|
||||
color: var(--bs-body-color) !important;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .table {
|
||||
--bs-table-bg: var(--bs-tertiary-bg);
|
||||
--bs-table-striped-bg: var(--bs-secondary-bg);
|
||||
--bs-table-hover-bg: var(--bs-border-color);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .alert {
|
||||
border-color: var(--bs-border-color);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .form-control,
|
||||
[data-bs-theme="dark"] .form-select {
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
border-color: var(--bs-border-color);
|
||||
color: var(--bs-body-color);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .form-control:focus,
|
||||
[data-bs-theme="dark"] .form-select:focus {
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
border-color: var(--bs-primary);
|
||||
color: var(--bs-body-color);
|
||||
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .form-check-input {
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
border-color: var(--bs-border-color);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .form-check-input:checked {
|
||||
background-color: var(--bs-primary);
|
||||
border-color: var(--bs-primary);
|
||||
}
|
||||
|
||||
.transition-all {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Dark Mode Toggle Button -->
|
||||
<button class="dark-mode-toggle" id="darkModeToggle" title="Basculer le mode sombre" aria-label="Basculer le mode sombre">
|
||||
<i class="bi bi-moon-fill" id="darkModeIcon"></i>
|
||||
</button>
|
||||
<div class="container mt-5 mb-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
@@ -251,7 +348,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="bg-light text-center text-muted py-4 mt-5">
|
||||
<footer class="bg-light text-center text-muted py-4 mt-5 transition-all">
|
||||
<div class="container">
|
||||
<p>Générateur d'Exercices de Mathématiques © 2025</p>
|
||||
</div>
|
||||
@@ -259,6 +356,72 @@
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// Dark Mode Theme Management
|
||||
class ThemeManager {
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
// Load saved theme or detect system preference
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
const theme = savedTheme || systemTheme;
|
||||
|
||||
this.setTheme(theme);
|
||||
|
||||
// Listen for system theme changes
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
|
||||
if (!localStorage.getItem('theme')) {
|
||||
this.setTheme(e.matches ? 'dark' : 'light');
|
||||
}
|
||||
});
|
||||
|
||||
// Setup toggle button
|
||||
this.setupToggleButton();
|
||||
}
|
||||
|
||||
setTheme(theme) {
|
||||
document.documentElement.setAttribute('data-bs-theme', theme);
|
||||
localStorage.setItem('theme', theme);
|
||||
this.updateToggleIcon(theme);
|
||||
}
|
||||
|
||||
toggleTheme() {
|
||||
const currentTheme = document.documentElement.getAttribute('data-bs-theme');
|
||||
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
||||
this.setTheme(newTheme);
|
||||
}
|
||||
|
||||
updateToggleIcon(theme) {
|
||||
const icon = document.getElementById('darkModeIcon');
|
||||
if (theme === 'dark') {
|
||||
icon.className = 'bi bi-sun-fill';
|
||||
} else {
|
||||
icon.className = 'bi bi-moon-fill';
|
||||
}
|
||||
}
|
||||
|
||||
setupToggleButton() {
|
||||
const toggleButton = document.getElementById('darkModeToggle');
|
||||
toggleButton.addEventListener('click', () => {
|
||||
this.toggleTheme();
|
||||
this.animateToggle();
|
||||
});
|
||||
}
|
||||
|
||||
animateToggle() {
|
||||
const button = document.getElementById('darkModeToggle');
|
||||
button.style.transform = 'scale(0.9)';
|
||||
setTimeout(() => {
|
||||
button.style.transform = '';
|
||||
}, 150);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize theme manager
|
||||
const themeManager = new ThemeManager();
|
||||
|
||||
// Current page for pagination
|
||||
let currentPage = 1;
|
||||
const pageSize = 10;
|
||||
@@ -485,8 +648,11 @@
|
||||
|
||||
// Load PDF list on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Ensure theme is initialized first
|
||||
setTimeout(() => {
|
||||
restoreFormValues();
|
||||
loadPdfList(currentPage);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// Add event listeners to save form values on change
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
annotated-doc==0.0.4
|
||||
annotated-types==0.7.0
|
||||
anyio==4.10.0
|
||||
boto3==1.26.160
|
||||
boto3-stubs==1.40.23
|
||||
botocore==1.29.165
|
||||
botocore-stubs==1.40.23
|
||||
click==8.2.1
|
||||
anyio==4.12.0
|
||||
boto3==1.42.6
|
||||
boto3-stubs==1.42.6
|
||||
botocore==1.42.6
|
||||
botocore-stubs==1.42.6
|
||||
click==8.3.1
|
||||
defusedxml==0.7.1
|
||||
fastapi==0.116.1
|
||||
fonttools==4.59.2
|
||||
fpdf2==2.8.4
|
||||
fastapi==0.124.0
|
||||
fonttools==4.61.0
|
||||
fpdf2==2.8.5
|
||||
h11==0.16.0
|
||||
idna==3.10
|
||||
Jinja2==3.1.4
|
||||
idna==3.11
|
||||
Jinja2==3.1.6
|
||||
jmespath==1.0.1
|
||||
MarkupSafe==3.0.2
|
||||
pillow==11.3.0
|
||||
pydantic==2.11.7
|
||||
pydantic_core==2.33.2
|
||||
MarkupSafe==3.0.3
|
||||
pillow==12.0.0
|
||||
pydantic==2.12.5
|
||||
pydantic_core==2.41.5
|
||||
python-dateutil==2.9.0.post0
|
||||
python-multipart==0.0.9
|
||||
s3transfer==0.6.2
|
||||
python-multipart==0.0.20
|
||||
s3transfer==0.16.0
|
||||
six==1.17.0
|
||||
sniffio==1.3.1
|
||||
starlette==0.47.3
|
||||
types-awscrt==0.27.6
|
||||
types-fpdf2==2.8.4.20250822
|
||||
types-s3transfer==0.13.1
|
||||
typing-inspection==0.4.1
|
||||
starlette==0.50.0
|
||||
types-awscrt==0.29.2
|
||||
types-s3transfer==0.16.0
|
||||
typing-inspection==0.4.2
|
||||
typing_extensions==4.15.0
|
||||
urllib3==1.26.20
|
||||
uvicorn==0.30.6
|
||||
urllib3==2.6.1
|
||||
uvicorn==0.38.0
|
||||
|
||||
Reference in New Issue
Block a user