Compare commits
No commits in common. "main" and "v0.1.0-alpha" have entirely different histories.
main
...
v0.1.0-alp
|
|
@ -1,47 +0,0 @@
|
||||||
name: DevSecOps Pipeline - Universal Quality Gate
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main", "develop", "dev/*" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
health-check:
|
|
||||||
name: System & Environment Check
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: System Check
|
|
||||||
run: |
|
|
||||||
echo "🚀 Pipeline CI/CD opérationnel !"
|
|
||||||
uname -a
|
|
||||||
|
|
||||||
gitleaks-scan:
|
|
||||||
name: Secret Detection (Gitleaks)
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout Code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Download and Run Gitleaks
|
|
||||||
run: |
|
|
||||||
wget -q https://github.com/gitleaks/gitleaks/releases/download/v8.18.2/gitleaks_8.18.2_linux_x64.tar.gz
|
|
||||||
tar -xzf gitleaks_8.18.2_linux_x64.tar.gz gitleaks
|
|
||||||
./gitleaks detect --source="." --verbose --redact
|
|
||||||
|
|
||||||
trivy-iac-scan:
|
|
||||||
name: IaC Security & Vulnerability Scan (Trivy)
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: gitleaks-scan
|
|
||||||
steps:
|
|
||||||
- name: Checkout Code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Run Trivy Scan
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
wget -q https://github.com/aquasec/trivy/releases/download/v0.49.1/trivy_0.49.1_Linux-64bit.tar.gz
|
|
||||||
tar -xzf trivy_0.49.1_Linux-64bit.tar.gz trivy
|
|
||||||
./trivy config .
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
# ====================================================================
|
|
||||||
# RYM Horizon - Git Ignore Rules
|
|
||||||
# ====================================================================
|
|
||||||
|
|
||||||
# --- Système d'Exploitation (Hôtes & Laboratoires) ---
|
|
||||||
# Fedora / Linux généraux
|
|
||||||
.directory
|
|
||||||
.Trash-*
|
|
||||||
*~
|
|
||||||
|
|
||||||
# Fichiers systèmes Windows / macOS au cas où un collaborateur en utilise
|
|
||||||
Thumbs.db
|
|
||||||
Desktop.ini
|
|
||||||
.DS_Store
|
|
||||||
.AppleDouble
|
|
||||||
.LSOverride
|
|
||||||
|
|
||||||
# --- Éditeurs de Code & IDE ---
|
|
||||||
# VS Codium / VS Code
|
|
||||||
.vscode/
|
|
||||||
*.code-workspace
|
|
||||||
.history/
|
|
||||||
|
|
||||||
# --- Infrastructure locale (Podman / Docker) ---
|
|
||||||
.docker/
|
|
||||||
.podman/
|
|
||||||
*.tar
|
|
||||||
*.tar.gz
|
|
||||||
# Ne pas ignorer les fichiers de conf Nginx si nécessaire,
|
|
||||||
# mais ignorer les logs locaux si générés dans le projet
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# --- Fichiers d'environnement & Sécurité ---
|
|
||||||
# Contient les clés d'API, secrets RYM Bank, accès serveurs
|
|
||||||
.env
|
|
||||||
.env.local
|
|
||||||
.env.*.local
|
|
||||||
*.pem
|
|
||||||
*.key
|
|
||||||
*.secret
|
|
||||||
|
|
||||||
# --- Dépendances futures ---
|
|
||||||
# Pour anticiper l'arrivée de Node.js, npm, ou de préprocesseurs CSS
|
|
||||||
node_modules/
|
|
||||||
.npm/
|
|
||||||
dist/
|
|
||||||
build/
|
|
||||||
.sass-cache/
|
|
||||||
.cache/
|
|
||||||
|
|
||||||
# --- Nginx erreurs fichiers ---
|
|
||||||
# A remplir au fur et à mesure
|
|
||||||
50x.html
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"rules": {
|
|
||||||
"block-no-empty": true,
|
|
||||||
"color-no-invalid-hex": true,
|
|
||||||
"comment-no-empty": true,
|
|
||||||
"declaration-block-no-duplicate-properties": true,
|
|
||||||
"declaration-block-no-shorthand-property-overrides": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
RYM Horizon — Spécifications Architecturales
|
|
||||||
|
|
||||||
Version : 3.0.0 (Souveraine & Épurée)
|
|
||||||
|
|
||||||
Date : Samedi 23 Mai 2026
|
|
||||||
|
|
||||||
Statut : Validé en Laboratoire Local
|
|
||||||
1. Philosophie & Alignement Géopolitique
|
|
||||||
|
|
||||||
RYM Horizon est le cockpit d'organisation temporelle et de gestion des actifs de la performance pour l'athlète d'endurance. Conformément à la charte "Tout sauf US", l'intégralité de l'environnement de développement et de déploiement est étanche aux lois extra-territoriales américaines (Cloud Act, EAR).
|
|
||||||
|
|
||||||
Hébergement cible : Serveurs souverains européens (Debian VPS).
|
|
||||||
|
|
||||||
Laboratoire local : Conteneurisé sous OS Européen (Allemagne/Suède).
|
|
||||||
|
|
||||||
Flux Financiers : Intégration native exclusive des rails européens (Wero / Euro Numérique).
|
|
||||||
|
|
||||||
2. Infrastructure du Laboratoire Local (Podman & openSUSE)
|
|
||||||
|
|
||||||
Pour valider le fonctionnement de l'application sans dépendance externe, le projet est exécuté dans un bac à sable isolé.
|
|
||||||
Composants techniques :
|
|
||||||
|
|
||||||
Orchestrateur : Podman (Rootless, natif Fedora, sans démon privilégié).
|
|
||||||
|
|
||||||
Système d'Exploitation : openSUSE Leap 15.6 (Distribution allemande/suédoise, ultra-stable).
|
|
||||||
|
|
||||||
Serveur Web : Nginx (Configuration optimisée).
|
|
||||||
|
|
||||||
Architecture Réseau & Ports :
|
|
||||||
|
|
||||||
Pour des raisons de sécurité (mode Rootless de Podman), le conteneur n'a pas les droits pour ouvrir le port standard 80. La configuration a été basculée sur le port 8080. Un tunnel de port lie la machine hôte au conteneur.
|
|
||||||
|
|
||||||
Accès local de développement : http://localhost:8080
|
|
||||||
|
|
||||||
3. Spécifications Fonctionnelles de l'Interface (v3.0.0)
|
|
||||||
|
|
||||||
L'interface abandonne le look "calendrier de bureau" au profit d'un cockpit de vie multi-échelle, inspiré de la clarté de Runna, de la précision de Garmin et du minimalisme de Stripe/Vercel.
|
|
||||||
Les 4 Échelles Temporelles :
|
|
||||||
|
|
||||||
Vue Jour : Découpage de la journée en cours (Matin / Après-midi / Soir) pour coller au bi-quotidien des athlètes.
|
|
||||||
|
|
||||||
Vue Semaine : Timeline horizontale fluide avec capacité de réorganisation des séances (Drag & Drop).
|
|
||||||
|
|
||||||
Vue Mois : Aperçu stratégique de la charge globale et des blocs d'assimilation.
|
|
||||||
|
|
||||||
Vue Macro / Olympiades : Planification à long terme des objectifs majeurs (Ex: Ironman, Pics de forme) et des budgets matériels associés.
|
|
||||||
|
|
||||||
Cockpit Physiologique & Matériel (Les Spinners) :
|
|
||||||
|
|
||||||
Indicateurs circulaires fins calculant en temps réel :
|
|
||||||
|
|
||||||
Fraîcheur / VRC : Niveau de tolérance à la charge d'entraînement.
|
|
||||||
|
|
||||||
Santé Matériel : Indice d'usure des actifs critiques (chaînes, chaussures carbone) corrélé directement à la RYM Bank pour le provisionnement budgétaire automatique.
|
|
||||||
69
CHANGELOG.md
69
CHANGELOG.md
|
|
@ -1,69 +0,0 @@
|
||||||
# Journal des Modifications — RYM Horizon
|
|
||||||
|
|
||||||
Toutes les modifications notables de ce projet seront documentées dans ce fichier.
|
|
||||||
|
|
||||||
Le format est basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/)
|
|
||||||
et ce projet respecte le [Versionnement Sémantique](https://semver.org/lang/fr/).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## [3.1.3] - 2026-05-28
|
|
||||||
|
|
||||||
### Ajouté
|
|
||||||
- **Cockpit Holistique à 6 Piliers :** Extension du tableau de bord de 4 à 6 indicateurs circulaires SVG autonomes représentant l'intégralité des dimensions de l'athlète (Entraînement, Récupération, Nutrition, Hydratation, Soins, Matériel).
|
|
||||||
- **Usine à Badges Dynamique :** Implémentation d'un générateur d'activités et de tâches de maintenance à la volée via un formulaire JavaScript natif interconnecté au moteur de planification.
|
|
||||||
- **Sécurisation de la Supply Chain (SRI) :** Intégration des verrous d'intégrité cryptographique `integrity` (SHA-384) sur les liaisons CDN externes pour se conformer aux exigences de sécurité strictes de SonarQube.
|
|
||||||
|
|
||||||
### Modifié
|
|
||||||
- **Recentrage Produit (MVP) :** Nettoyage architectural complet de l'interface pour éliminer les briques tierces obsolètes (Espace Cohorte, Administrateur, MCO Infra) et recentrer l'application sur le profil unique de l'athlète d'endurance.
|
|
||||||
- **Moteur de Rendu Temporel :** Refonte de la logique événementielle dans `app.js` pour détruire et réassigner dynamiquement les écouteurs de glisser-déposer (*Drag & Drop*) sur les nouveaux composants injectés en cours de session.
|
|
||||||
- **Feuille de Style Souveraine :** Élimination des conflits d'opacité liés aux classes de transition natives de Bootstrap au profit d'un contrôle d'affichage exclusif et performant en CSS pur.
|
|
||||||
|
|
||||||
## [3.1.0] - 2026-05-27
|
|
||||||
### Ajouté
|
|
||||||
- **Moteur Drag & Drop Natif :** Implémentation d'un système de planification agile (Kanban) dans `app.js` permettant de glisser-déposer les séances d'entraînement à la souris sans aucune dépendance logicielle externe.
|
|
||||||
- **Cockpit Physiologique & Matériel :** Intégration de 4 indicateurs de performance (Fraîcheur VRC, Charge Hebdo, Usure Chaîne Vélo, Paires Carbone) basés sur des tracés SVG natifs et légers.
|
|
||||||
- **Gouvernance & Linters :** Déploiement des fichiers de configuration modernes `eslint.config.js` (Format Flat Config de niveau industriel) et `.stylelintrc.json` à la racine du projet.
|
|
||||||
- **Moteur Kanban Métier :** Implémentation du système de Drag & Drop natif dans l'onglet RYM Coach permettant de réorganiser le planning hebdomadaire.
|
|
||||||
- **Calculateur de Charge Dynamique :** Automatisation du recalcul du spinner "Charge Hebdo" en JavaScript à chaque déplacement d'entraînement.
|
|
||||||
|
|
||||||
### Modifié
|
|
||||||
- **Architecture de Navigation :** Consolidation du routage événementiel pour assurer la permutation étanche entre les onglets MCO Dashboard, RYM Bank, RYM Coach et Suivi Cohorte.
|
|
||||||
- **Design System :** Correction structurelle des imbrications de conteneurs Bootstrap 5 pour garantir un affichage fluide de la zone Expert.
|
|
||||||
- **Design System Responsif :** Optimisation de la structure Bootstrap 5 pour forcer l'alignement des "spinners" sur une seule ligne (`row`) sur écran desktop et une répartition fluide sur mobile.
|
|
||||||
- **Pont de Développement :** Restructuration du conteneur de validation openSUSE Leap 15.6 via un montage de volume Podman sécurisé (`:Z`) permettant l'audit du code en temps réel depuis l'hôte Fedora.
|
|
||||||
|
|
||||||
## [3.0.0] - 2026-05-23
|
|
||||||
|
|
||||||
### Ajouté
|
|
||||||
- **Architecture W3C :** Découplage complet et strict du code source en trois entités distinctes (`index.html`, `style.css`, `app.js`).
|
|
||||||
- **Logique JS Moderne :** Remplacement des attributs obsolètes `onclick` par un gestionnaire d'événements JavaScript non-intrusif basé sur les `data-attributes`.
|
|
||||||
- **Documentation :** Création du fichier `ARCHITECTURE.md` figeant la vision technique et la philosophie souveraine du projet.
|
|
||||||
- **Sécurité & Git :** Déploiement d'un fichier `.gitignore` standardisé pour protéger les secrets de la RYM Bank (fichiers `.env`, clés privées).
|
|
||||||
- **Cockpit à 4 Échelles :** Intégration de la vision multi-échelle (Jour J détaillé / Semaine fluide / Aperçu Mensuel / Macro-Olympiades).
|
|
||||||
- **Indicateurs Fins :** Implémentation des "spinners" circulaires en CSS pur pour le suivi de la fraîcheur physiologique (VRC) et de la santé du matériel.
|
|
||||||
|
|
||||||
### Modifié
|
|
||||||
- **Infrastructure Lab :** Bascule du serveur de test local vers un conteneur souverain européen **openSUSE Leap 15.6** opéré via **Podman** (Rootless).
|
|
||||||
- **Réseau :** Configuration et routage du serveur Nginx local sur le port alternatif `8080` pour contourner les restrictions de privilèges.
|
|
||||||
|
|
||||||
### Sécurisé
|
|
||||||
- Exclusion stricte des fichiers de configuration locaux et des dossiers caches d'éditeurs (`.vscode/`).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## [2.4.0] - 2026-05-10
|
|
||||||
|
|
||||||
### Ajouté
|
|
||||||
- Première ébauche de la vue calendrier hebdomadaire en tableau standard.
|
|
||||||
- Intégration des boutons d'exports de rapports pour l'Espace Expert (Cohort-Dashboard).
|
|
||||||
- Intégration visuelle de l'état de synchronisation avec l'API Strava.
|
|
||||||
- Structure HTML de base intégrant Bootstrap 5 (version monolithique avec style et script intégrés).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## [1.0.0] - 2026-04-01
|
|
||||||
|
|
||||||
### Ajouté
|
|
||||||
- Initialisation du projet RYM Horizon.
|
|
||||||
- Maquette de principe de l'interface et choix de la charte graphique de base.
|
|
||||||
68
LICENSE
68
LICENSE
|
|
@ -1,68 +0,0 @@
|
||||||
====================================================================
|
|
||||||
RYM HORIZON — CONTRAT DE LICENCE COMMERCIALE ET DE CONFIDENTIALITÉ
|
|
||||||
====================================================================
|
|
||||||
|
|
||||||
Version : 1.0.0
|
|
||||||
Date de révision : 23 Mai 2026
|
|
||||||
Titulaire des droits : RYM Bank / Écosystème RYM
|
|
||||||
Juridiction exclusive : République Française / Union Européenne
|
|
||||||
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
1. PROPRIÉTÉ ET DROITS D'AUTEUR
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
Le présent logiciel, incluant sans limitation le code source (HTML,
|
|
||||||
CSS, JavaScript), l'architecture technique, les éléments graphiques,
|
|
||||||
l'arborescence et la documentation associée (ci-après "le Logiciel"),
|
|
||||||
est la propriété exclusive et entière de son auteur originel et de
|
|
||||||
la structure RYM Bank.
|
|
||||||
|
|
||||||
Le Logiciel est protégé par les lois françaises et internationales
|
|
||||||
relatives au droit d'auteur et à la propriété intellectuelle.
|
|
||||||
Tous droits non expressément concédés par le présent contrat sont
|
|
||||||
strictement réservés par le titulaire des droits.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
2. SOUVERAINETÉ ET ÉTANCHÉITÉ COMPORTEMENTALE
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
Conformément à la charte fondamentale de l'écosystème RYM, ce logiciel
|
|
||||||
est conçu pour garantir une étanchéité absolue vis-à-vis des lois
|
|
||||||
extra-territoriales étrangères (notamment le US Cloud Act / USA PATRIOT Act).
|
|
||||||
|
|
||||||
Toute intégration future, modification ou exploitation du code source
|
|
||||||
doit impérativement respecter cette clause d'étanchéité et de
|
|
||||||
souveraineté numérique européenne.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
3. RESTRICTIONS D'UTILISATION ET DE DISTRIBUTION
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
Sauf autorisation écrite, préalable et expresse du titulaire des
|
|
||||||
droits, il est strictement interdit de :
|
|
||||||
- Copier, modifier, adapter, traduire ou créer des œuvres dérivées
|
|
||||||
du Logiciel à des fins commerciales externes ou personnelles.
|
|
||||||
- Distribuer, louer, sous-licencier, vendre ou transférer le Logiciel
|
|
||||||
ou son code source à des tiers.
|
|
||||||
- Divulguer ou publier le code source sur des forges logicielles
|
|
||||||
publiques non contrôlées ou non hébergées en Europe de manière souveraine.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
4. CLAUSE PARTICULIÈRE : RECRUTEMENT ET COLLABORATION (LEAD TECH)
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
Le présent code source est structuré selon les meilleures pratiques du
|
|
||||||
W3C à des fins d'audit technique et d'intégration de collaborateurs
|
|
||||||
clés (notamment un Lead Technical Officer).
|
|
||||||
|
|
||||||
L'accès à ce code par un tiers dans le cadre d'un recrutement, d'un
|
|
||||||
partenariat ou d'un co-développement implique de plein droit une
|
|
||||||
obligation stricte de secret professionnel, de réserve et de non-divulgation.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
5. EXCLUSION DE GARANTIE
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
Le Logiciel est fourni "en l'état", sans garantie d'aucune sorte,
|
|
||||||
expresse ou implicite, y compris mais sans s'y limiter, les garanties
|
|
||||||
de commercialisation ou d'adéquation à un usage particulier.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
Fait à usage de droit. Pour toute demande de licence ou contribution :
|
|
||||||
Contact de l'infrastructure : www.gorym.fr
|
|
||||||
====================================================================
|
|
||||||
18
README.md
18
README.md
|
|
@ -1,18 +0,0 @@
|
||||||
# RYM Horizon
|
|
||||||
|
|
||||||
> Le Cockpit de Performance Souverain pour l'Athlète d'Endurance.
|
|
||||||
|
|
||||||
## Présentation
|
|
||||||
RYM Horizon fusionne l'organisation temporelle, le suivi de la fraîcheur physiologique et la gestion budgétaire de la performance (MCO des actifs), de manière totalement étanche aux technologies extra-territoriales américaines.
|
|
||||||
|
|
||||||
## Installation Rapide (Laboratoire Local)
|
|
||||||
Le projet est configuré pour tourner de manière isolée sur un serveur web openSUSE via Podman.
|
|
||||||
|
|
||||||
1. Lancer le conteneur :
|
|
||||||
podman run -d -p 8080:8080 --name rym-suse-stable registry.opensuse.org/opensuse/leap:latest tail -f /dev/null
|
|
||||||
|
|
||||||
2. Accéder à l'application : `http://localhost:8080`
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
- Spécifications techniques : `ARCHITECTURE.md`
|
|
||||||
- Historique des versions : `CHANGELOG.md`
|
|
||||||
148
app.js
148
app.js
|
|
@ -1,148 +0,0 @@
|
||||||
/**
|
|
||||||
* ====================================================================
|
|
||||||
* RYM HORIZON — ENGINE APPLICATION (v3.1.3)
|
|
||||||
* ====================================================================
|
|
||||||
* Philosophie : Code découplé, souveraineté et performance pure.
|
|
||||||
* Architecture : Gestionnaire de vues + Moteur Drag & Drop + Usine à badges.
|
|
||||||
* Conformité : Sans dépendances tierces intrusives.
|
|
||||||
*/
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
|
|
||||||
// --- INTÉGRATION DE LA CHRONOLOGIE (SESSION LOG) ---
|
|
||||||
console.log("RYM Horizon Engine v3.1.3 : Initialisation du système...");
|
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// MODULE 1 : MANAGER DE NAVIGATION SOUVERAIN
|
|
||||||
// ==========================================
|
|
||||||
const tabButtons = document.querySelectorAll('.nav-view-switcher .nav-link');
|
|
||||||
const tabPanes = document.querySelectorAll('.tab-content .tab-pane');
|
|
||||||
|
|
||||||
tabButtons.forEach(button => {
|
|
||||||
button.addEventListener('click', (e) => {
|
|
||||||
const targetTabId = button.getAttribute('data-tab');
|
|
||||||
|
|
||||||
// 1. Mise à jour de l'état actif sur les boutons du menu
|
|
||||||
tabButtons.forEach(btn => btn.classList.remove('active'));
|
|
||||||
button.classList.add('active');
|
|
||||||
|
|
||||||
// 2. Commutation stricte des conteneurs de vues (Géré via CSS display !important)
|
|
||||||
tabPanes.forEach(pane => {
|
|
||||||
if (pane.id === targetTabId) {
|
|
||||||
pane.classList.add('active');
|
|
||||||
} else {
|
|
||||||
pane.classList.remove('active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console.log(`[Navigation] Passage sur la vue : ${targetTabId}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// MODULE 2 : USINE DE CRÉATION DE BADGES (À LA VOLÉE)
|
|
||||||
// ==========================================
|
|
||||||
const generatorForm = document.getElementById('rym-coach-generator');
|
|
||||||
const productionZone = document.getElementById('badge-production-zone');
|
|
||||||
|
|
||||||
// Dictionnaire de configuration des composants (Couleurs CSS natifs et Icônes)
|
|
||||||
const typeDictionary = {
|
|
||||||
run: { cssClass: 'run', icon: 'bi-lightning-fill' },
|
|
||||||
bike: { cssClass: 'bike', icon: 'bi-bicycle' },
|
|
||||||
swim: { cssClass: 'swim', icon: 'bi-water' },
|
|
||||||
matos: { cssClass: 'run', icon: 'bi-gear-wide-connected', customStyle: 'background: #fef2f2; color: #991b1b; border: 1px dashed #f87171;' },
|
|
||||||
soins: { cssClass: 'swim', icon: 'bi-heart-pulse-fill', customStyle: 'background: #faf5ff; color: #6b21a8; border: 1px dashed #c084fc;' }
|
|
||||||
};
|
|
||||||
|
|
||||||
generatorForm.addEventListener('submit', (e) => {
|
|
||||||
e.preventDefault(); // Bloque le rechargement de la page pour préserver le cache local
|
|
||||||
|
|
||||||
const type = document.getElementById('gen-type').value;
|
|
||||||
const title = document.getElementById('gen-title').value;
|
|
||||||
const config = typeDictionary[type];
|
|
||||||
const uniqueId = `w-generated-${Date.now()}`; // Identifiant unique basé sur le timestamp
|
|
||||||
|
|
||||||
// Nettoyage de la zone de production
|
|
||||||
productionZone.innerHTML = '';
|
|
||||||
|
|
||||||
// Création du nœud DOM du badge
|
|
||||||
const badge = document.createElement('div');
|
|
||||||
badge.id = uniqueId;
|
|
||||||
badge.className = `workout ${config.cssClass} rym-draggable-workout`;
|
|
||||||
badge.setAttribute('draggable', 'true');
|
|
||||||
|
|
||||||
if (config.customStyle) {
|
|
||||||
badge.setAttribute('style', config.customStyle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Injection du contenu structuré
|
|
||||||
badge.innerHTML = `<i class="bi ${config.icon} me-1"></i> ${title}`;
|
|
||||||
|
|
||||||
// Activation immédiate de la mécanique Drag sur le nouveau composant
|
|
||||||
attachDragEventsToElement(badge);
|
|
||||||
|
|
||||||
// Rendu final dans l'interface
|
|
||||||
productionZone.appendChild(badge);
|
|
||||||
generatorForm.reset();
|
|
||||||
console.log(`[Engine] Nouveau badge instancié avec succès ID: ${uniqueId}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// MODULE 3 : MOTEUR DRAG & DROP MULTI-CIBLES
|
|
||||||
// ==========================================
|
|
||||||
let draggedElement = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attache les écouteurs d'événements Drag à un élément unique
|
|
||||||
* @param {HTMLElement} element
|
|
||||||
*/
|
|
||||||
function attachDragEventsToElement(element) {
|
|
||||||
element.addEventListener('dragstart', (e) => {
|
|
||||||
draggedElement = element;
|
|
||||||
e.dataTransfer.setData('text/plain', element.id);
|
|
||||||
element.style.opacity = '0.4';
|
|
||||||
console.log(`[Drag] Début du déplacement de l'élément : ${element.id}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
element.addEventListener('dragend', () => {
|
|
||||||
element.style.opacity = '1';
|
|
||||||
draggedElement = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialisation du moteur Drag sur les cartes pré-existantes au boot
|
|
||||||
document.querySelectorAll('.rym-draggable-workout').forEach(attachDragEventsToElement);
|
|
||||||
|
|
||||||
// Configuration des zones de réception (Les jours de la semaine)
|
|
||||||
const dropZones = document.querySelectorAll('.drop-zone');
|
|
||||||
|
|
||||||
dropZones.forEach(zone => {
|
|
||||||
zone.addEventListener('dragover', (e) => {
|
|
||||||
e.preventDefault(); // Indispensable pour autoriser le drop dans le navigateur
|
|
||||||
zone.classList.add('drag-over');
|
|
||||||
});
|
|
||||||
|
|
||||||
zone.addEventListener('dragleave', () => {
|
|
||||||
zone.classList.remove('drag-over');
|
|
||||||
});
|
|
||||||
|
|
||||||
zone.addEventListener('drop', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
zone.classList.remove('drag-over');
|
|
||||||
|
|
||||||
if (draggedElement) {
|
|
||||||
// Déplacement physique du nœud dans le conteneur du jour ciblé
|
|
||||||
zone.appendChild(draggedElement);
|
|
||||||
|
|
||||||
// Si le badge provient de la zone de production, on remet le texte d'attente
|
|
||||||
if (productionZone.children.length === 0) {
|
|
||||||
productionZone.innerHTML = 'Aucun badge généré';
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`[Drop] Élément réassigné au jour : ${zone.getAttribute('data-day')}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
export default [
|
|
||||||
{
|
|
||||||
languageOptions: {
|
|
||||||
ecmaVersion: "latest",
|
|
||||||
sourceType: "module",
|
|
||||||
globals: {
|
|
||||||
window: "readonly",
|
|
||||||
document: "readonly",
|
|
||||||
console: "readonly",
|
|
||||||
setTimeout: "readonly"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
"no-unused-vars": "warn",
|
|
||||||
"no-undef": "error",
|
|
||||||
"no-console": "off",
|
|
||||||
"eqeqeq": "error",
|
|
||||||
"curly": "error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
355
index.html
355
index.html
|
|
@ -3,261 +3,152 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>RYM Horizon — Cockpit Intégré v3.1.3</title>
|
<title>RYM Horizon | Écosystème Souverain</title>
|
||||||
<link
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||||
rel="stylesheet"
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
|
<style>
|
||||||
crossorigin="anonymous"
|
:root { --rym-main: #004a99; --rym-dark: #121416; --rym-accent: #00d1b2; --rym-premium: #ffd700; }
|
||||||
>
|
body { background-color: #f0f2f5; font-family: 'Inter', sans-serif; font-size: 0.9rem; }
|
||||||
<link
|
.sidebar { min-height: 100vh; background: var(--rym-dark); color: white; }
|
||||||
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css"
|
.nav-link { color: #8a8d91; border-radius: 10px; padding: 10px 15px; margin-bottom: 4px; cursor: pointer; }
|
||||||
rel="stylesheet"
|
.nav-link.active { background: var(--rym-main); color: white; }
|
||||||
integrity="sha384-4LISF5TTv3qMT719A6O7faWdgANoF94m85M84IfTWM5cKWAYjHL0ive8SkWAAAAA"
|
.sidebar-heading { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; color: #495057; margin-top: 1.5rem; padding-bottom: 5px; border-bottom: 1px solid #343a40; }
|
||||||
crossorigin="anonymous"
|
.card-rym { border: none; border-radius: 18px; box-shadow: 0 4px 20px rgba(0,0,0,0.05); background: white; }
|
||||||
>
|
.tab-content { display: none; }
|
||||||
<link rel="stylesheet" href="style.css">
|
.tab-content.active { display: block; animation: fadeIn 0.3s; }
|
||||||
|
.premium-zone { border: 2px solid var(--rym-premium); position: relative; }
|
||||||
|
.hour-row { border-bottom: 1px solid #eee; min-height: 40px; display: flex; align-items: center; }
|
||||||
|
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<header class="bg-white border-bottom py-3 sticky-top">
|
<div class="container-fluid">
|
||||||
<div class="container-fluid px-4 d-flex align-items-center justify-content-between">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<span class="fw-bold fs-4 me-4">Rym<span class="text-primary">Horizon</span></span>
|
|
||||||
<div class="nav nav-view-switcher" role="tablist">
|
|
||||||
<button class="nav-link" data-tab="view-day">Jour</button>
|
|
||||||
<button class="nav-link active" data-tab="view-week">Semaine</button>
|
|
||||||
<button class="nav-link" data-tab="view-month">Mois</button>
|
|
||||||
<button class="nav-link" data-tab="view-macro">Macro</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<div class="text-end me-3">
|
|
||||||
<small class="text-muted d-block" style="font-size: 0.7rem;">RYM BANK</small>
|
|
||||||
<span class="fw-bold">19 420,00 €</span>
|
|
||||||
</div>
|
|
||||||
<i class="bi bi-wallet2 fs-4 text-primary"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main class="container-fluid py-4 px-4">
|
|
||||||
|
|
||||||
<section class="row g-4 mb-5">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="bg-white rounded-4 p-3 border d-flex justify-content-around flex-wrap gap-4">
|
|
||||||
<div class="d-flex align-items-center gap-3">
|
|
||||||
<div class="spinner-container">
|
|
||||||
<svg width="60" height="60"><circle cx="30" cy="30" r="26" fill="none" stroke="#e2e8f0" stroke-width="4"/><circle cx="30" cy="30" r="26" fill="none" stroke="#0d9488" stroke-width="4" stroke-dasharray="163" stroke-dashoffset="80"/></svg>
|
|
||||||
<div class="spinner-value" style="color:#0d9488" id="val-charge">12h</div>
|
|
||||||
</div>
|
|
||||||
<div><small class="text-muted d-block">Entraînement</small><span class="fw-bold">Charge Hebdo</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex align-items-center gap-3">
|
|
||||||
<div class="spinner-container">
|
|
||||||
<svg width="60" height="60"><circle cx="30" cy="30" r="26" fill="none" stroke="#e2e8f0" stroke-width="4"/><circle cx="30" cy="30" r="26" fill="none" stroke="#16a34a" stroke-width="4" stroke-dasharray="163" stroke-dashoffset="30"/></svg>
|
|
||||||
<div class="spinner-value text-success" id="val-recup">82%</div>
|
|
||||||
</div>
|
|
||||||
<div><small class="text-muted d-block">Récupération</small><span class="fw-bold">VRC / Sommeil</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex align-items-center gap-3">
|
|
||||||
<div class="spinner-container">
|
|
||||||
<svg width="60" height="60"><circle cx="30" cy="30" r="26" fill="none" stroke="#e2e8f0" stroke-width="4"/><circle cx="30" cy="30" r="26" fill="none" stroke="#2563eb" stroke-width="4" stroke-dasharray="163" stroke-dashoffset="40"/></svg>
|
|
||||||
<div class="spinner-value text-primary" id="val-nutrition">75%</div>
|
|
||||||
</div>
|
|
||||||
<div><small class="text-muted d-block">Nutrition</small><span class="fw-bold">Macro Cibles</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex align-items-center gap-3">
|
|
||||||
<div class="spinner-container">
|
|
||||||
<svg width="60" height="60"><circle cx="30" cy="30" r="26" fill="none" stroke="#e2e8f0" stroke-width="4"/><circle cx="30" cy="30" r="26" fill="none" stroke="#0284c7" stroke-width="4" stroke-dasharray="163" stroke-dashoffset="50"/></svg>
|
|
||||||
<div class="spinner-value" style="color:#0284c7" id="val-hydra">2.5L</div>
|
|
||||||
</div>
|
|
||||||
<div><small class="text-muted d-block">Hydratation</small><span class="fw-bold">Eau / Électro</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex align-items-center gap-3">
|
|
||||||
<div class="spinner-container">
|
|
||||||
<svg width="60" height="60"><circle cx="30" cy="30" r="26" fill="none" stroke="#e2e8f0" stroke-width="4"/><circle cx="30" cy="30" r="26" fill="none" stroke="#f59e0b" stroke-width="4" stroke-dasharray="163" stroke-dashoffset="120"/></svg>
|
|
||||||
<div class="spinner-value text-warning" id="val-soins">Kiné</div>
|
|
||||||
</div>
|
|
||||||
<div><small class="text-muted d-block">Soins / Santé</small><span class="fw-bold">Fatigue Musc.</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex align-items-center gap-3">
|
|
||||||
<div class="spinner-container">
|
|
||||||
<svg width="60" height="60"><circle cx="30" cy="30" r="26" fill="none" stroke="#e2e8f0" stroke-width="4"/><circle cx="30" cy="30" r="26" fill="none" stroke="#ea580c" stroke-width="4" stroke-dasharray="163" stroke-dashoffset="130"/></svg>
|
|
||||||
<div class="spinner-value text-danger" id="val-matos">22%</div>
|
|
||||||
</div>
|
|
||||||
<div><small class="text-muted d-block">Matériel</small><span class="fw-bold text-danger">MCO Critique</span></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<div class="tab-content">
|
|
||||||
|
|
||||||
<div class="tab-pane" id="view-day">
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 mx-auto">
|
<nav class="col-md-2 d-none d-md-block sidebar p-4 sticky-top">
|
||||||
<h2 class="fw-bold h4 mb-4">Aujourd'hui, Samedi 23 mai</h2>
|
<h4 class="fw-bold text-center mb-5">RYM <span class="text-info">HORIZON</span></h4>
|
||||||
<div class="day-part-card">
|
|
||||||
<span class="text-muted small fw-bold">MATIN</span>
|
<div class="sidebar-heading">Admin</div>
|
||||||
<div class="workout swim"><i class="bi bi-water me-2"></i><strong>Natation</strong> - 1h15 Endurance (2500m)</div>
|
<ul class="nav flex-column"><li class="nav-item"><a class="nav-link active" onclick="showTab(event, 'dashboard')"><i class="bi bi-shield-check me-2"></i> MCO Dashboard</a></li></ul>
|
||||||
|
|
||||||
|
<div class="sidebar-heading">Finance</div>
|
||||||
|
<ul class="nav flex-column"><li class="nav-item"><a class="nav-link" onclick="showTab(event, 'bank')"><i class="bi bi-bank me-2"></i> RYM Bank</a></li></ul>
|
||||||
|
|
||||||
|
<div class="sidebar-heading">Utilisateur</div>
|
||||||
|
<ul class="nav flex-column"><li class="nav-item"><a class="nav-link" onclick="showTab(event, 'activity')"><i class="bi bi-heart-pulse me-2"></i> RYM Coach</a></li></ul>
|
||||||
|
|
||||||
|
<div class="sidebar-heading">Expert</div>
|
||||||
|
<ul class="nav flex-column"><li class="nav-item"><a class="nav-link" onclick="showTab(event, 'clients')"><i class="bi bi-people me-2"></i> Suivi Cohorte</a></li></ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main class="col-md-10 ms-sm-auto px-md-5 py-4">
|
||||||
|
|
||||||
|
<div id="dashboard" class="tab-content active">
|
||||||
|
<h2 class="mb-4">MCO Dashboard</h2>
|
||||||
|
<div class="card card-rym p-3 w-25"><h6 class="text-muted">Status Infra</h6><p class="text-success mb-0">● Online - France (OVH)</p></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="day-part-card day-part-active">
|
|
||||||
<span class="text-primary small fw-bold">APRÈS-MIDI</span>
|
<div id="bank" class="tab-content">
|
||||||
<p class="text-muted small mt-2">Repos actif / Préparation vélo</p>
|
<h2 class="mb-4">RYM Bank</h2>
|
||||||
|
<div class="card card-rym p-4 bg-primary text-white w-50 shadow-lg">
|
||||||
|
<h6>Solde Courant</h6>
|
||||||
|
<h2 class="fw-bold">12 450,80 €</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="day-part-card">
|
|
||||||
<span class="text-muted small fw-bold">SOIR</span>
|
|
||||||
<div class="workout run"><i class="bi bi-speedometer2 me-2"></i><strong>Course</strong> - 45' Footing souple</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="activity" class="tab-content">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h2>RYM Coach <small class="text-muted fs-6">| Mon Planning</small></h2>
|
||||||
|
<span class="badge bg-primary">Saison : Triathlon</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-rym p-4 shadow-sm mb-5">
|
||||||
|
<h5 class="mb-3 text-primary"><i class="bi bi-calendar-week me-2"></i>Vue Hebdomadaire (Standard)</h5>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered text-center align-middle">
|
||||||
|
<thead class="bg-dark text-white">
|
||||||
|
<tr><th>Moment</th><th>Lun</th><th>Mar</th><th>Mer</th><th>Jeu</th><th>Ven</th><th>Sam</th><th>Dim</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td class="bg-light fw-bold">Matin</td><td><i class="bi bi-water"></i></td><td>-</td><td><i class="bi bi-bicycle"></i></td><td><i class="bi bi-water"></i></td><td>-</td><td class="bg-info-subtle">Loisir</td><td class="bg-danger-subtle">Repos</td></tr>
|
||||||
|
<tr><td class="bg-light fw-bold">A-M</td><td>-</td><td><i class="bi bi-lightning"></i></td><td>-</td><td>-</td><td><i class="bi bi-lightning"></i></td><td><i class="bi bi-bicycle"></i></td><td>-</td></tr>
|
||||||
|
<tr><td class="bg-light fw-bold">Soir</td><td>-</td><td>-</td><td><i class="bi bi-person-walking"></i></td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-rym p-4 premium-zone shadow-lg">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
<h5 class="fw-bold text-dark"><i class="bi bi-clock me-2"></i>Agenda Précision Premium (24h/24)</h5>
|
||||||
|
<button class="btn btn-warning btn-sm fw-bold">Passer au Premium</button>
|
||||||
|
</div>
|
||||||
|
<div class="bg-light rounded p-3" style="max-height: 250px; overflow-y: auto;">
|
||||||
|
<div class="hour-row"><div class="col-1 fw-bold border-end pe-2">06:00</div><div class="col-11 ps-3 text-muted">Sommeil / Réveil</div></div>
|
||||||
|
<div class="hour-row"><div class="col-1 fw-bold border-end pe-2">07:00</div><div class="col-11 ps-3 bg-primary-subtle text-primary">Natation : 2500m Seuil</div></div>
|
||||||
|
<div class="hour-row"><div class="col-1 fw-bold border-end pe-2">08:00</div><div class="col-11 ps-3">Petit-Déjeuner & Hydratation</div></div>
|
||||||
|
<div class="hour-row"><div class="col-1 fw-bold border-end pe-2 text-primary">...</div><div class="col-11 ps-3">...</div></div>
|
||||||
|
<div class="hour-row"><div class="col-1 fw-bold border-end pe-2">23:00</div><div class="col-11 ps-3 text-muted">Repos / Nuit</div></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane active" id="view-week">
|
<div id="clients" class="tab-content">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h2>Espace Expert <small class="text-muted fs-6">| Dashboard Cohorte</small></h2>
|
||||||
|
<div class="btn-group shadow-sm">
|
||||||
|
<button class="btn btn-white border btn-sm"><i class="bi bi-file-earmark-pdf"></i> PDF</button>
|
||||||
|
<button class="btn btn-white border btn-sm"><i class="bi bi-file-earmark-excel"></i> XLS</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<div class="col-xl-3">
|
<div class="col-md-7">
|
||||||
<div class="bg-white border rounded-4 p-4 sticky-md-top" style="top: 90px; z-index: 10;">
|
<div class="card card-rym p-0 overflow-hidden">
|
||||||
<h5 class="fw-bold mb-3"><i class="bi bi-plus-circle-fill text-primary me-2"></i>RYM Coach Engine</h5>
|
<table class="table table-hover align-middle mb-0">
|
||||||
<p class="text-muted small">Créez une activité ou une tâche de maintenance et planifiez-la par Drag & Drop.</p>
|
<thead class="bg-light"><tr><th class="p-3">Athlète</th><th>Santé</th><th>Sync API</th><th>Action</th></tr></thead>
|
||||||
<hr class="text-muted opacity-25">
|
<tbody>
|
||||||
|
<tr>
|
||||||
<form id="rym-coach-generator" autocomplete="off">
|
<td class="p-3"><strong>Jean Dupont</strong><br><small>Ironman Nice 2026</small></td>
|
||||||
<div class="mb-3">
|
<td><span class="badge bg-success">Optimal</span></td>
|
||||||
<label class="form-label small fw-bold text-muted">TYPE DE COMPOSANT</label>
|
<td><i class="bi bi-strava text-orange"></i> <i class="bi bi-check-circle-fill text-primary"></i></td>
|
||||||
<select class="form-select form-select-sm" id="gen-type">
|
<td><button class="btn btn-sm btn-outline-dark">Ouvrir Dossier</button></td>
|
||||||
<option value="run">🏃 Course à pied</option>
|
</tr>
|
||||||
<option value="bike">🚴 Vélo / Home-Trainer</option>
|
</tbody>
|
||||||
<option value="swim">🏊 Natation</option>
|
</table>
|
||||||
<option value="matos">🔧 Maintenance Matériel</option>
|
|
||||||
<option value="soins">🧘 Soins / Récupération</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label small fw-bold text-muted">TITRE / DESCRIPTION</label>
|
|
||||||
<input type="text" class="form-control form-control-sm" id="gen-title" placeholder="ex: 6x800m VMA ou Purge freins" required>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary btn-sm w-100 fw-bold">Générer le Badge</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="mt-4">
|
|
||||||
<label class="form-label small fw-bold text-muted d-block mb-2">BADGE PRÊT À GLISSER :</label>
|
|
||||||
<div id="badge-production-zone" class="p-3 border border-dashed rounded-3 bg-light text-center small text-muted">
|
|
||||||
Aucun badge généré
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xl-9">
|
<div class="col-md-5">
|
||||||
<div class="d-flex justify-content-between align-items-end mb-3">
|
<div class="card card-rym p-4 border-start border-primary border-5">
|
||||||
<h2 class="fw-bold h4 mb-0">Timeline Hebdomadaire</h2>
|
<h5 class="mb-3">Bilan Anthropométrique (Cible)</h5>
|
||||||
<span class="text-muted small">Semaine 21 — Bloc Intensité</span>
|
<div class="row g-2 small">
|
||||||
|
<div class="col-6">Poids: <strong>74.5 kg</strong></div><div class="col-6 text-end">Âge: <strong>32</strong></div>
|
||||||
|
<hr>
|
||||||
|
<div class="col-6">Cou: 39cm</div><div class="col-6 text-end">Poitrine: 104cm</div>
|
||||||
|
<div class="col-6">Hanches: 92cm</div><div class="col-6 text-end">Taille: 80cm</div>
|
||||||
|
<div class="col-6 text-primary">Cuisse (D/G): 58/58</div><div class="col-6 text-primary text-end">Mollet (D/G): 39/39</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="timeline-scroll">
|
<div class="mt-4 p-2 bg-light border rounded text-center x-small">
|
||||||
<div class="day-card drop-zone" data-day="Lun">
|
<i class="bi bi-shield-lock me-1"></i> Données Chiffrées (Souveraineté RYM)
|
||||||
<span class="d-block fw-bold">Lundi 18</span>
|
|
||||||
<small class="text-muted">Repos</small>
|
|
||||||
<div class="mt-4 text-center py-3 border rounded-3 border-dashed">😴 Assimilation</div>
|
|
||||||
</div>
|
|
||||||
<div class="day-card drop-zone" data-day="Mar">
|
|
||||||
<span class="d-block fw-bold">Mardi 19</span>
|
|
||||||
<small class="text-muted">Haute Intensité</small>
|
|
||||||
<div class="workout run rym-draggable-workout" draggable="true" id="w-vma">
|
|
||||||
<i class="bi bi-lightning-fill me-1"></i> 6x800m VMA
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="day-card today drop-zone" data-day="Mer">
|
|
||||||
<span class="d-block fw-bold text-primary">Mercredi 20 (Aujourd'hui)</span>
|
|
||||||
<small class="text-primary fw-bold">Bi-quotidien</small>
|
|
||||||
<div class="workout swim rym-draggable-workout" draggable="true" id="w-swim">
|
|
||||||
<i class="bi bi-water me-1"></i> Swim 2500m
|
|
||||||
</div>
|
|
||||||
<div class="workout bike rym-draggable-workout" draggable="true" id="w-bike">
|
|
||||||
<i class="bi bi-bicycle"></i> H.Trainer 1h
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="day-card drop-zone" data-day="Jeu">
|
|
||||||
<span class="d-block fw-bold">Jeudi 21</span>
|
|
||||||
<small class="text-muted">Récupération</small>
|
|
||||||
<div class="workout run rym-draggable-workout" draggable="true" id="w-footing">
|
|
||||||
<i class="bi bi-speedometer2 me-1"></i> Footing 40'
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="day-card drop-zone" data-day="Ven">
|
|
||||||
<span class="d-block fw-bold">Vendredi 22</span>
|
|
||||||
<small class="text-muted">Repos</small>
|
|
||||||
<div class="mt-4 text-center py-3 border rounded-3 border-dashed">🧘 Flexibilité</div>
|
|
||||||
</div>
|
|
||||||
<div class="day-card drop-zone" data-day="Sam">
|
|
||||||
<span class="d-block fw-bold">Samedi 23</span>
|
|
||||||
<small class="text-muted">Sortie Longue</small>
|
|
||||||
</div>
|
|
||||||
<div class="day-card drop-zone" data-day="Dim">
|
|
||||||
<span class="d-block fw-bold">Dimanche 24</span>
|
|
||||||
<small class="text-muted">Enchaînement</small>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane" id="view-month">
|
|
||||||
<div class="row g-3">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="bg-white border rounded-4 p-3">
|
|
||||||
<h6 class="fw-bold">Semaine 1</h6>
|
|
||||||
<div class="progress mb-2" style="height: 6px;"><div class="progress-bar bg-primary" style="width: 70%"></div></div>
|
|
||||||
<small class="text-muted">Focus : Volume Foncier</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="bg-white border rounded-4 p-3">
|
|
||||||
<h6 class="fw-bold">Semaine 2</h6>
|
|
||||||
<div class="progress mb-2" style="height: 6px;"><div class="progress-bar bg-primary" style="width: 85%"></div></div>
|
|
||||||
<small class="text-muted">Focus : Charge Progressive</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="bg-white border rounded-4 p-3">
|
|
||||||
<h6 class="fw-bold">Semaine 3</h6>
|
|
||||||
<div class="progress mb-2" style="height: 6px;"><div class="progress-bar bg-primary" style="width: 40%"></div></div>
|
|
||||||
<small class="text-muted">Focus : Assimilation / Repos</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="bg-white border rounded-4 p-3">
|
|
||||||
<h6 class="fw-bold">Semaine 4</h6>
|
|
||||||
<div class="progress mb-2" style="height: 6px;"><div class="progress-bar bg-primary" style="width: 90%"></div></div>
|
|
||||||
<small class="text-muted">Focus : Intensité Cible</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tab-pane" id="view-macro">
|
|
||||||
<div class="macro-card">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-8">
|
|
||||||
<h2 class="fw-bold mb-3">Saison 2026 : Road to Ironman Vitoria</h2>
|
|
||||||
<p class="opacity-75">Cycle de 24 semaines — Actuellement en Phase de Spécificité 1.</p>
|
|
||||||
<div class="d-flex gap-2 mt-4">
|
|
||||||
<span class="badge bg-primary">Prep Foncière</span>
|
|
||||||
<span class="badge bg-primary">Prep Spécifique</span>
|
|
||||||
<span class="badge bg-outline-light border text-white opacity-50">Affûtage</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4 text-end">
|
|
||||||
<div class="h1 fw-bold">J - 142</div>
|
|
||||||
<small class="opacity-75">Avant l'objectif A</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="app.js" defer></script>
|
<script>
|
||||||
|
function showTab(event, tabId) {
|
||||||
|
document.querySelectorAll('.tab-content').forEach(tab => tab.classList.remove('active'));
|
||||||
|
document.querySelectorAll('.nav-link').forEach(link => link.classList.remove('active'));
|
||||||
|
document.getElementById(tabId).classList.add('active');
|
||||||
|
event.currentTarget.classList.add('active');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
170
style.css
170
style.css
|
|
@ -1,170 +0,0 @@
|
||||||
:root {
|
|
||||||
--rym-bg: #f8fafc;
|
|
||||||
--rym-surface: #ffffff;
|
|
||||||
--rym-accent: #2563eb;
|
|
||||||
--rym-text: #0f172a;
|
|
||||||
--rym-muted: #64748b;
|
|
||||||
--rym-stroke: #e2e8f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: var(--rym-bg);
|
|
||||||
color: var(--rym-text);
|
|
||||||
font-family: 'Inter', -apple-system, sans-serif;
|
|
||||||
letter-spacing: -0.01em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nav & Tabs Switcheur du haut */
|
|
||||||
.nav-view-switcher {
|
|
||||||
background: #e2e8f0;
|
|
||||||
padding: 4px;
|
|
||||||
border-radius: 12px;
|
|
||||||
display: inline-flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-view-switcher .nav-link {
|
|
||||||
border-radius: 10px;
|
|
||||||
color: var(--rym-muted);
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
padding: 8px 16px;
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-view-switcher .nav-link.active {
|
|
||||||
background: var(--rym-surface);
|
|
||||||
color: var(--rym-text);
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cockpit Spinners Originaux */
|
|
||||||
.spinner-container {
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinner-container svg {
|
|
||||||
transform: rotate(-90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinner-container circle {
|
|
||||||
transition: stroke-dashoffset 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinner-value {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Timeline Hebdo Défilante */
|
|
||||||
.timeline-scroll {
|
|
||||||
display: flex;
|
|
||||||
gap: 1.25rem;
|
|
||||||
overflow-x: auto;
|
|
||||||
padding: 10px 0 20px;
|
|
||||||
scroll-snap-type: x mandatory;
|
|
||||||
}
|
|
||||||
|
|
||||||
.day-card {
|
|
||||||
min-width: 280px;
|
|
||||||
background: var(--rym-surface);
|
|
||||||
border: 1px solid var(--rym-stroke);
|
|
||||||
border-radius: 20px;
|
|
||||||
padding: 1.5rem;
|
|
||||||
scroll-snap-align: start;
|
|
||||||
transition: background-color 0.2s ease, border-color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.day-card.today {
|
|
||||||
border-color: var(--rym-accent);
|
|
||||||
border-width: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drag & Drop Zones visual feedback */
|
|
||||||
.drop-zone.drag-over {
|
|
||||||
background-color: #f1f5f9 !important;
|
|
||||||
border: 2px dashed var(--rym-accent) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rym-draggable-workout {
|
|
||||||
cursor: grab;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rym-draggable-workout:active {
|
|
||||||
cursor: grabbing;
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Vue Journalière (Matin/Midi/Soir) */
|
|
||||||
.day-part-card {
|
|
||||||
border-left: 3px solid var(--rym-stroke);
|
|
||||||
padding-left: 15px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.day-part-card::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
left: -6px;
|
|
||||||
top: 0;
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: var(--rym-stroke);
|
|
||||||
}
|
|
||||||
|
|
||||||
.day-part-active {
|
|
||||||
border-left-color: var(--rym-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.day-part-active::before {
|
|
||||||
background: var(--rym-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Badges de Séances d'endurance */
|
|
||||||
.workout {
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
margin-top: 10px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.run { background: #fff7ed; color: #9a3412; }
|
|
||||||
.bike { background: #f0f9ff; color: #075985; }
|
|
||||||
.swim { background: #f0fdfa; color: #115e59; }
|
|
||||||
|
|
||||||
/* Carte Macro Annu */
|
|
||||||
.macro-card {
|
|
||||||
background: linear-gradient(135deg, #1e293b, #0f172a);
|
|
||||||
color: white;
|
|
||||||
border-radius: 20px;
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --- MOTEUR DE NAVIGATION SOUVERAIN (FIX DE L'AFFICHAGE) --- */
|
|
||||||
.tab-pane {
|
|
||||||
display: none !important;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Force l'affichage et l'opacité à 1 quand l'onglet est actif */
|
|
||||||
.tab-pane.active {
|
|
||||||
display: block !important;
|
|
||||||
opacity: 1 !important;
|
|
||||||
animation: rymFadeIn 0.25s ease-out forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rymFadeIn {
|
|
||||||
from { opacity: 0; transform: translateY(6px); }
|
|
||||||
to { opacity: 1; transform: translateY(0); }
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue