Add comment system with models, forms, and UI integration for lessons

This commit is contained in:
mrtoine 2025-12-10 22:22:17 +01:00
parent c22622ebc1
commit 95111240bc
26 changed files with 1001 additions and 77 deletions

View file

@ -109,6 +109,103 @@
}
/* Light theme values — applied via colors_light.css inclusion */
/* ==========================
Cours Sommaire (TOC)
========================== */
.courseToc {
background: var(--surface);
border: 1px solid var(--border-subtle);
border-radius: var(--r-3);
box-shadow: var(--shadow-1);
/* Make the TOC span the full width of its section */
width: 100%;
margin: var(--space-5) 0;
padding: var(--space-5);
max-width: none;
}
.courseToc .tocModules,
.courseToc .tocLessons {
list-style: none;
margin: 0;
padding: 0;
}
.courseToc .tocModule + .tocModule {
margin-top: var(--space-5);
padding-top: var(--space-5);
border-top: 2px dashed var(--border-subtle);
}
.courseToc .tocModuleHeader {
display: flex;
align-items: center;
gap: var(--space-3);
color: var(--text);
font-weight: 600;
letter-spacing: .2px;
margin-bottom: var(--space-3);
}
.courseToc .tocModuleIndex {
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: 999px;
background: var(--primary);
color: var(--primary-contrast);
font-size: 14px;
font-weight: 700;
box-shadow: 0 0 0 3px rgba(78,158,214,0.15);
}
.courseToc .tocModuleTitle {
font-size: 18px;
}
.courseToc .tocLessons {
display: grid;
grid-template-columns: 1fr;
gap: 6px;
}
.courseToc .tocLesson {
position: relative;
}
.courseToc .tocLink {
display: block;
padding: 10px 12px;
border-radius: var(--r-2);
text-decoration: none;
color: var(--link);
background: rgba(255,255,255,0.02);
border: 1px solid transparent;
transition: all var(--transition-1);
}
.courseToc .tocLink:hover {
color: var(--link-hover);
background: rgba(78,158,214,0.08);
border-color: var(--border-subtle);
}
.courseToc .tocLesson.current .tocLink {
color: var(--success);
background: rgba(47,168,108,0.12);
border-color: rgba(47,168,108,0.35);
font-weight: 700;
}
.courseToc .tocCurrentTag {
color: var(--text-muted);
font-weight: 600;
margin-left: 8px;
font-size: 12px;
}
[data-theme='light'] {
/* Palette: plus nuancé, moins "blanc" */
--bg: #eef3f7; /* fond légèrement teinté bleu-gris */
@ -719,7 +816,227 @@ pre {
/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
* { transition: none !important; animation: none !important; }
* { transition: none !important; animation: none !important; }
}
/* ---------------------------------------------
Container Global
--------------------------------------------- */
.lessonComments {
margin-top: var(--space-6);
background: var(--surface); /* Assure-toi que c'est une couleur un peu plus claire que le fond de page */
border: 1px solid var(--border-subtle);
border-radius: var(--r-3);
/* On enlève le padding global pour coller les éléments aux bords si besoin,
ou on le garde pour un effet "carte" */
padding: var(--space-5);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.lessonComments h3 {
font-size: 1.1rem;
font-weight: 700;
color: var(--text);
margin-bottom: var(--space-4);
display: flex;
align-items: center;
gap: 10px;
}
/* ---------------------------------------------
Liste des commentaires
--------------------------------------------- */
.commentsList {
list-style: none;
padding: 0;
margin: 0 0 var(--space-6) 0;
display: flex;
flex-direction: column;
gap: var(--space-4); /* Espace entre les commentaires */
}
.commentItem {
background: var(--neutral-100); /* Un fond très léger pour détacher le commentaire */
border: 1px solid var(--border-subtle);
border-radius: var(--r-2);
padding: var(--space-4);
transition: border-color 0.2s ease;
}
.commentItem:hover {
border-color: var(--border-strong);
}
/* En-tête du commentaire (Auteur + Date) */
.commentHeader {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--space-3);
padding-bottom: var(--space-3);
border-bottom: 1px solid var(--border-subtle);
}
.commentAuthor {
font-weight: 700;
color: var(--primary); /* Couleur primaire pour l'auteur */
font-size: 0.95rem;
display: flex;
align-items: center;
gap: 8px;
}
/* Petit point décoratif avant le nom */
.commentAuthor::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
background-color: var(--primary);
border-radius: 50%;
opacity: 0.6;
}
.commentDate {
font-size: 0.8rem;
color: var(--text-muted);
}
/* Contenu du texte */
.commentContent {
color: var(--text);
font-size: 0.95rem;
line-height: 1.6;
}
/* Markdown Styles dans les commentaires */
.commentContent p { margin-bottom: 0.8em; }
.commentContent p:last-child { margin-bottom: 0; }
.commentContent code {
font-family: 'Fira Code', monospace;
background: rgba(124, 58, 237, 0.1); /* Petite teinte violette légère */
color: var(--primary);
padding: 2px 5px;
border-radius: 4px;
font-size: 0.9em;
}
.commentContent pre {
background: #1e1e2e; /* Fond sombre style IDE */
color: #cdd6f4;
padding: 15px;
border-radius: 8px;
overflow-x: auto;
margin: 10px 0;
border: 1px solid rgba(255,255,255,0.05);
}
.commentContent a {
color: var(--primary);
text-decoration: none;
border-bottom: 1px dotted var(--primary);
}
.commentContent a:hover { border-bottom-style: solid; }
/* ---------------------------------------------
Formulaire "Éditeur Riche"
--------------------------------------------- */
.commentFormBlock {
margin-top: var(--space-4);
}
.commentForm {
background: var(--surface);
border: 1px solid var(--border-strong); /* Bordure plus visible */
border-radius: var(--r-2);
overflow: hidden; /* Pour que les enfants ne dépassent pas des coins */
transition: box-shadow 0.2s;
}
.commentForm:focus-within {
box-shadow: 0 0 0 2px var(--primary-focus, rgba(124, 58, 237, 0.3));
border-color: var(--primary);
}
/* La barre d'outils collée au textarea */
.commentToolbar {
background: var(--neutral-200); /* Fond gris clair/sombre pour la barre */
padding: 8px 12px;
border-bottom: 1px solid var(--border-subtle);
display: flex;
gap: 8px;
}
.commentToolbar .btnTool {
background: transparent;
border: none;
color: var(--text-muted);
cursor: pointer;
padding: 6px;
border-radius: 4px;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
}
.commentToolbar .btnTool:hover {
background: rgba(0,0,0,0.05); /* Ou blanc semi-transparent en dark mode */
color: var(--primary);
}
/* Le champ texte */
.commentField {
padding: 0; /* On enlève le padding du container */
}
.commentField textarea {
width: 100%; /* Prend toute la largeur */
border: none; /* Pas de bordure, c'est le container .commentForm qui gère */
background: transparent;
color: var(--text);
padding: 15px;
min-height: 120px;
resize: vertical;
font-family: inherit;
outline: none; /* Le focus est géré par le parent */
display: block; /* Évite les espaces fantômes */
line-height: 1.5;
}
/* Footer du formulaire (Aide + Bouton) */
.formActions {
padding: 10px 15px;
background: var(--neutral-100); /* Pied de formulaire légèrement différent */
border-top: 1px solid var(--border-subtle);
display: flex;
justify-content: space-between; /* Aide à gauche, Bouton à droite */
align-items: center;
}
.commentHelp {
margin: 0;
font-size: 0.75rem;
color: var(--text-muted);
font-style: italic;
}
.lessonComments .btn {
background: var(--primary);
color: #fff;
border: none;
padding: 8px 20px;
border-radius: 6px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
font-size: 0.9rem;
}
.lessonComments .btn:hover {
background: var(--bg, #6d28d9);
transform: translateY(-1px);
}
/* Responsive */
@ -1345,7 +1662,7 @@ footer { background-color: var(--card); color: var(--text-muted); }
form {
display: flex;
flex-direction: column;
width: 50%;
width: 90%;
margin: 20px auto;
}
@ -1360,7 +1677,7 @@ form {
border-radius: 10px; /* Bordure arrondie */
box-shadow: var(--shadow-1); /* Ombre légère */
margin: 20px auto;
width: 50%;
width: min(680px, 92%);
}
.login-form {
@ -1425,6 +1742,82 @@ input[type="text"], input[type="email"], input[type="password"], textarea {
color: var(--fg);
}
/*
Système de formulaires générique pour un rendu cohérent avec le site
À appliquer avec class="form" sur <form> (fonctionne aussi avec {{ form.as_p }})
*/
.form {
width: 100%;
}
.form p { /* Django {{ form.as_p }} */
display: flex;
flex-direction: column;
gap: 6px;
margin: 0 0 14px 0;
}
.form label {
font-weight: 600;
color: var(--text);
}
.form input[type="text"],
.form input[type="email"],
.form input[type="password"],
.form input[type="url"],
.form input[type="number"],
.form input[type="file"],
.form input[type="search"],
.form input[type="tel"],
.form select,
.form textarea {
width: 100%;
padding: 10px 12px;
border: 1px solid var(--border);
border-radius: var(--r-2);
background-color: var(--surface);
color: var(--text);
box-shadow: inset var(--shadow-1);
transition: border-color var(--transition-1), box-shadow var(--transition-1), background-color var(--transition-1);
}
.form input:focus,
.form select:focus,
.form textarea:focus {
outline: none;
box-shadow: var(--focus-ring);
border-color: var(--primary);
}
.form .helptext,
.form small.helptext {
color: var(--text-muted);
font-size: 0.9rem;
}
/* Erreurs Django: ul.errorlist > li */
.form ul.errorlist {
list-style: none;
margin: 0 0 6px 0;
padding: 8px 10px;
border: 1px solid color-mix(in oklab, var(--danger) 60%, var(--border));
background: color-mix(in oklab, var(--danger) 12%, var(--surface));
color: var(--danger);
border-radius: var(--r-2);
}
.form ul.errorlist li { margin: 0; }
.form .actions,
.form .form-actions {
display: flex;
gap: 8px;
justify-content: flex-end;
margin-top: 12px;
}
/*
Système de boutons harmonisé avec le thème
Utilise les tokens de couleurs et de rayons définis en haut de fichier.