v1.0.0 — redesign complet charte graphique V2
- 8 états météo : arc-en-ciel, ensoleillé, brumeux, nuageux, pluvieux, orageux, tempête, fin du monde - Fonts : Fredoka (titres) + Nunito (texte), palette V2 (bleu #3B82F6, orange #F59E0B, rouge #EF4444) - Nav flottante : Météo / Radar / Bilan / Paramètres (La Carte supprimée) - Thème clair / sombre (toggle dans Paramètres) - Icône app : papier quadrillé + 0 rouge manuscrit - Illustrations météo CSS pures (soleil, nuages, pluie, éclair, champignon nucléaire, arc-en-ciel) - Panel admin centralisé dans Paramètres (flash, classe, évaluations, météo, membres) - Bottom nav flottante avec safe-area pour ne plus toucher la nav système Android - Suppression des anciennes vues (cards.ts, map.ts, plus.ts, exam-form.ts)
This commit is contained in:
parent
8c79476d96
commit
2f2f363650
23 changed files with 1679 additions and 1715 deletions
|
|
@ -1,90 +1,128 @@
|
|||
/**
|
||||
* Types et métadonnées partagés entre le serveur et le front.
|
||||
* Aucun import runtime ici : ce module est consommé tel quel par les deux côtés.
|
||||
* Charte graphique V2 — 8 états météo.
|
||||
*/
|
||||
|
||||
/** Statut météorologique d'une évaluation. */
|
||||
export type WeatherKind = 'soleil' | 'brouillard' | 'vent' | 'orage' | 'tempete'
|
||||
export type WeatherKind =
|
||||
| 'arcenciel' // aucune évaluation + événement spécial
|
||||
| 'soleil' // aucune évaluation
|
||||
| 'brouillard' // suspicion
|
||||
| 'nuageux' // petite évaluation / QCM
|
||||
| 'pluie' // évaluation classique
|
||||
| 'orage' // DS / contrôle surveillé
|
||||
| 'tempete' // bac blanc / examen blanc
|
||||
| 'fin_du_monde' // vrai bac
|
||||
|
||||
export const WEATHER_KINDS: WeatherKind[] = ['soleil', 'brouillard', 'vent', 'orage', 'tempete']
|
||||
export const WEATHER_KINDS: WeatherKind[] = [
|
||||
'arcenciel', 'soleil', 'brouillard', 'nuageux', 'pluie', 'orage', 'tempete', 'fin_du_monde',
|
||||
]
|
||||
|
||||
/** Du plus rassurant au plus menaçant. Sert aux tris et au calcul du statut d'une journée. */
|
||||
export const SEVERITY: Record<WeatherKind, number> = {
|
||||
arcenciel: 0,
|
||||
soleil: 0,
|
||||
brouillard: 1,
|
||||
vent: 2,
|
||||
orage: 3,
|
||||
tempete: 4,
|
||||
nuageux: 2,
|
||||
pluie: 3,
|
||||
orage: 4,
|
||||
tempete: 5,
|
||||
fin_du_monde: 6,
|
||||
}
|
||||
|
||||
export interface WeatherMeta {
|
||||
/** Nom affiché, ex. « Alerte Rouge ». */
|
||||
label: string
|
||||
/** Titre long pour les modales et la légende. */
|
||||
title: string
|
||||
icon: string
|
||||
/** Description pédagogique affichée dans la légende. */
|
||||
hint: string
|
||||
/** Couleur d'accent en dur, pour les SVG et jauges. */
|
||||
/** Couleur principale du statut (hex). */
|
||||
hex: string
|
||||
/** Classes Tailwind de la pastille (fond / bordure / texte). */
|
||||
chip: string
|
||||
/** Classe de couleur du texte seule, pour les libellés sur fond neutre. */
|
||||
accent: string
|
||||
/** Classes Tailwind du badge plein. */
|
||||
badge: string
|
||||
/** Classe de couleur du texte seule. */
|
||||
accent: string
|
||||
/** Gradient CSS pour les cartes hero / mini-arts. */
|
||||
gradient: string
|
||||
}
|
||||
|
||||
export const WEATHER: Record<WeatherKind, WeatherMeta> = {
|
||||
arcenciel: {
|
||||
label: 'Arc-en-ciel',
|
||||
title: 'Arc-en-ciel',
|
||||
icon: '🌈',
|
||||
hint: 'Aucune évaluation + événement spécial : sortie, pas de cours…',
|
||||
hex: '#3B82F6',
|
||||
badge: 'bg-blue-500/15 text-blue-300 border-blue-400/30',
|
||||
accent: 'text-blue-400',
|
||||
gradient: 'linear-gradient(145deg,#1570EF,#7555D9)',
|
||||
},
|
||||
soleil: {
|
||||
label: 'Grand Soleil',
|
||||
title: 'Grand Soleil',
|
||||
label: 'Ensoleillé',
|
||||
title: 'Ensoleillé',
|
||||
icon: '☀️',
|
||||
hint: 'Journée calme. Aucun examen répertorié ni suspecté.',
|
||||
hex: '#0284c7',
|
||||
chip: 'bg-sky-500/10 border-sky-500/20 text-sky-400',
|
||||
accent: 'text-sky-400',
|
||||
badge: 'bg-sky-500/15 text-sky-300 border-sky-400/30',
|
||||
hint: 'Aucune évaluation aujourd’hui.',
|
||||
hex: '#FFD43B',
|
||||
badge: 'bg-amber-400/15 text-amber-300 border-amber-400/30',
|
||||
accent: 'text-amber-300',
|
||||
gradient: 'linear-gradient(145deg,#1488FF,#55B8FF)',
|
||||
},
|
||||
brouillard: {
|
||||
label: 'Brouillard',
|
||||
title: 'Brouillard',
|
||||
label: 'Brumeux',
|
||||
title: 'Brumeux',
|
||||
icon: '🌫️',
|
||||
hint: 'Zone d’incertitude. Rumeur ou sous-entendu d’un professeur.',
|
||||
hex: '#7c3aed',
|
||||
chip: 'bg-purple-500/10 border-purple-500/20 text-purple-400',
|
||||
accent: 'text-purple-400',
|
||||
badge: 'bg-purple-500/15 text-purple-300 border-purple-400/30',
|
||||
hint: 'Suspicion d’évaluation aujourd’hui.',
|
||||
hex: '#9CA3AF',
|
||||
badge: 'bg-slate-400/15 text-slate-300 border-slate-400/30',
|
||||
accent: 'text-slate-300',
|
||||
gradient: 'linear-gradient(145deg,#A6B5C9,#7288A8)',
|
||||
},
|
||||
vent: {
|
||||
label: 'Coup de vent',
|
||||
title: 'Coup de vent',
|
||||
icon: '💨',
|
||||
hint: 'Interrogation surprise potentielle ou petit QCM, coefficient faible.',
|
||||
hex: '#d97706',
|
||||
chip: 'bg-amber-500/10 border-amber-500/20 text-amber-400',
|
||||
accent: 'text-amber-400',
|
||||
badge: 'bg-amber-500/15 text-amber-300 border-amber-400/30',
|
||||
nuageux: {
|
||||
label: 'Nuageux',
|
||||
title: 'Nuageux',
|
||||
icon: '☁️',
|
||||
hint: 'Petite évaluation, exposé ou QCM aujourd’hui.',
|
||||
hex: '#60A5FA',
|
||||
badge: 'bg-sky-400/15 text-sky-300 border-sky-400/30',
|
||||
accent: 'text-sky-400',
|
||||
gradient: 'linear-gradient(145deg,#57B7FF,#2D86ED)',
|
||||
},
|
||||
pluie: {
|
||||
label: 'Pluvieux',
|
||||
title: 'Pluvieux',
|
||||
icon: '🌧️',
|
||||
hint: 'Évaluation classique aujourd’hui.',
|
||||
hex: '#3B82F6',
|
||||
badge: 'bg-blue-500/15 text-blue-300 border-blue-400/30',
|
||||
accent: 'text-blue-400',
|
||||
gradient: 'linear-gradient(145deg,#14589B,#092E64)',
|
||||
},
|
||||
orage: {
|
||||
label: 'Orage',
|
||||
title: 'Orage / Pluie battante',
|
||||
icon: '🌩️',
|
||||
hint: 'Devoir surveillé (DS) confirmé ou évaluation de chapitre.',
|
||||
hex: '#e11d48',
|
||||
chip: 'bg-rose-500/10 border-rose-500/20 text-rose-400',
|
||||
accent: 'text-rose-400',
|
||||
badge: 'bg-rose-500/15 text-rose-300 border-rose-400/30',
|
||||
label: 'Orageux',
|
||||
title: 'Orageux',
|
||||
icon: '⛈️',
|
||||
hint: 'Devoir surveillé aujourd’hui.',
|
||||
hex: '#8B5CF6',
|
||||
badge: 'bg-purple-500/15 text-purple-300 border-purple-400/30',
|
||||
accent: 'text-purple-400',
|
||||
gradient: 'linear-gradient(145deg,#291B69,#152758)',
|
||||
},
|
||||
tempete: {
|
||||
label: 'Alerte Rouge',
|
||||
title: 'Alerte Rouge / Tempête',
|
||||
icon: '🚨',
|
||||
hint: 'Examen blanc, épreuve commune ou gros devoir de fin de trimestre.',
|
||||
hex: '#dc2626',
|
||||
chip: 'bg-red-500/10 border-red-500/20 text-red-500',
|
||||
accent: 'text-red-500',
|
||||
label: 'Tempête',
|
||||
title: 'Tempête',
|
||||
icon: '🌀',
|
||||
hint: 'Bac blanc / examen blanc.',
|
||||
hex: '#EF4444',
|
||||
badge: 'bg-red-500/15 text-red-300 border-red-400/30',
|
||||
accent: 'text-red-400',
|
||||
gradient: 'radial-gradient(circle at 50% 50%,#FBAE45 0 5%,#F04464 6% 12%,#7E2BD5 13% 21%,#11194B 22% 36%,#F04464 37% 43%,#11194B 44%)',
|
||||
},
|
||||
fin_du_monde: {
|
||||
label: 'Fin du monde',
|
||||
title: 'Fin du monde',
|
||||
icon: '💥',
|
||||
hint: 'Vrai bac. Niveau maximal.',
|
||||
hex: '#FF713D',
|
||||
badge: 'bg-orange-500/15 text-orange-300 border-orange-400/30',
|
||||
accent: 'text-orange-400',
|
||||
gradient: 'linear-gradient(#281846,#B33C33 55%,#F59337)',
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -92,28 +130,24 @@ export function isWeatherKind(value: unknown): value is WeatherKind {
|
|||
return typeof value === 'string' && (WEATHER_KINDS as string[]).includes(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Statut par défaut déduit du coefficient, pour pré-remplir le formulaire d'ajout.
|
||||
* 0 = rien de prévu, 1 = interro surprise, 2-3 = DS, 4+ = alerte rouge.
|
||||
*/
|
||||
export function kindFromWeight(weight: number): WeatherKind {
|
||||
if (weight <= 0) return 'soleil'
|
||||
if (weight < 2) return 'vent'
|
||||
if (weight < 1) return 'nuageux'
|
||||
if (weight < 2) return 'pluie'
|
||||
if (weight < 4) return 'orage'
|
||||
return 'tempete'
|
||||
if (weight < 5) return 'tempete'
|
||||
return 'fin_du_monde'
|
||||
}
|
||||
|
||||
/** Les coefficients proposés dans le formulaire, avec leur statut déduit. */
|
||||
export const WEIGHT_PRESETS: { value: number; label: string }[] = [
|
||||
{ value: 0, label: '0 — coursework' },
|
||||
{ value: 1, label: '1 — interro' },
|
||||
{ value: 0, label: '0 — rien' },
|
||||
{ value: 1, label: '1 — QCM / interro' },
|
||||
{ value: 2, label: '2 — contrôle' },
|
||||
{ value: 3, label: '3 — DS' },
|
||||
{ value: 4, label: '4 — examen blanc' },
|
||||
{ value: 5, label: '5 — épreuve commune' },
|
||||
]
|
||||
|
||||
/** Statut le plus sévère d'une journée ; `soleil` si la journée est vide. */
|
||||
export function dominantKind(exams: { kind: WeatherKind }[]): WeatherKind {
|
||||
let best: WeatherKind = 'soleil'
|
||||
for (const exam of exams) {
|
||||
|
|
@ -131,10 +165,8 @@ export interface Exam {
|
|||
teacher: string | null
|
||||
room: string | null
|
||||
chapter: string | null
|
||||
/** ISO 8601 UTC. */
|
||||
startsAt: string
|
||||
durationMin: number
|
||||
/** Coefficient : alimente la future « pression atmosphérique ». */
|
||||
weight: number
|
||||
kind: WeatherKind
|
||||
note: string | null
|
||||
|
|
@ -146,7 +178,6 @@ export interface ClassInfo {
|
|||
id: number
|
||||
name: string
|
||||
level: string | null
|
||||
/** Message d'annonce du jour (flash info), lu par tous les membres. */
|
||||
flashMessage: string | null
|
||||
}
|
||||
|
||||
|
|
@ -155,11 +186,9 @@ export interface Member {
|
|||
classId: number
|
||||
nickname: string
|
||||
role: Role
|
||||
/** true = créateur de la classe (ne peut pas être rétrogradé). */
|
||||
isCreator: boolean
|
||||
}
|
||||
|
||||
/** Charge utile de `GET /api/me`, renvoyée aussi à la création et à l'adhésion. */
|
||||
export interface Session {
|
||||
member: Member
|
||||
klass: ClassInfo
|
||||
|
|
@ -169,7 +198,6 @@ export interface ApiError {
|
|||
error: string
|
||||
}
|
||||
|
||||
/** Override météo posé par l'admin pour un jour donné (clé locale AAAA-MM-JJ). */
|
||||
export interface DayWeather {
|
||||
classId: number
|
||||
dayKey: string
|
||||
|
|
@ -177,15 +205,12 @@ export interface DayWeather {
|
|||
updatedAt: string
|
||||
}
|
||||
|
||||
/** Flash info : message quotidien rédigé par l'admin. */
|
||||
export interface FlashInfo {
|
||||
classId: number
|
||||
/** null = pas de message publié. */
|
||||
message: string | null
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
/** Payloads émis par le flux SSE. */
|
||||
export type StreamEvent =
|
||||
| { type: 'exam.created'; exam: Exam }
|
||||
| { type: 'exam.updated'; exam: Exam }
|
||||
|
|
@ -198,5 +223,4 @@ export type StreamEvent =
|
|||
|
||||
export const CLASS_CODE_LENGTH = 6
|
||||
|
||||
/** Version de l'application. Incrémentée à chaque release APK. */
|
||||
export const APP_VERSION = '0.5.0'
|
||||
export const APP_VERSION = '1.0.0'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue