From 278245cd7c32b9098c26ae853fd4edf7391755b4 Mon Sep 17 00:00:00 2001 From: DevOps Engineer Date: Wed, 29 Apr 2026 15:43:02 +0200 Subject: [PATCH 1/2] =?UTF-8?q?feat(HRT-84):=20dashboard=20SaaS=20?= =?UTF-8?q?=E2=80=94=20UI=20Premium=20&=20Pro=20avec=20gating=20plan=20str?= =?UTF-8?q?ict?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ajout sections: Value Bets, Alertes Telegram, API Token, Webhook, Historique, Multi-compte - Gating plan strict: Free < Premium < Pro (jamais de données réelles derrière plan inférieur) - Value Bets: raccordé sur endpoint réel /api/v1/valuebets (premium+) - Historique: raccordé sur endpoint réel /api/v1/history (HRT-81) - Telegram / API Token / Webhook: mocks structurés avec contrats d'interface (TODO: replace mock — HRT-79 pour Telegram, HRT-80 pour API Token/Webhook) - Multi-compte: gating UI Pro uniquement, endpoint non défini - Navigation par section avec chargement lazy - Design cohérent dark theme avec badges, lock icons et CTA upgrade par plan Co-Authored-By: Paperclip --- dashboard_saas.html | 1266 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 1188 insertions(+), 78 deletions(-) diff --git a/dashboard_saas.html b/dashboard_saas.html index 797d425..2702ec3 100644 --- a/dashboard_saas.html +++ b/dashboard_saas.html @@ -11,7 +11,7 @@ --gold: #ffd600; --orange: #ff6d00; --dark: #0d1117; --dark2: #161b22; --dark3: #21262d; --text: #e6edf3; --muted: #8b949e; --border: #30363d; - --radius: 10px; --error: #f85149; + --radius: 10px; --error: #f85149; --purple: #7c3aed; } html { scroll-behavior: smooth; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: var(--dark); color: var(--text); min-height: 100vh; display: flex; } @@ -35,6 +35,7 @@ .nav-item:hover { background: var(--dark3); color: var(--text); } .nav-item.active { background: rgba(0,200,83,.1); color: var(--green); } .nav-item .icon { font-size: 1.1rem; width: 22px; text-align: center; } + .nav-item .plan-lock { font-size: .65rem; margin-left: auto; opacity: .6; } .sidebar-bottom { margin-top: auto; padding: 16px; border-top: 1px solid var(--border); } .user-chip { display: flex; align-items: center; gap: 10px; } .user-avatar { width: 32px; height: 32px; border-radius: 50%; background: var(--green); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: .9rem; color: #000; flex-shrink: 0; } @@ -57,6 +58,10 @@ .btn-ghost { background: transparent; border: 1px solid var(--border); color: var(--text); } .btn-ghost:hover { border-color: var(--muted); } .btn-upgrade { background: linear-gradient(135deg, var(--gold), var(--orange)); color: #000; } + .btn-upgrade-pro { background: linear-gradient(135deg, var(--blue), var(--purple)); color: #fff; } + .btn-danger { background: rgba(248,81,73,.15); color: var(--error); border: 1px solid rgba(248,81,73,.3); } + .btn-danger:hover { background: rgba(248,81,73,.25); } + .btn-sm { padding: 5px 12px; font-size: .8rem; } /* CONTENT */ .content { padding: 28px; } @@ -102,12 +107,17 @@ .rank-2 { color: var(--muted); } .rank-3 { color: #cd7f32; } - /* BLURRED (locked) */ - .locked { filter: blur(6px); pointer-events: none; user-select: none; position: relative; } - .locked-overlay { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: rgba(13,17,23,.7); border-radius: var(--radius); z-index: 2; } - .locked-overlay-msg { text-align: center; } - .locked-overlay-msg h3 { font-size: 1rem; margin-bottom: 8px; } + /* LOCK / GATING */ .lock-wrap { position: relative; } + .plan-gate { + background: var(--dark2); border: 1px solid var(--border); border-radius: var(--radius); + padding: 40px 24px; text-align: center; margin-bottom: 24px; + } + .plan-gate .gate-icon { font-size: 2.5rem; margin-bottom: 12px; } + .plan-gate h3 { font-size: 1rem; margin-bottom: 8px; } + .plan-gate p { font-size: .88rem; color: var(--muted); max-width: 400px; margin: 0 auto 16px; line-height: 1.5; } + .plan-gate.gate-premium { border-color: rgba(255,214,0,.3); } + .plan-gate.gate-pro { border-color: rgba(30,136,229,.3); } /* RACE CARD grid */ .races-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; margin-bottom: 24px; } @@ -126,26 +136,112 @@ .horse-chip.top2 { border-color: var(--muted); } .horse-chip.top3 { border-color: #cd7f32; color: #cd7f32; background: rgba(205,127,50,.08); } + /* VALUE BET CARDS */ + .vb-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; margin-bottom: 24px; } + .vb-card { + background: var(--dark2); border: 1px solid rgba(0,200,83,.2); + border-radius: var(--radius); padding: 16px 18px; + transition: border-color .2s, transform .15s; + } + .vb-card:hover { border-color: var(--green); transform: translateY(-2px); } + .vb-card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } + .vb-horse { font-weight: 700; font-size: .95rem; } + .vb-cote { font-size: 1.1rem; font-weight: 800; color: var(--green); } + .vb-race { font-size: .78rem; color: var(--muted); margin-bottom: 8px; } + .vb-stats { display: flex; gap: 12px; font-size: .78rem; color: var(--muted); } + .vb-stat-item { display: flex; flex-direction: column; gap: 2px; } + .vb-stat-label { font-size: .68rem; text-transform: uppercase; letter-spacing: .5px; } + .vb-stat-val { font-weight: 700; color: var(--text); } + .vb-risk { padding: 2px 8px; border-radius: 10px; font-size: .72rem; font-weight: 700; } + .vb-risk-low { background: rgba(0,200,83,.15); color: var(--green); } + .vb-risk-med { background: rgba(255,214,0,.15); color: var(--gold); } + .vb-risk-high { background: rgba(248,81,73,.15); color: var(--error); } + + /* FORM CARDS */ + .form-card { background: var(--dark2); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; margin-bottom: 20px; } + .form-card h3 { font-size: .95rem; font-weight: 700; margin-bottom: 18px; } + .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; } + .form-group { display: flex; flex-direction: column; gap: 6px; } + .form-group label { font-size: .8rem; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: .4px; } + .form-group input, .form-group select, .form-group textarea { + background: var(--dark3); border: 1px solid var(--border); + border-radius: 8px; padding: 9px 12px; color: var(--text); font-size: .88rem; + outline: none; transition: border-color .2s; font-family: inherit; + } + .form-group input:focus, .form-group select:focus, .form-group textarea:focus { border-color: var(--green); } + .form-group input.mono { font-family: monospace; letter-spacing: .5px; } + .form-actions { display: flex; gap: 10px; flex-wrap: wrap; } + .status-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; } + .status-ok { background: var(--green); } + .status-off { background: var(--muted); } + .status-err { background: var(--error); } + .inline-status { font-size: .82rem; color: var(--muted); } + .token-display { + background: var(--dark3); border: 1px solid var(--border); border-radius: 8px; + padding: 10px 14px; font-family: monospace; font-size: .82rem; + word-break: break-all; color: var(--green); letter-spacing: .5px; + display: flex; align-items: center; justify-content: space-between; gap: 8px; + } + .copy-btn { cursor: pointer; opacity: .6; font-size: .75rem; white-space: nowrap; } + .copy-btn:hover { opacity: 1; } + + /* HISTORY */ + .history-filters { display: flex; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; align-items: flex-end; } + .history-filters .form-group { min-width: 160px; } + .hist-vb-tag { background: rgba(0,200,83,.15); color: var(--green); padding: 1px 6px; border-radius: 8px; font-size: .72rem; font-weight: 700; } + + /* MULTI-ACCOUNT */ + .member-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--border); } + .member-row:last-child { border-bottom: none; } + .member-avatar { width: 36px; height: 36px; border-radius: 50%; background: var(--dark3); display: flex; align-items: center; justify-content: center; font-weight: 700; color: var(--muted); flex-shrink: 0; } + .member-info { flex: 1; } + .member-name { font-size: .9rem; font-weight: 600; } + .member-email { font-size: .78rem; color: var(--muted); } + .member-plan-badge { font-size: .72rem; padding: 2px 8px; border-radius: 10px; } + /* EMPTY STATE */ .empty-state { text-align: center; padding: 60px 20px; color: var(--muted); } .empty-state .icon { font-size: 3rem; margin-bottom: 14px; } .empty-state h3 { font-size: 1.1rem; font-weight: 700; color: var(--text); margin-bottom: 8px; } .empty-state p { font-size: .9rem; max-width: 360px; margin: 0 auto 20px; } + /* TABS */ + .tab-bar { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 20px; overflow-x: auto; } + .tab-btn { + padding: 10px 18px; font-size: .88rem; font-weight: 600; cursor: pointer; + border-bottom: 2px solid transparent; color: var(--muted); white-space: nowrap; + transition: all .15s; background: none; border-top: none; border-left: none; border-right: none; + } + .tab-btn:hover { color: var(--text); } + .tab-btn.active { color: var(--text); border-bottom-color: var(--green); } + .tab-panel { display: none; } + .tab-panel.active { display: block; } + /* TOAST */ #toast { position: fixed; bottom: 24px; right: 24px; z-index: 999; padding: 12px 20px; border-radius: 10px; font-size: .88rem; font-weight: 600; transform: translateY(60px); opacity: 0; transition: all .3s; pointer-events: none; } #toast.show { transform: translateY(0); opacity: 1; } #toast.success { background: var(--green); color: #000; } #toast.info { background: var(--blue); color: #fff; } + #toast.error { background: var(--error); color: #fff; } /* LOADING */ .loader-row { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 40px; color: var(--muted); } .spinner { width: 20px; height: 20px; border: 2px solid var(--border); border-top-color: var(--green); border-radius: 50%; animation: spin .7s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } + /* SECTION WRAPPER */ + .dashboard-section { margin-bottom: 32px; } + /* RESPONSIVE */ - @media (max-width: 900px) { .sidebar { display: none; } } - @media (max-width: 600px) { .stats-row { grid-template-columns: 1fr 1fr; } .content { padding: 16px; } } + @media (max-width: 900px) { + .sidebar { display: none; } + } + @media (max-width: 600px) { + .stats-row { grid-template-columns: 1fr 1fr; } + .content { padding: 16px; } + .form-row { grid-template-columns: 1fr; } + .history-filters { flex-direction: column; } + } @@ -155,15 +251,19 @@ - 📊 Dashboard - 🏁 Courses du jour - 🧠 Prédictions - 💎 Value Bets + 📊 Dashboard + 🏁 Courses du jour + 💎 Value Bets - 📅 Historique - 📤 Export CSV - API Docs + 📅 Historique + 📤 Export CSV + + + 📱 Alertes Telegram + API Token + 🔗 Webhook + 👥 Multi-compte ⚙️ Mon compte @@ -183,7 +283,7 @@
-
Tableau de bord
+
Tableau de bord
@@ -191,74 +291,481 @@
+ - -
-
-
Courses analysées
-
-
aujourd'hui
+ + + +
+ +
+
+
Courses analysées
+
+
aujourd'hui
+
+
+
Précision Top-3
+
+
30 derniers jours
+
+
+
Value bets du jour
+
+
+
+
+
Prochaine course
+
+
+
-
-
Précision Top-3
-
-
30 derniers jours
+ + +
+ 🏇 Résumé du jour + Chargement…
-
-
Value bets du jour
-
-
-
-
-
Prochaine course
-
-
+
+
Chargement…
- -
- 🏁 Prédictions du jour - Chargement… + + + + -
-
Chargement des prédictions…
-
+ + + +