Compare commits

..

No commits in common. "main" and "v0.1.0-alpha" have entirely different histories.

10 changed files with 61 additions and 632 deletions

49
.gitignore vendored
View File

@ -1,49 +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/

View File

@ -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
}
}

View File

@ -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.

View File

@ -1,53 +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.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.
### Modifié
- **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
View File

@ -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
====================================================================

View File

@ -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`

61
app.js
View File

@ -1,61 +0,0 @@
document.addEventListener("DOMContentLoaded", () => {
// --- GESTION DES ONGLETS EXISTANTE ---
const navLinks = document.querySelectorAll(".nav-link");
const tabContents = document.querySelectorAll(".tab-content");
navLinks.forEach(link => {
link.addEventListener("click", (e) => {
e.preventDefault();
navLinks.forEach(l => l.classList.remove("active"));
tabContents.forEach(tc => tc.classList.remove("active"));
link.classList.add("active");
const tabId = link.getAttribute("data-tab");
document.getElementById(tabId).classList.add("active");
});
});
// --- OPTION 1 : DRAG & DROP ENGINE (AAA SOUVERAIN) ---
const draggables = document.querySelectorAll(".rym-draggable-workout");
const dropZones = document.querySelectorAll(".drop-zone");
draggables.forEach(draggable => {
draggable.addEventListener("dragstart", (e) => {
e.dataTransfer.setData("text/plain", draggable.id);
// Petit délai pour l'effet visuel de déplacement
setTimeout(() => {
draggable.style.display = "none";
}, 0);
});
draggable.addEventListener("dragend", () => {
draggable.style.display = "block";
});
});
dropZones.forEach(zone => {
zone.addEventListener("dragover", (e) => {
e.preventDefault(); // Indispensable pour autoriser le drop
zone.classList.add("drag-over");
});
zone.addEventListener("dragleave", () => {
zone.classList.remove("drag-over");
});
zone.addEventListener("drop", (e) => {
e.preventDefault();
zone.classList.remove("drag-over");
const id = e.dataTransfer.getData("text/plain");
const draggableElement = document.getElementById(id);
if (draggableElement) {
zone.appendChild(draggableElement);
// Ici se branchera l'appel API asynchrone vers ton Gitea/Serveur
const targetDay = zone.getAttribute("data-day");
console.log(`Séance déplacée avec succès sur le jour : ${targetDay}`);
}
});
});
});

View File

@ -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"
}
}
];

View File

@ -6,189 +6,95 @@
<title>RYM Horizon | Écosystème Souverain</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<link rel="stylesheet" href="style.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
: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; }
.sidebar { min-height: 100vh; background: var(--rym-dark); color: white; }
.nav-link { color: #8a8d91; border-radius: 10px; padding: 10px 15px; margin-bottom: 4px; cursor: pointer; }
.nav-link.active { background: var(--rym-main); color: white; }
.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; }
.card-rym { border: none; border-radius: 18px; box-shadow: 0 4px 20px rgba(0,0,0,0.05); background: white; }
.tab-content { display: none; }
.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>
<body>
<div class="container-fluid">
<div class="row">
<nav class="col-md-2 d-none d-md-block sidebar p-4 sticky-top">
<h4 class="fw-bold text-center mb-5">RYM <span class="text-info">HORIZON</span></h4>
<div class="sidebar-heading">Admin</div>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" data-tab="dashboard"><i class="bi bi-shield-check me-2"></i> MCO Dashboard</a>
</li>
</ul>
<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" data-tab="bank"><i class="bi bi-bank me-2"></i> RYM Bank</a>
</li>
</ul>
<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" data-tab="activity"><i class="bi bi-heart-pulse me-2"></i> RYM Coach</a>
</li>
</ul>
<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" data-tab="clients"><i class="bi bi-people me-2"></i> Suivi Cohorte</a>
</li>
</ul>
<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">
<section id="dashboard" class="tab-content active">
<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 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>
</section>
<section id="bank" class="tab-content">
<div id="bank" class="tab-content">
<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>
</section>
</div>
<section id="activity" class="tab-content">
<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-4">
<h5 class="mb-3 text-primary"><i class="bi bi-activity me-2"></i>Indicateurs de Performance & Souveraineté</h5>
<div class="row row-cols-2 row-cols-sm-2 row-cols-md-4 g-3 text-center justify-content-center">
<div class="col">
<div class="rym-spinner-wrapper">
<svg class="rym-spinner-svg" viewBox="0 0 36 36">
<path class="circle-bg" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
<path class="circle-stroke text-success" stroke-dasharray="82, 100" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
</svg>
<div class="rym-spinner-text">
<span class="fw-bold fs-5">82</span><small>%</small>
</div>
</div>
<div class="small fw-semibold mt-2">Fraîcheur VRC</div>
</div>
<div class="col">
<div class="rym-spinner-wrapper">
<svg class="rym-spinner-svg" viewBox="0 0 36 36">
<path class="circle-bg" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
<path class="circle-stroke text-warning" stroke-dasharray="65, 100" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
</svg>
<div class="rym-spinner-text">
<span class="fw-bold fs-5">65</span><small>%</small>
</div>
</div>
<div class="small fw-semibold mt-2">Charge Hebdo</div>
</div>
<div class="col">
<div class="rym-spinner-wrapper">
<svg class="rym-spinner-svg" viewBox="0 0 36 36">
<path class="circle-bg" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
<path class="circle-stroke text-info" stroke-dasharray="45, 100" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
</svg>
<div class="rym-spinner-text">
<span class="fw-bold fs-5">45</span><small>%</small>
</div>
</div>
<div class="small fw-semibold mt-2">Chaîne Vélo</div>
</div>
<div class="col">
<div class="rym-spinner-wrapper">
<svg class="rym-spinner-svg" viewBox="0 0 36 36">
<path class="circle-bg" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
<path class="circle-stroke text-danger" stroke-dasharray="90, 100" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" />
</svg>
<div class="rym-spinner-text">
<span class="fw-bold fs-5">90</span><small>%</small>
</div>
</div>
<div class="small fw-semibold mt-2">Paires Carbone</div>
</div>
</div>
</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 Dynamique</h5>
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-4 row-cols-lg-7 g-2" id="planning-kanban">
<div class="col">
<div class="bg-light p-2 rounded border h-100 drop-zone" data-day="Lun">
<div class="fw-bold text-center border-bottom pb-1 mb-2 bg-dark text-white rounded-top small">Lundi</div>
<div class="rym-draggable-workout bg-primary text-white p-2 rounded mb-2 shadow-sm small" draggable="true" id="w1">
<i class="bi bi-water me-1"></i> Natation : 2500m
</div>
</div>
</div>
<div class="col">
<div class="bg-light p-2 rounded border h-100 drop-zone" data-day="Mar">
<div class="fw-bold text-center border-bottom pb-1 mb-2 bg-dark text-white rounded-top small">Mardi</div>
<div class="rym-draggable-workout bg-warning text-dark p-2 rounded mb-2 shadow-sm small" draggable="true" id="w2">
<i class="bi bi-lightning me-1"></i> VMA Balayage
</div>
</div>
</div>
<div class="col">
<div class="bg-light p-2 rounded border h-100 drop-zone" data-day="Mer">
<div class="fw-bold text-center border-bottom pb-1 mb-2 bg-dark text-white rounded-top small">Mercredi</div>
<div class="rym-draggable-workout bg-info text-dark p-2 rounded mb-2 shadow-sm small" draggable="true" id="w3">
<i class="bi bi-bicycle me-1"></i> Vélo Tempête
</div>
</div>
</div>
<div class="col">
<div class="bg-light p-2 rounded border h-100 drop-zone" data-day="Jeu">
<div class="fw-bold text-center border-bottom pb-1 mb-2 bg-dark text-white rounded-top small">Jeudi</div>
</div>
</div>
<div class="col">
<div class="bg-light p-2 rounded border h-100 drop-zone" data-day="Ven">
<div class="fw-bold text-center border-bottom pb-1 mb-2 bg-dark text-white rounded-top small">Vendredi</div>
</div>
</div>
<div class="col">
<div class="bg-light p-2 rounded border h-100 drop-zone" data-day="Sam">
<div class="fw-bold text-center border-bottom pb-1 mb-2 bg-dark text-white rounded-top small">Samedi</div>
</div>
</div>
<div class="col">
<div class="bg-light p-2 rounded border h-100 drop-zone" data-day="Dim">
<div class="fw-bold text-center border-bottom pb-1 mb-2 bg-dark text-white rounded-top small">Dimanche</div>
</div>
</div>
<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>
<section id="clients" class="tab-content">
<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">
@ -222,7 +128,7 @@
<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">Cuisse (D/G): 58/58</div><div class="col-6 text-primary text-end">Mollet (D/G): 39/39</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 class="mt-4 p-2 bg-light border rounded text-center x-small">
<i class="bi bi-shield-lock me-1"></i> Données Chiffrées (Souveraineté RYM)
@ -230,13 +136,19 @@
</div>
</div>
</div>
</section>
</div>
</main>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<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>
</html>

150
style.css
View File

@ -1,150 +0,0 @@
/* Variables de Design System RYM */
:root {
--rym-main: #004a99;
--rym-dark: #121416;
--rym-accent: #00d1b2;
--rym-premium: #ffd700;
--rym-bg: #f0f2f5;
}
/* Base App Layout */
body {
background-color: var(--rym-bg);
font-family: 'Inter', sans-serif;
font-size: 0.9rem;
}
/* Navigation & Sidebar UI */
.sidebar {
min-height: 100vh;
background: var(--rym-dark);
color: white;
}
.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;
}
.nav-link {
color: #8a8d91;
border-radius: 10px;
padding: 10px 15px;
margin-bottom: 4px;
cursor: pointer;
transition: background 0.2s ease, color 0.2s ease;
}
.nav-link:hover {
color: white;
background: rgba(255, 255, 255, 0.05);
}
.nav-link.active {
background: var(--rym-main);
color: white;
}
/* UI Components */
.card-rym {
border: none;
border-radius: 18px;
box-shadow: 0 4px 20px rgba(0,0,0,0.05);
background: white;
}
.premium-zone {
border: 2px solid var(--rym-premium);
position: relative;
}
/* Agenda Components */
.agenda-scroll {
max-height: 250px;
overflow-y: auto;
}
.hour-row {
border-bottom: 1px solid #eee;
min-height: 40px;
display: flex;
align-items: center;
}
/* Router / Navigation Tabs States */
.tab-content {
display: none;
}
.tab-content.active {
display: block;
animation: fadeIn 0.3s forwards;
}
/* Animations */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
}
/* --- CONFIGURATION DES SPINNERS (OPTION 2) --- */
.rym-spinner-wrapper {
position: relative;
width: 90px;
height: 90px;
margin: 0 auto;
}
.rym-spinner-svg {
width: 100%;
height: 100%;
transform: rotate(-90deg);
}
.circle-bg {
fill: none;
stroke: #e6e6e6;
stroke-width: 2.8;
}
.circle-stroke {
fill: none;
stroke-width: 2.8;
stroke-linecap: round;
transition: stroke-dasharray 0.5s ease;
}
.rym-spinner-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
/* --- DRAG AND DROP KANBAN (OPTION 1) --- */
.drop-zone {
min-height: 140px;
transition: background-color 0.2s ease, border-color 0.2s ease;
}
.drop-zone.drag-over {
background-color: #e2e8f0 !important;
border: 2px dashed #0dcaf0 !important;
}
.rym-draggable-workout {
cursor: grab;
transition: transform 0.1s ease, opacity 0.1s ease;
user-select: none;
}
.rym-draggable-workout:active {
cursor: grabbing;
opacity: 0.5;
}