Add initial migrations, admin configurations, and base CSS for the project
This commit is contained in:
parent
16897b6010
commit
8fe6fe5390
19 changed files with 2101 additions and 68 deletions
0
core/__init__.py
Normal file
0
core/__init__.py
Normal file
26
core/admin.py
Normal file
26
core/admin.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
from django.contrib import admin
|
||||
from .models import SiteSettings
|
||||
|
||||
@admin.register(SiteSettings)
|
||||
class SiteSettingsAdmin(admin.ModelAdmin):
|
||||
# On empêche d'ajouter une nouvelle config s'il en existe déjà une
|
||||
def has_add_permission(self, request):
|
||||
return not SiteSettings.objects.exists()
|
||||
|
||||
# On empêche de supprimer la config (trop dangereux)
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
# Petite astuce visuelle pour l'admin
|
||||
fieldsets = (
|
||||
('Général', {
|
||||
'fields': ('site_name', 'site_logo')
|
||||
}),
|
||||
('Réseaux Sociaux', {
|
||||
'fields': ('facebook_url', 'twitter_url', 'youtube_url'),
|
||||
'classes': ('collapse',) # Cache cette section par défaut pour alléger
|
||||
}),
|
||||
('Contact', {
|
||||
'fields': ('contact_email',)
|
||||
}),
|
||||
)
|
||||
5
core/apps.py
Normal file
5
core/apps.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CoreConfig(AppConfig):
|
||||
name = 'core'
|
||||
33
core/migrations/0001_initial.py
Normal file
33
core/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Generated by Django 6.0 on 2025-12-10 18:32
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SiteSettings',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('site_name', models.CharField(default='Mon Super Site', max_length=200)),
|
||||
('site_logo', models.ImageField(blank=True, upload_to='settings/')),
|
||||
('contact_email', models.EmailField(blank=True, max_length=254)),
|
||||
('facebook_url', models.URLField(blank=True)),
|
||||
('twitter_url', models.URLField(blank=True)),
|
||||
('youtube_url', models.URLField(blank=True)),
|
||||
('instagram_url', models.URLField(blank=True)),
|
||||
('linkedin_url', models.URLField(blank=True)),
|
||||
('github_url', models.URLField(blank=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Réglages du site',
|
||||
'verbose_name_plural': 'Réglages du site',
|
||||
},
|
||||
),
|
||||
]
|
||||
0
core/migrations/__init__.py
Normal file
0
core/migrations/__init__.py
Normal file
29
core/models.py
Normal file
29
core/models.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
from django.db import models
|
||||
|
||||
class SiteSettings(models.Model):
|
||||
site_name = models.CharField(max_length=200, default="Mon Super Site")
|
||||
site_logo = models.ImageField(upload_to='settings/', blank=True)
|
||||
contact_email = models.EmailField(blank=True)
|
||||
|
||||
# Réseaux sociaux
|
||||
facebook_url = models.URLField(blank=True)
|
||||
twitter_url = models.URLField(blank=True)
|
||||
youtube_url = models.URLField(blank=True)
|
||||
instagram_url = models.URLField(blank=True)
|
||||
linkedin_url = models.URLField(blank=True)
|
||||
github_url = models.URLField(blank=True)
|
||||
|
||||
# L'astuce pour qu'il n'y ait qu'un seul réglage
|
||||
def save(self, *args, **kwargs):
|
||||
self.pk = 1 # On force l'ID à 1. Si tu sauvegardes, ça écrase l'existant.
|
||||
super(SiteSettings, self).save(*args, **kwargs)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
pass # On empêche la suppression. On ne peut pas supprimer les réglages.
|
||||
|
||||
def __str__(self):
|
||||
return "Configuration Générale"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Réglages du site"
|
||||
verbose_name_plural = "Réglages du site"
|
||||
3
core/tests.py
Normal file
3
core/tests.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
3
core/views.py
Normal file
3
core/views.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
59
courses/migrations/0001_initial.py
Normal file
59
courses/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# Generated by Django 6.0 on 2025-12-10 18:04
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Course',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200)),
|
||||
('slug', models.SlugField(unique=True)),
|
||||
('tags', models.CharField(max_length=200)),
|
||||
('thumbnail', models.ImageField(default='default.jpg', upload_to='thumbnails/courses/')),
|
||||
('description', models.TextField()),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('enable', models.BooleanField(default=True)),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Module',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200)),
|
||||
('slug', models.SlugField()),
|
||||
('description', models.TextField()),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('enable', models.BooleanField(default=True)),
|
||||
('order', models.PositiveIntegerField()),
|
||||
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='modules', to='courses.course')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Lesson',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200)),
|
||||
('slug', models.SlugField()),
|
||||
('content', models.TextField()),
|
||||
('video_id', models.CharField(blank=True, max_length=200)),
|
||||
('is_premium', models.BooleanField(default=False)),
|
||||
('order', models.PositiveIntegerField()),
|
||||
('module', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lessons', to='courses.module')),
|
||||
],
|
||||
),
|
||||
]
|
||||
BIN
data78HyT4mloSq_Gt.sqlite3
Normal file
BIN
data78HyT4mloSq_Gt.sqlite3
Normal file
Binary file not shown.
1670
static/css/app.css
Normal file
1670
static/css/app.css
Normal file
File diff suppressed because it is too large
Load diff
11
static/css/colors_dark.css
Normal file
11
static/css/colors_dark.css
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/* Theme bridge (DARK) — 2025 design system
|
||||
Minimal overrides; colors and components come from app.css tokens. */
|
||||
html {
|
||||
background-color: var(--bg);
|
||||
color: var(--text);
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
nav.site-nav {
|
||||
background: var(--nav-bg);
|
||||
}
|
||||
14
static/css/colors_light.css
Normal file
14
static/css/colors_light.css
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* Theme bridge (LIGHT) — 2025 design system
|
||||
This file intentionally contains minimal overrides. The full palette,
|
||||
components and tokens live in css/app.css using CSS variables.
|
||||
Keeping this file ensures JS can swap theme stylesheets without FOUC. */
|
||||
|
||||
/* Prefer light-friendly scrollbar & subtle touches without overriding tokens */
|
||||
html[data-theme='light'] {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
/* Optional: ensure nav backdrop looks crisp on light */
|
||||
nav.site-nav {
|
||||
background: var(--nav-bg);
|
||||
}
|
||||
|
|
@ -2,18 +2,54 @@
|
|||
|
||||
{% block content %}
|
||||
<section class="hero">
|
||||
<div class="hero-inner">
|
||||
<h1>Apprenez à coder de A à Z</h1>
|
||||
<p class="hero-sub">Des cours gratuits et payants, structurés et concrets, pour progresser rapidement en programmation.</p>
|
||||
<div class="button-grp hero-cta">
|
||||
<a class="button cta-primary" href="{% url 'register' %}"><i class="fa-solid fa-play"></i> Commencer gratuitement</a>
|
||||
<a class="button cta-secondary" href="{% url 'courses:list' %}"><i class="fa-solid fa-book"></i> Voir les cours</a>
|
||||
<div class="hero-decor" aria-hidden="true"></div>
|
||||
<div class="hero-inner hero-split">
|
||||
|
||||
<div class="hero-text">
|
||||
<h1>Apprenez à coder de A à Z</h1>
|
||||
<p class="hero-sub">Des cours gratuits et payants, structurés et concrets, pour progresser rapidement en programmation.</p>
|
||||
<div class="badge-row" aria-hidden="true">
|
||||
<span class="badge"><i class="fa-solid fa-code"></i> Logiciel, Web, Jeux Vidéos</span>
|
||||
<span class="badge"><i class="fa-solid fa-graduation-cap"></i> Pédagogie claire</span>
|
||||
<span class="badge"><i class="fa-solid fa-laptop-code"></i> Projets concrets</span>
|
||||
</div>
|
||||
<div class="button-grp hero-cta">
|
||||
<a class="button cta-primary" href="{% url 'register' %}"><i class="fa-solid fa-play"></i> Commencer gratuitement</a>
|
||||
<a class="button cta-secondary" href="{% url 'courses:list' %}"><i class="fa-solid fa-book"></i> Voir les cours</a>
|
||||
</div>
|
||||
<div class="hero-trust">
|
||||
<span><i class="fa-solid fa-check"></i> Pas de carte requise pour commencer</span>
|
||||
<span><i class="fa-solid fa-clock"></i> À votre rythme</span>
|
||||
<span><i class="fa-solid fa-certificate"></i> Accès premium en option</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-trust">
|
||||
<span><i class="fa-solid fa-check"></i> Pas de carte requise pour commencer</span>
|
||||
<span><i class="fa-solid fa-clock"></i> À votre rythme</span>
|
||||
<span><i class="fa-solid fa-certificate"></i> Accès premium en option</span>
|
||||
|
||||
<div class="hero-visual">
|
||||
<div class="code-window">
|
||||
<div class="window-header">
|
||||
<div class="dots">
|
||||
<span class="dot red"></span>
|
||||
<span class="dot yellow"></span>
|
||||
<span class="dot green"></span>
|
||||
</div>
|
||||
<span class="filename">main.py — PartirDeZero</span>
|
||||
</div>
|
||||
<div class="window-content">
|
||||
<pre class="code-block"><code><span class="line"><span class="qn">def</span> <span class="fn">devenir_dev_autonome</span>(etudiant):</span>
|
||||
<span class="line"> <span class="cm"># Objectif: Maîtriser Python & Django</span></span>
|
||||
<span class="line"> motivation = <span class="kw">True</span></span>
|
||||
<span class="line"> projet_concret = <span class="st">"Mon Portfolio"</span></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="qn">if</span> motivation <span class="ow">and</span> etudiant.<span class="fn">suit_le_cours</span>():</span>
|
||||
<span class="line"> etudiant.<span class="fn">skills</span>.<span class="fn">append</span>(<span class="st">"Backend"</span>)</span>
|
||||
<span class="line"> <span class="qn">return</span> <span class="st">f"Succès : {projet_concret} déployé !"</span></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="cm"># Lancez votre carrière aujourd'hui</span></span>
|
||||
<span class="line"><span class="fn">print</span>(<span class="fn">devenir_dev_autonome</span>(<span class="st">"Toi"</span>))</span></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -37,7 +73,7 @@
|
|||
{% block course %}
|
||||
{% include "courses/partials/list.html" %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
<section class="pricing-teaser">
|
||||
<h2>Gratuit pour commencer, Premium pour aller plus loin</h2>
|
||||
<ul class="ul-arrow">
|
||||
|
|
@ -51,11 +87,11 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<section class="carousel">
|
||||
<section class="carousel" aria-label="Cours en vedette">
|
||||
<h2>Cours en vedette</h2>
|
||||
<div class="carousel-track">
|
||||
<div class="carousel-track" role="list">
|
||||
{% for course in courses|slice:":6" %}
|
||||
<a class="carousel-item card" href="{% url 'courses:show' course.id course.name|slugify %}">
|
||||
<a class="carousel-item card" href="{% url 'courses:show' course.id course.name|slugify %}" role="listitem">
|
||||
<div class="ratio-16x9">
|
||||
<img src="{{ course.thumbnail.url }}" alt="{{ course.name }}" loading="lazy">
|
||||
</div>
|
||||
|
|
@ -74,15 +110,21 @@
|
|||
<h2>Ils progressent avec Partir de zéro</h2>
|
||||
<div class="testimonials-grid">
|
||||
<div class="testimonial">
|
||||
<p>“Des cours clairs et progressifs. J’ai enfin compris Django et j’ai lancé mon premier projet.”</p>
|
||||
<blockquote>
|
||||
<p>Des cours clairs et progressifs. J’ai enfin compris Django et j’ai lancé mon premier projet.</p>
|
||||
</blockquote>
|
||||
<div class="who">Alexandre — Débutant devenu autonome</div>
|
||||
</div>
|
||||
<div class="testimonial">
|
||||
<p>“L’approche projet et les explications pas-à-pas m’ont fait gagner des semaines.”</p>
|
||||
<blockquote>
|
||||
<p>L’approche projet et les explications pas-à-pas m’ont fait gagner des semaines.</p>
|
||||
</blockquote>
|
||||
<div class="who">Sarah — Étudiante en informatique</div>
|
||||
</div>
|
||||
<div class="testimonial">
|
||||
<p>“Parfait pour reprendre les bases et aller plus loin. Le mode sombre est top 👌.”</p>
|
||||
<blockquote>
|
||||
<p>Parfait pour reprendre les bases et aller plus loin. Le mode sombre est top 👌.</p>
|
||||
</blockquote>
|
||||
<div class="who">Yassine — Dev front-end</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,40 @@
|
|||
{% block 'profile-nav' %}
|
||||
<div class="profile-header">
|
||||
<h2>Profil de {{ user.username }}</h2>
|
||||
<img src="/{{ user.profile.avatar }}" alt="Profile Picture" class="profile-picture">
|
||||
</div>
|
||||
<!-- On affiche le menu que si l'id du profil est égale à celui de l'utilisateur -->
|
||||
{% if user.id == request.user.id %}
|
||||
<div class="profile-nav">
|
||||
<ul>
|
||||
<li><a href="{% url 'profile' %}">Profil</a></li>
|
||||
<li><a href="{% url 'account_update' %}">Paramètre de compte</a></li>
|
||||
<li><a href="{% url 'user_courses' %}">Mes cours</a></li>
|
||||
<div class="profile-cover">
|
||||
<div class="profile-cover-bg"></div>
|
||||
<div class="profile-cover-content">
|
||||
<img src="/{{ user.profile.avatar }}" alt="Avatar de {{ user.username }}" class="profile-avatar">
|
||||
<div class="profile-identity">
|
||||
<h1 class="profile-name">{{ user.profile.first_name|default:user.username }} {{ user.profile.last_name }}</h1>
|
||||
<div class="profile-username">@{{ user.username }}</div>
|
||||
{% if user.profile.biography %}
|
||||
<p class="profile-bio">{{ user.profile.biography }}</p>
|
||||
{% endif %}
|
||||
<ul class="profile-meta">
|
||||
<li><i class="fa-regular fa-calendar"></i> Inscrit depuis {{ user.date_joined|date:"F Y" }}</li>
|
||||
<li>
|
||||
<i class="fa-solid fa-book"></i>
|
||||
{% with user.course_set.count as courses_count %}
|
||||
{{ courses_count }} cours
|
||||
{% endwith %}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
<div class="profile-actions-rail">
|
||||
{% if user.id == request.user.id %}
|
||||
<a href="{% url 'profile_update' %}" class="btn btn-primary">Éditer le profil</a>
|
||||
<a href="{% url 'account_update' %}" class="btn btn-secondary">Paramètres</a>
|
||||
{% else %}
|
||||
<button class="btn btn-primary" disabled>Suivre</button>
|
||||
<button class="btn btn-secondary" disabled>Message</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="profile-tabs">
|
||||
<ul>
|
||||
<li class="active"><a href="#about">À propos</a></li>
|
||||
{% if user.id == request.user.id %}
|
||||
<li><a href="{% url 'user_courses' %}">Mes cours</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
|
|
@ -1,16 +1,31 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% block content %}
|
||||
<section class="profile-section">
|
||||
{% block profile-nav %}
|
||||
{% include "../partials/_profile_nav.html" %}
|
||||
{% endblock %}
|
||||
<div class="profile-details">
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ user_form.as_p }}
|
||||
<button type="submit" class="btn btn-primary">Mettre à jour</button>
|
||||
</form>
|
||||
</div>
|
||||
{% include "../partials/_profile_nav.html" %}
|
||||
|
||||
</section>
|
||||
<div class="profile-content">
|
||||
<div class="profile-grid">
|
||||
<div class="profile-card">
|
||||
<h3>Paramètres du compte</h3>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ user_form.as_p }}
|
||||
<div class="text-right" style="margin-top:12px; display:flex; gap:8px; justify-content:flex-end;">
|
||||
<a href="{% url 'profile' %}" class="btn btn-secondary">Annuler</a>
|
||||
<button type="submit" class="btn btn-primary">Enregistrer</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="profile-card">
|
||||
<h3>Conseils</h3>
|
||||
<ul class="profile-about-list">
|
||||
<li>Assurez-vous que votre adresse email est valide pour récupérer votre compte.</li>
|
||||
<li>Utilisez un mot de passe unique et robuste (mélange de lettres, chiffres, symboles).</li>
|
||||
<li>Votre nom d’utilisateur est visible publiquement — choisissez-le avec soin.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
@ -1,13 +1,49 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% block content %}
|
||||
<section class="profile-section">
|
||||
{% block profile-nav %}
|
||||
{% include "../partials/_profile_nav.html" %}
|
||||
{% endblock %}
|
||||
<div class="profile-details">
|
||||
<p><strong>Pseudo :</strong> {{ user.username }}</p>
|
||||
<p><strong>Date d'nscription :</strong> {{ user.date_joined|date:"F j, Y" }}</p>
|
||||
<p><strong>Bio de profil :</strong> {{ user.profile.biography }}</p>
|
||||
{% include "../partials/_profile_nav.html" %}
|
||||
|
||||
<div class="profile-content">
|
||||
<div class="profile-grid">
|
||||
<div class="profile-card" id="about">
|
||||
<h3>À propos</h3>
|
||||
<ul class="profile-about-list">
|
||||
<li><strong>Pseudo</strong> : {{ user.username }}</li>
|
||||
<li><strong>Nom complet</strong> : {{ user.profile.first_name }} {{ user.profile.last_name }}</li>
|
||||
<li><strong>Inscription</strong> : {{ user.date_joined|date:"j F Y" }}</li>
|
||||
</ul>
|
||||
{% if user.profile.biography %}
|
||||
<p class="profile-bio-body">{{ user.profile.biography }}</p>
|
||||
{% else %}
|
||||
<p class="profile-bio-body muted">Aucune bio pour le moment.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="profile-card">
|
||||
<h3>Cours publiés</h3>
|
||||
{% with courses=user.course_set.all %}
|
||||
{% if courses %}
|
||||
<ul class="profile-courses">
|
||||
{% for course in courses|slice:":6" %}
|
||||
<li>
|
||||
<a href="{% url 'courses:show' course_id=course.id course_name=course.slug %}">
|
||||
<img src="/{{ course.thumbnail }}" alt="{{ course.name }}" class="course-thumb-mini">
|
||||
<span>{{ course.name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="muted">Aucun cours publié.</p>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
<div class="profile-card">
|
||||
<h3>Activité</h3>
|
||||
<p class="muted">Le fil d’activité de cet utilisateur arrive bientôt.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
@ -1,18 +1,53 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% block content %}
|
||||
<section class="profile-section">
|
||||
{% block profile-nav %}
|
||||
{% include "../partials/_profile_nav.html" %}
|
||||
{% endblock %}
|
||||
<div class="profile-details">
|
||||
<p><strong>Username:</strong> {{ user.username }}</p>
|
||||
<p><strong>Email:</strong> {{ user.email }}</p>
|
||||
<p><strong>Nom complet:</strong> {{ user.profile.first_name }} {{ user.profile.last_name }}</p>
|
||||
<p><strong>Inscription:</strong> {{ user.date_joined|date:"F j, Y" }}</p>
|
||||
<p><strong>Bio:</strong> {{ user.profile.biography }}</p>
|
||||
</div>
|
||||
<div class="profile-actions">
|
||||
<a href="{% url 'profile_update' %}" class="btn btn-primary">Modifier le profil publique</a><br><br>
|
||||
{% include "../partials/_profile_nav.html" %}
|
||||
|
||||
<div class="profile-content">
|
||||
<div class="profile-grid">
|
||||
<div class="profile-card" id="about">
|
||||
<h3>À propos</h3>
|
||||
<ul class="profile-about-list">
|
||||
<li><strong>Pseudo</strong> : {{ user.username }}</li>
|
||||
<li><strong>Nom complet</strong> : {{ user.profile.first_name }} {{ user.profile.last_name }}</li>
|
||||
<li><strong>Email</strong> : {{ user.email }}</li>
|
||||
<li><strong>Inscription</strong> : {{ user.date_joined|date:"j F Y" }}</li>
|
||||
</ul>
|
||||
{% if user.profile.biography %}
|
||||
<p class="profile-bio-body">{{ user.profile.biography }}</p>
|
||||
{% else %}
|
||||
<p class="profile-bio-body muted">Ajoutez une bio pour présenter votre parcours.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="profile-card">
|
||||
<h3>Mes cours</h3>
|
||||
{% with courses=user.course_set.all %}
|
||||
{% if courses %}
|
||||
<ul class="profile-courses">
|
||||
{% for course in courses|slice:":6" %}
|
||||
<li>
|
||||
<a href="{% url 'courses:show' course_id=course.id course_name=course.slug %}">
|
||||
<img src="/{{ course.thumbnail }}" alt="{{ course.name }}" class="course-thumb-mini">
|
||||
<span>{{ course.name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<div class="text-right">
|
||||
<a class="btn btn-secondary btn-sm" href="{% url 'user_courses' %}">Voir tous mes cours</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="muted">Aucun cours publié pour le moment.</p>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
<div class="profile-card">
|
||||
<h3>Activité</h3>
|
||||
<p class="muted">Le fil d’activité arrive bientôt.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
@ -1,11 +1,39 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% block content %}
|
||||
<section>
|
||||
<h2>Update Profile</h2>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ profile_form.as_p }}
|
||||
<button type="submit">Modifier</button>
|
||||
</form>
|
||||
<section class="profile-section">
|
||||
{% include "../partials/_profile_nav.html" %}
|
||||
|
||||
<div class="profile-content">
|
||||
<div class="profile-grid">
|
||||
<div class="profile-card">
|
||||
<h3>Modifier mon profil public</h3>
|
||||
<div style="display:flex; align-items:center; gap:16px; margin: 10px 0 14px;">
|
||||
<img src="/{{ user.profile.avatar }}" alt="Avatar actuel" class="profile-avatar" style="width:72px;height:72px;margin-top:0;">
|
||||
<div>
|
||||
<div class="muted">Aperçu de l’avatar actuel</div>
|
||||
<small class="muted">Vous pouvez téléverser une nouvelle image ci‑dessous.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ profile_form.as_p }}
|
||||
<div class="text-right" style="margin-top:12px; display:flex; gap:8px; justify-content:flex-end;">
|
||||
<a href="{% url 'profile' %}" class="btn btn-secondary">Annuler</a>
|
||||
<button type="submit" class="btn btn-primary">Enregistrer</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="profile-card">
|
||||
<h3>Conseils</h3>
|
||||
<ul class="profile-about-list">
|
||||
<li>Utilisez votre vrai nom pour être plus facilement reconnu.</li>
|
||||
<li>Une bio claire aide la communauté à mieux vous connaître.</li>
|
||||
<li>Privilégiez une photo carrée pour un meilleur rendu.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue