diff --git a/devart/settings.py b/devart/settings.py index 1936a8a..044d68c 100644 --- a/devart/settings.py +++ b/devart/settings.py @@ -14,6 +14,8 @@ from pathlib import Path import os from dotenv import load_dotenv +import devart.context_processor + # Charger les variables d'environnement depuis le fichier .env load_dotenv() @@ -74,7 +76,8 @@ TEMPLATES = [ 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', - + + 'devart.context_processor.app_version', 'core.context_processor.site_settings', 'courses.context_processors.course_list', ], @@ -152,3 +155,18 @@ STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')] # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +# On défini une fonction qui va s'occuper de récupérer la version actuelle de l'application +def get_git_version(): + try: + import subprocess + hash_version = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).strip().decode('utf-8') + app_version = subprocess.check_output( + ["git", "describe", "--tags", "--abbrev=0"], + stderr=subprocess.STDOUT + ).strip().decode('utf-8') + return app_version + " (" + hash_version + ")" + except Exception: + return 'Dev / Pas de git' + +GIT_VERSION = get_git_version() \ No newline at end of file diff --git a/static/css/app.css b/static/css/app.css index 8d25550..9aa06af 100644 --- a/static/css/app.css +++ b/static/css/app.css @@ -79,8 +79,9 @@ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* Layout */ - --container-w: 1100px; - --gutter: 20px; + /* Fluid container and gutters for responsive spacing */ + --container-w: clamp(320px, 92vw, 1100px); + --gutter: clamp(14px, 3vw, 24px); --focus-ring: 0 0 0 3px rgba(78,158,214,0.45); /* Utility base colors */ @@ -108,6 +109,23 @@ --border-glass-light: rgba(255,255,255,0.05); } +/* + Mobile width guardrail + - Cap container width on touch devices to improve readability and avoid edge overflows +*/ +@media (hover: none) and (pointer: coarse) { + :root { + /* Keep fluid gutters but prevent overly wide lines on large/mobile landscape */ + --container-w: min(92vw, 480px); + } + html, body { overflow-x: hidden; } +} + +/* Global box-sizing reset to prevent width overflow on mobile + Ensures padding/border are included in the element's total width/height */ +html { box-sizing: border-box; } +*, *::before, *::after { box-sizing: inherit; } + /* Light theme values — applied via colors_light.css inclusion */ /* ========================== @@ -469,8 +487,7 @@ body { height: 100vh; /* Ensure total box never exceeds the viewport width (padding + border included) */ box-sizing: border-box; - width: min(85vw, 380px); - max-width: 100vw; + width: min(92vw, 380px); margin: 0; /* Safe-area aware padding on the right (iOS notch) */ padding: var(--space-5) max(var(--gutter), env(safe-area-inset-right)) var(--space-5) var(--gutter); @@ -510,8 +527,8 @@ body { z-index: 1100; } - .navbar ul { flex-direction: column; width: 100%; } - .navbar li { margin: 0; } + .navbar ul { flex-direction: column; width: 100%; align-items: flex-start; } + .navbar li { margin: 0; width: 100%; } .navbar a { display: block; padding: 12px 14px; border-radius: var(--r-1); } /* Dropdowns behave as inline lists on mobile */ @@ -524,18 +541,22 @@ body { padding-left: 10px; } - .navbar ul ul li { border: 0; margin: 0; padding: 6px 8px; } + .navbar ul ul { align-items: flex-start; } + .navbar ul ul li { border: 0; margin: 0; padding: 6px 8px; width: 100%; } + .navbar ul ul a { text-align: left; } .navend { width: 100%; margin-top: auto; /* push to bottom */ display: flex; flex-direction: column; - align-items: stretch; + align-items: flex-start; /* start-align items on mobile */ + justify-content: flex-start; gap: 6px; } - .navend ul { width: 100%; } + .navend ul { width: 100%; align-items: flex-start; } + .navend a { text-align: left; } } /* Respect reduced motion preferences */ @@ -650,17 +671,18 @@ section { display: flex; flex-direction: column; padding: var(--space-6) var(--gutter); - width: min(100%, 60%); - margin: 20px auto; + width: 100%; + max-width: var(--container-w); + margin: clamp(12px, 3vw, 24px) auto; } .courseNav { display: block; float: left; - position: fixed; + position: sticky; left: 0; - top: 150px; - max-width: 15%; + top: clamp(64px, 12vh, 150px); + max-width: clamp(220px, 22vw, 300px); border: 1px solid; } @@ -691,9 +713,7 @@ section { h1 { color: var(--primary); font-size: clamp(1.8rem, 4vw, 2.5rem); - border-left: 5px solid var(--accent); - border-bottom: 1px solid var(--accent); - padding-left: 10px; + padding-left: var(--space-3); } h2 { @@ -703,8 +723,15 @@ h2 { img { max-width: 100%; + height: auto; } +/* Make embedded media responsive */ +iframe, video { max-width: 100%; height: auto; } + +/* Responsive tables: wrap in a container if needed */ +.table-responsive { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; } + .card-header img.thumbnails { transition: transform 1s ease } @@ -714,21 +741,20 @@ img { } .container-inline { - display: flex; - flex-direction: row; - flex-wrap: wrap; - gap: 20px; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: var(--space-5); } .card { display: flex; flex-direction: column; - max-width: 250px; + width: 100%; border-left: 1px solid var(--border); border-top: 1px solid var(--border); border-radius: var(--r-2); overflow: hidden; - margin: 20px; + margin: 0; background: var(--card); box-shadow: var(--shadow-1); transition: transform var(--transition-1), box-shadow var(--transition-1); @@ -767,7 +793,7 @@ img { .def-author { display: flex; - padding: 10px; + padding: var(--space-3); flex-direction: row; align-items: center; font-size: 0.8rem; @@ -780,18 +806,18 @@ img { } pre { - border-radius: 5px; + border-radius: var(--r-2); /* Ne dépasse pas du parent en largeur et défile si nécessaire */ - max-width: 800px; + max-width: clamp(320px, 100%, 800px); overflow: auto; /* scroll horizontal et vertical si besoin */ - max-height: 800px; + max-height: clamp(360px, 70vh, 800px); } /* ====== Homepage enhancements ====== */ .hero { display: block; width: 100%; - padding: 80px 20px 56px; + padding: clamp(48px, 10vw, 96px) var(--gutter) clamp(32px, 6vw, 64px); text-align: center; background: radial-gradient(1200px 600px at 50% -10%, rgba(78,158,214,0.20), transparent 60%), @@ -800,10 +826,7 @@ pre { position: relative; } -.hero-inner { - max-width: 960px; - margin: 0 auto; -} +.hero-inner { max-width: var(--container-w); margin: 0 auto; padding: 0 var(--gutter); } .hero-decor { position: absolute; @@ -816,31 +839,12 @@ pre { opacity: .6; } -.hero .hero-sub { - font-size: 1.125rem; - font-weight: 500; - margin: 10px auto 0; - max-width: 800px; -} +.hero .hero-sub { font-size: clamp(1rem, 2.4vw, 1.125rem); font-weight: 500; margin: var(--space-3) auto 0; max-width: 65ch; } -.badge-row { display: flex; gap: 10px; justify-content: center; margin: 18px 0 6px; flex-wrap: wrap; } -.badge { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 6px 10px; - border: 1px solid var(--border-subtle); - border-radius: 999px; - background: color-mix(in oklab, var(--card) 80%, transparent); - font-size: .9rem; - color: var(--text-muted); -} +.badge-row { display: flex; gap: var(--space-3); justify-content: center; margin: var(--space-4) 0 var(--space-2); flex-wrap: wrap; } +.badge { display: inline-flex; align-items: center; gap: var(--space-2); padding: 6px 10px; border: 1px solid var(--border-subtle); border-radius: 999px; background: color-mix(in oklab, var(--card) 80%, transparent); font-size: .9rem; color: var(--text-muted); } -.hero-cta .button { - padding: 12px 18px; - font-size: 1rem; - border-radius: 6px; -} +.hero-cta .button { padding: 12px 18px; font-size: 1rem; border-radius: var(--r-2); } .cta-primary { /* Make primary CTA more visible */ @@ -927,11 +931,12 @@ pre { } .pricing-teaser { - width: 60%; - margin: 10px auto 40px; + width: 100%; + max-width: 820px; + margin: var(--space-3) auto var(--space-6); border: 1px solid var(--border); border-radius: var(--r-3); - padding: 20px; + padding: var(--space-5); background: var(--card); } @@ -943,7 +948,7 @@ pre { .carousel-track { display: grid; grid-auto-flow: column; - grid-auto-columns: 80%; + grid-auto-columns: minmax(260px, 80%); gap: var(--space-4); overflow-x: auto; scroll-snap-type: x mandatory; @@ -967,7 +972,7 @@ pre { display: grid; gap: var(--space-4); } -.testimonials-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); } +.testimonials-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--space-4); } .testimonial { background: var(--card); border: 1px solid var(--border); diff --git a/templates/home.html b/templates/home.html index fd4b276..76ebca2 100644 --- a/templates/home.html +++ b/templates/home.html @@ -6,7 +6,7 @@
Des cours gratuits, structurés et concrets, pour progresser rapidement en programmation.
\ No newline at end of file