déplacement des sections mail dans la partie "profile" modification de la page home logique à mettre en placeWebUI
| @@ -5,81 +5,115 @@ | |||
| <BlazoredToasts /> | |||
| <div class="page"> | |||
| <!-- Barre supérieure fixe --> | |||
| <div class="top-bar"> | |||
| <div class="top-bar-content"> | |||
| <div class="top-bar-left"> | |||
| <button class="burger-menu" onclick="toggleSidebar()" aria-label="Toggle menu"> | |||
| <span></span> | |||
| <span></span> | |||
| <span></span> | |||
| </button> | |||
| <a href="https://www.allin-it.fr/" target="_blank" class="logo-link"> | |||
| <img src="images/logo.png" alt="Logo All in IT" width="50" height="50" /> | |||
| </a> | |||
| <a class="app-title" href="">AI-100-SaaS</a> | |||
| </div> | |||
| <div class="top-bar-right"> | |||
| <div class="user-menu"> | |||
| <button class="user-menu-button" onclick="toggleUserMenu(event)"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16"> | |||
| <path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0" /> | |||
| <path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1" /> | |||
| </svg> | |||
| </button> | |||
| <div class="user-menu-dropdown" id="userMenuDropdown"> | |||
| <AuthorizeView Roles="Admin"> | |||
| <Authorized> | |||
| <a href="administration" class="dropdown-item"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-tools dropdown-icon " viewBox="0 0 16 16"> | |||
| <path d="M1 0 0 1l2.2 3.081a1 1 0 0 0 .815.419h.07a1 1 0 0 1 .708.293l2.675 2.675-2.617 2.654A3.003 3.003 0 0 0 0 13a3 3 0 1 0 5.878-.851l2.654-2.617.968.968-.305.914a1 1 0 0 0 .242 1.023l3.27 3.27a.997.997 0 0 0 1.414 0l1.586-1.586a.997.997 0 0 0 0-1.414l-3.27-3.27a1 1 0 0 0-1.023-.242L10.5 9.5l-.96-.96 2.68-2.643A3.005 3.005 0 0 0 16 3q0-.405-.102-.777l-2.14 2.141L12 4l-.364-1.757L13.777.102a3 3 0 0 0-3.675 3.68L7.462 6.46 4.793 3.793a1 1 0 0 1-.293-.707v-.071a1 1 0 0 0-.419-.814zm9.646 10.646a.5.5 0 0 1 .708 0l2.914 2.915a.5.5 0 0 1-.707.707l-2.915-2.914a.5.5 0 0 1 0-.708M3 11l.471.242.529.026.287.445.445.287.026.529L5 13l-.242.471-.026.529-.445.287-.287.445-.529.026L3 15l-.471-.242L2 14.732l-.287-.445L1.268 14l-.026-.529L1 13l.242-.471.026-.529.445-.287.287-.445.529-.026z" /> | |||
| <div class="main-container"> | |||
| <div class=""> | |||
| <NavMenu /> | |||
| </div> | |||
| <div class="content-area"> | |||
| <!-- Barre supérieure (au-dessus du contenu uniquement) --> | |||
| <div class="top-bar"> | |||
| <div class="top-bar-content"> | |||
| <div class="top-bar-left"> | |||
| <button class="burger-menu" onclick="toggleSidebar()" aria-label="Toggle menu"> | |||
| <span></span> | |||
| <span></span> | |||
| <span></span> | |||
| </button> | |||
| <!-- | |||
| <a href="https://www.allin-it.fr/" target="_blank" class="logo-link"> | |||
| <img src="images/logo.png" alt="Logo All in IT" width="50" height="50" /> | |||
| </a> | |||
| <a class="app-title" href="">AI-100-SaaS</a> | |||
| --> | |||
| </div> | |||
| <div class="top-bar-right"> | |||
| <div class="user-menu"> | |||
| <button class="user-menu-button" onclick="toggleUserMenu(event)"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16"> | |||
| <path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0" /> | |||
| <path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1" /> | |||
| </svg> | |||
| </button> | |||
| <div class="user-menu-dropdown" id="userMenuDropdown"> | |||
| <AuthorizeView Roles="Admin"> | |||
| <Authorized> | |||
| <a href="administration" class="dropdown-item"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-tools dropdown-icon" viewBox="0 0 16 16"> | |||
| <path d="M1 0 0 1l2.2 3.081a1 1 0 0 0 .815.419h.07a1 1 0 0 1 .708.293l2.675 2.675-2.617 2.654A3.003 3.003 0 0 0 0 13a3 3 0 1 0 5.878-.851l2.654-2.617.968.968-.305.914a1 1 0 0 0 .242 1.023l3.27 3.27a.997.997 0 0 0 1.414 0l1.586-1.586a.997.997 0 0 0 0-1.414l-3.27-3.27a1 1 0 0 0-1.023-.242L10.5 9.5l-.96-.96 2.68-2.643A3.005 3.005 0 0 0 16 3q0-.405-.102-.777l-2.14 2.141L12 4l-.364-1.757L13.777.102a3 3 0 0 0-3.675 3.68L7.462 6.46 4.793 3.793a1 1 0 0 1-.293-.707v-.071a1 1 0 0 0-.419-.814zm9.646 10.646a.5.5 0 0 1 .708 0l2.914 2.915a.5.5 0 0 1-.707.707l-2.915-2.914a.5.5 0 0 1 0-.708M3 11l.471.242.529.026.287.445.445.287.026.529L5 13l-.242.471-.026.529-.445.287-.287.445-.529.026L3 15l-.471-.242L2 14.732l-.287-.445L1.268 14l-.026-.529L1 13l.242-.471.026-.529.445-.287.287-.445.529-.026z" /> | |||
| </svg> | |||
| <span>Administration</span> | |||
| </a> | |||
| </Authorized> | |||
| </AuthorizeView> | |||
| <a href="dt_work_force_list" class="dropdown-item"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person dropdown-icon" viewBox="0 0 16 16"> | |||
| <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6m2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0m4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4m-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10s-3.516.68-4.168 1.332c-.678.678-.83 1.418-.832 1.664z" /> | |||
| </svg> | |||
| <span>Administration</span> | |||
| <span>Mon compte</span> | |||
| </a> | |||
| </Authorized> | |||
| </AuthorizeView> | |||
| <a href="dt_work_force_list" class="dropdown-item"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person dropdown-icon" viewBox="0 0 16 16"> | |||
| <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6m2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0m4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4m-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10s-3.516.68-4.168 1.332c-.678.678-.83 1.418-.832 1.664z" /> | |||
| </svg> | |||
| <span>Mon compte</span> | |||
| </a> | |||
| <div class="dropdown-divider"></div> | |||
| <div class="dropdown-divider"></div> | |||
| <a href="logout" class="dropdown-item"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-door-closed dropdown-icon" viewBox="0 0 16 16"> | |||
| <path d="M3 2a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v13h1.5a.5.5 0 0 1 0 1h-13a.5.5 0 0 1 0-1H3zm1 13h8V2H4z" /> | |||
| <path d="M9 9a1 1 0 1 0 2 0 1 1 0 0 0-2 0" /> | |||
| </svg> | |||
| <span>Déconnexion</span> | |||
| </a> | |||
| <a href="listemails_card" class="dropdown-item"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-envelope dropdown-icon" viewBox="0 0 16 16"> | |||
| <path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1zm13 2.383-4.708 2.825L15 11.105zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741M1 11.105l4.708-2.897L1 5.383z" /> | |||
| </svg> | |||
| <span>Emails non lus</span> | |||
| </a> | |||
| <a href="listemailssend_card" class="dropdown-item"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-mailbox dropdown-icon" viewBox="0 0 16 16"> | |||
| <path d="M4 4a3 3 0 0 0-3 3v6h6V7a3 3 0 0 0-3-3m0-1h8a4 4 0 0 1 4 4v6a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V7a4 4 0 0 1 4-4m2.646 1A4 4 0 0 1 8 7v6h7V7a3 3 0 0 0-3-3z" /> | |||
| <path d="M11.793 8.5H9v-1h5a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.354-.146zM5 7c0 .552-.448 0-1 0s-1 .552-1 0a1 1 0 0 1 2 0" /> | |||
| </svg> | |||
| <span>Emails à suivre</span> | |||
| </a> | |||
| <a href="editmail_redaction" class="dropdown-item"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-square dropdown-icon" viewBox="0 0 16 16"> | |||
| <path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z" /> | |||
| <path fill-rule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5z" /> | |||
| </svg> | |||
| <span>Rédiger un email</span> | |||
| </a> | |||
| <a href="parametres_mail" class="dropdown-item"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-gear dropdown-icon" viewBox="0 0 16 16"> | |||
| <path d="M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492M5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0" /> | |||
| <path d="M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.433-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.377l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115z" /> | |||
| </svg> | |||
| <span>Paramètres mails</span> | |||
| </a> | |||
| <div class="dropdown-divider"></div> | |||
| <a href="logout" class="dropdown-item"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-door-closed dropdown-icon" viewBox="0 0 16 16"> | |||
| <path d="M3 2a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v13h1.5a.5.5 0 0 1 0 1h-13a.5.5 0 0 1 0-1H3zm1 13h8V2H4z" /> | |||
| <path d="M9 9a1 1 0 1 0 2 0 1 1 0 0 0-2 0" /> | |||
| </svg> | |||
| <span>Déconnexion</span> | |||
| </a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="sidebar-overlay" id="sidebarOverlay" onclick="closeSidebar()"></div> | |||
| <!-- Container principal avec sidebar et contenu --> | |||
| <div class="main-container"> | |||
| <!-- Sidebar avec le menu --> | |||
| <div class="sidebar" id="sidebar"> | |||
| <NavMenu /> | |||
| </div> | |||
| <div class="content-wrapper"> | |||
| <main class="main-content"> | |||
| @Body | |||
| </main> | |||
| <footer class="footer"> | |||
| <small> | |||
| <p>© 2025 Make with love - Tous droits réservés - Version 1.0.0</p> | |||
| </small> | |||
| </footer> | |||
| <div class="content-wrapper"> | |||
| <main class="main-content"> | |||
| @Body | |||
| </main> | |||
| <footer class="footer"> | |||
| <small> | |||
| <p>© 2025 Make with love - Tous droits réservés - Version 1.0.0</p> | |||
| </small> | |||
| </footer> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -99,16 +133,14 @@ | |||
| const sidebar = document.getElementById('sidebar'); | |||
| const overlay = document.getElementById('sidebarOverlay'); | |||
| const burger = document.querySelector('.burger-menu'); | |||
| sidebar.classList.remove('active'); | |||
| overlay.classList.remove('active'); | |||
| burger.classList.remove('active'); | |||
| } | |||
| function toggleUserMenu(event) { | |||
| event.stopPropagation(); | |||
| const dropdown = document.getElementById('userMenuDropdown'); | |||
| dropdown.classList.toggle('show'); | |||
| if (dropdown) { | |||
| dropdown.classList.toggle('show'); | |||
| } | |||
| } | |||
| document.addEventListener('click', function(event) { | |||
| @@ -129,4 +161,4 @@ | |||
| authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); | |||
| user = authState.User; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,46 +1,65 @@ | |||
| /* Page principale */ | |||
| .page { | |||
| display: flex; | |||
| flex-direction: column; | |||
| height: 100vh; | |||
| width: 100%; | |||
| width: 100vw; | |||
| overflow: hidden; | |||
| } | |||
| main { | |||
| .main-container { | |||
| display: flex; | |||
| flex: 1; | |||
| overflow: hidden; | |||
| } | |||
| /* Conteneur de layout principal */ | |||
| .layout-container { | |||
| display: flex; | |||
| flex-direction: column; | |||
| height: 100%; /* Prend toute la hauteur de la fenêtre (viewport height) */ | |||
| width: 100%; /* Prend toute la largeur de la fenêtre (viewport width) */ | |||
| overflow: hidden; /* Empêche les barres de défilement, utile pour un layout sans débordement */ | |||
| .sidebar { | |||
| width: 280px; | |||
| background: linear-gradient(180deg, var(--secondary-color), var(--main-color)); | |||
| height: 100vh; /* Prend toute la hauteur de l'écran */ | |||
| overflow-y: auto; | |||
| overflow-x: hidden; | |||
| flex-shrink: 0; | |||
| transition: transform 0.3s ease; | |||
| } | |||
| .sidebar::-webkit-scrollbar { | |||
| width: 6px; | |||
| } | |||
| /* Conteneur principal avec sidebar et contenu */ | |||
| .main-container { | |||
| display: flex; | |||
| .sidebar::-webkit-scrollbar-track { | |||
| background: rgba(255, 255, 255, 0.1); | |||
| } | |||
| .sidebar::-webkit-scrollbar-thumb { | |||
| background: rgba(255, 255, 255, 0.3); | |||
| border-radius: 3px; | |||
| } | |||
| .sidebar::-webkit-scrollbar-thumb:hover { | |||
| background: rgba(255, 255, 255, 0.5); | |||
| } | |||
| .content-area { | |||
| flex: 1; | |||
| margin-top: 60px; /* Hauteur de la top-bar */ | |||
| height: calc(100vh - 60px); | |||
| display: flex; | |||
| flex-direction: column; | |||
| overflow: hidden; | |||
| } | |||
| /* Barre supérieure fixe */ | |||
| .top-bar { | |||
| height: 60px; | |||
| background-color: #e9ecef; | |||
| border-bottom: 1px solid #dee2e6; | |||
| position: fixed; | |||
| top: 0; | |||
| left: 0; | |||
| right: 0; | |||
| z-index: 1000; | |||
| z-index: 100; | |||
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); | |||
| flex-shrink: 0; | |||
| } | |||
| .top-bar-content { | |||
| @@ -92,25 +111,6 @@ main { | |||
| transform: rotate(-45deg) translate(7px, -7px); | |||
| } | |||
| /* Overlay pour fermer le menu */ | |||
| .sidebar-overlay { | |||
| display: none; | |||
| position: fixed; | |||
| top: 60px; | |||
| left: 0; | |||
| right: 0; | |||
| bottom: 0; | |||
| background-color: rgba(0, 0, 0, 0.5); | |||
| z-index: 998; | |||
| opacity: 0; | |||
| transition: opacity 0.3s ease; | |||
| } | |||
| .sidebar-overlay.active { | |||
| display: block; | |||
| opacity: 1; | |||
| } | |||
| /* Logo */ | |||
| .logo-link { | |||
| display: flex; | |||
| @@ -122,10 +122,6 @@ main { | |||
| opacity: 0.8; | |||
| } | |||
| .logo-link img { | |||
| vertical-align: middle; | |||
| } | |||
| /* Titre de l'application */ | |||
| .app-title { | |||
| font-size: 1.5rem; | |||
| @@ -167,11 +163,6 @@ main { | |||
| transform: scale(1.05); | |||
| } | |||
| .user-menu-button img { | |||
| border-radius: 50%; | |||
| display: block; | |||
| } | |||
| /* Menu déroulant utilisateur */ | |||
| .user-menu-dropdown { | |||
| position: absolute; | |||
| @@ -237,52 +228,36 @@ main { | |||
| } | |||
| /* Bouton de déconnexion */ | |||
| .logout-btn { | |||
| color: #dc3545; | |||
| font-weight: 500; | |||
| } | |||
| .logout-btn:hover { | |||
| background-color: #fff5f5; | |||
| } | |||
| .sidebar { | |||
| width: 280px; | |||
| background: linear-gradient(180deg, var(--secondary-color) , var(--main-color) ); | |||
| overflow-y: auto; | |||
| flex-shrink: 0; | |||
| transition: transform 0.3s ease; | |||
| } | |||
| /* Conteneur de droite qui héberge le contenu principal et le footer */ | |||
| .content-area { | |||
| flex-grow: 1; | |||
| .content-wrapper { | |||
| flex: 1; | |||
| display: flex; | |||
| flex-direction: column; | |||
| overflow: hidden; | |||
| min-width: 0; | |||
| } | |||
| .content-wrapper { | |||
| .main-content { | |||
| flex: 1; | |||
| overflow: auto; | |||
| width: 100%; | |||
| flex-direction: column; | |||
| display:flex; | |||
| overflow-y: auto; | |||
| background-color: #f8f9fa; | |||
| } | |||
| /* Contenu principal : scrollable si trop long */ | |||
| .main-content { | |||
| flex-grow: 1; | |||
| overflow: auto; | |||
| background-color: #f8f9fa; | |||
| .main-content::-webkit-scrollbar { | |||
| width: 8px; | |||
| } | |||
| } | |||
| .main-content::-webkit-scrollbar-track { | |||
| /* Conteneur de droite qui héberge le contenu principal et le footer */ | |||
| } | |||
| .main-content::-webkit-scrollbar-thumb { | |||
| background: #888; | |||
| border-radius: 4px; | |||
| } | |||
| /* Contenu principal : scrollable si trop long */ | |||
| background: #555; | |||
| } | |||
| @@ -291,6 +266,7 @@ main { | |||
| background-color: #e9ecef; | |||
| border-top: 1px solid #dee2e6; | |||
| text-align: center; | |||
| flex-shrink: 0; | |||
| } | |||
| .footer p { | |||
| @@ -300,43 +276,24 @@ main { | |||
| /* Bandeau supérieur (ancien style) */ | |||
| .top-banner { | |||
| padding: 0.5rem 1rem; | |||
| background-color: #e9ecef; | |||
| border-bottom: 1px solid #ccc; | |||
| display: flex; | |||
| justify-content: flex-end; | |||
| align-items: center; | |||
| } | |||
| /* Ancienne barre supérieure */ | |||
| .top-row { | |||
| background-color: #f7f7f7; | |||
| border-bottom: 1px solid #d6d5d5; | |||
| justify-content: flex-end; | |||
| height: 3.5rem; | |||
| display: flex; | |||
| align-items: center; | |||
| .sidebar-overlay { | |||
| display: none; | |||
| position: fixed; | |||
| top: 0; | |||
| left: 0; | |||
| right: 0; | |||
| bottom: 0; | |||
| background-color: rgba(0, 0, 0, 0.5); | |||
| z-index: 998; | |||
| opacity: 0; | |||
| transition: opacity 0.3s ease; | |||
| } | |||
| .top-row ::deep a, | |||
| .top-row ::deep .btn-link { | |||
| white-space: nowrap; | |||
| margin-left: 1.5rem; | |||
| text-decoration: none; | |||
| .sidebar-overlay.active { | |||
| display: block; | |||
| opacity: 1; | |||
| } | |||
| .top-row ::deep a:hover, | |||
| .top-row ::deep .btn-link:hover { | |||
| text-decoration: underline; | |||
| } | |||
| .top-row ::deep a:first-child { | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| } | |||
| @media (max-width: 768px) { | |||
| @@ -352,76 +309,26 @@ main { | |||
| } | |||
| } | |||
| /* Sidebar en position fixe cachée par défaut */ | |||
| .sidebar { | |||
| position: fixed; | |||
| top: 60px; | |||
| top: 0; | |||
| left: 0; | |||
| bottom: 0; | |||
| width: 240px; | |||
| width: 280px; | |||
| z-index: 999; | |||
| transform: translateX(-100%); | |||
| } | |||
| /* Sidebar visible quand active */ | |||
| .sidebar.active { | |||
| transform: translateX(0); | |||
| box-shadow: 2px 0 8px rgba(0, 0, 0, 0.3); | |||
| } | |||
| /* Le contenu prend toute la largeur sur mobile */ | |||
| .content-wrapper { | |||
| width: 100%; | |||
| .main-content { | |||
| padding: 1rem; | |||
| } | |||
| .top-bar-content { | |||
| padding: 0 1rem; | |||
| } | |||
| .top-row { | |||
| justify-content: space-between; | |||
| } | |||
| .top-row ::deep a, | |||
| .top-row ::deep .btn-link { | |||
| margin-left: 0; | |||
| } | |||
| } | |||
| /* Desktop */ | |||
| @media (min-width: 769px) { | |||
| /* Cacher le bouton burger sur desktop */ | |||
| .burger-menu { | |||
| display: none !important; | |||
| } | |||
| .page { | |||
| flex-direction: row; | |||
| } | |||
| .sidebar { | |||
| width: 240px; | |||
| height: 100vh; | |||
| position: sticky; | |||
| top: 0; | |||
| } | |||
| .top-row { | |||
| position: sticky; | |||
| top: 0; | |||
| z-index: 1; | |||
| } | |||
| .top-row.auth ::deep a:first-child { | |||
| flex: 1; | |||
| text-align: right; | |||
| width: 0; | |||
| } | |||
| .top-row, | |||
| article { | |||
| padding-left: 2rem !important; | |||
| padding-right: 1.5rem !important; | |||
| } | |||
| } | |||
| @@ -1,69 +1,309 @@ | |||
| @inject AuthenticationStateProvider AuthenticationStateProvider | |||
| @using Microsoft.AspNetCore.Components.Authorization; | |||
| @using ReAct_PME.WebUI.ServicesUI; | |||
| @using Microsoft.AspNetCore.Components.Authorization | |||
| @using ReAct_PME.Domain | |||
| @using ReAct_PME.WebUI.ServicesUI | |||
| @inject HttpClient Http | |||
| @inject AuthService AuthService | |||
| @inject AuthenticationStateProvider AuthenticationStateProvider | |||
| @inject NavigationManager Navigation | |||
| <div> | |||
| <div class="sidebar @(IsCollapsed ? "collapsed" : "")"> | |||
| <div class="sidebar-header"> | |||
| @if (!IsCollapsed) | |||
| { | |||
| <div class="logo"> | |||
| <h1>AIT</h1> | |||
| </div> | |||
| } | |||
| <button class="toggle-button" @onclick="ToggleSidebar" | |||
| aria-label="@(IsCollapsed ? "Ouvrir la barre latérale" : "Réduire la barre latérale")"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" | |||
| class="bi bi-layout-sidebar" viewBox="0 0 16 16"> | |||
| <path d="M0 3a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm5-1v12h9a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1zM4 2H2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h2z" /> | |||
| </svg> | |||
| </button> | |||
| </div> | |||
| <nav class="menu-section access-section"> | |||
| <div class="sidebar-section"> | |||
| @if (!IsCollapsed) | |||
| { | |||
| <h3 class="section-title"> Conversations</h3> | |||
| <div class="nav-item"> | |||
| <NavLink class="nav-link2" href="" Match="NavLinkMatch.All"> | |||
| <span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home | |||
| </NavLink> | |||
| </div> | |||
| <div class="conversations-section"> | |||
| <button class="new-chat-button" @onclick="OnNewChat" aria-label="Nouvelle conversation"> | |||
| <span class="icon"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chat-dots" viewBox="0 0 16 16"> | |||
| <path d="M5 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0m4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2" /> | |||
| <path d="m2.165 15.803.02-.004c1.83-.363 2.948-.842 3.468-1.105A9 9 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.4 10.4 0 0 1-.524 2.318l-.003.011a11 11 0 0 1-.244.637c-.079.186.074.394.273.362a22 22 0 0 0 .693-.125m.8-3.108a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6-3.004 6-7 6a8 8 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a11 11 0 0 0 .398-2" /> | |||
| </svg> | |||
| </span> | |||
| <span>Nouvelle conversation</span> | |||
| </button> | |||
| <div class="nav-item"> | |||
| <details> | |||
| <summary>💬 ChatRoom</summary> | |||
| <div class="nav-item"> | |||
| <NavLink class="nav-link2" href="chatroom_nav/1">Chat</NavLink> | |||
| <NavLink class="nav-link2" href="chatroom_nav/2">RAG</NavLink> | |||
| </div> | |||
| </details> | |||
| </div> | |||
| @if (IsLoadingChat) | |||
| { | |||
| <div class="loading">Chargement...</div> | |||
| } | |||
| else if (ChatConversations.Any()) | |||
| { | |||
| <div class="conversations-list"> | |||
| @foreach (var conversation in ChatConversations) | |||
| { | |||
| <div class="conversation-item @(CurrentConversationId == conversation.Id ? "active" : "")" | |||
| @onclick="() => OnSelectConversation(conversation.Id, 1)"> | |||
| <span class="conversation-title"> | |||
| @if (!string.IsNullOrEmpty(conversation.Title)) | |||
| { | |||
| @conversation.Title | |||
| } | |||
| else | |||
| { | |||
| @($"Conversation du {conversation.Date:dd/MM/yyyy}") | |||
| } | |||
| </span> | |||
| </div> | |||
| } | |||
| </div> | |||
| } | |||
| else | |||
| { | |||
| <div class="empty-state">Aucune conversation</div> | |||
| } | |||
| </div> | |||
| } | |||
| else | |||
| { | |||
| <button class="new-chat-button" @onclick="OnNewChat" aria-label="Nouvelle conversation"> | |||
| <span class="icon"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chat-dots" viewBox="0 0 16 16"> | |||
| <path d="M5 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0m4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2" /> | |||
| <path d="m2.165 15.803.02-.004c1.83-.363 2.948-.842 3.468-1.105A9 9 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.4 10.4 0 0 1-.524 2.318l-.003.011a11 11 0 0 1-.244.637c-.079.186.074.394.273.362a22 22 0 0 0 .693-.125m.8-3.108a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6-3.004 6-7 6a8 8 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a11 11 0 0 0 .398-2" /> | |||
| </svg> | |||
| <div class="nav-item"> | |||
| <details> | |||
| <summary>📧 Emails</summary> | |||
| <div class="nav-item"> | |||
| <NavLink class="nav-link2" href="listemails_card">Non lus</NavLink> | |||
| <NavLink class="nav-link2" href="listemailssend_card">A suivre</NavLink> | |||
| <NavLink class="nav-link2" href="editmail_redaction">Rédaction d'un mail</NavLink> | |||
| </div> | |||
| </details> | |||
| </div> | |||
| </span> | |||
| </button> | |||
| } | |||
| </div> | |||
| <div class="nav-item"> | |||
| <details> | |||
| <summary>⚙️ Paramètres</summary> | |||
| <div class="nav-item"> | |||
| <NavLink class="nav-link2" href="parametres_mail">Mails</NavLink> | |||
| </div> | |||
| </details> | |||
| </div> | |||
| <div class="sidebar-section"> | |||
| @if (!IsCollapsed) | |||
| { | |||
| <h3 class="section-title"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-folder" viewBox="0 0 16 16"> | |||
| <path d="M.54 3.87.5 3a2 2 0 0 1 2-2h3.672a2 2 0 0 1 1.414.586l.828.828A2 2 0 0 0 9.828 3h3.982a2 2 0 0 1 1.992 2.181l-.637 7A2 2 0 0 1 13.174 14H2.826a2 2 0 0 1-1.991-1.819l-.637-7a2 2 0 0 1 .342-1.31zM2.19 4a1 1 0 0 0-.996 1.09l.637 7a1 1 0 0 0 .995.91h10.348a1 1 0 0 0 .995-.91l.637-7A1 1 0 0 0 13.81 4zm4.69-1.707A1 1 0 0 0 6.172 2H2.5a1 1 0 0 0-1 .981l.006.139q.323-.119.684-.12h5.396z" /> | |||
| </svg> | |||
| RAG</h3> | |||
| </nav> | |||
| <div class="conversations-section"> | |||
| <button class="new-chat-button" @onclick="OnNewRagChat" aria-label="Nouveau RAG"> | |||
| <span class="icon"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chat-dots" viewBox="0 0 16 16"> | |||
| <path d="M5 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0m4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2" /> | |||
| <path d="m2.165 15.803.02-.004c1.83-.363 2.948-.842 3.468-1.105A9 9 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.4 10.4 0 0 1-.524 2.318l-.003.011a11 11 0 0 1-.244.637c-.079.186.074.394.273.362a22 22 0 0 0 .693-.125m.8-3.108a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6-3.004 6-7 6a8 8 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a11 11 0 0 0 .398-2" /> | |||
| </svg> | |||
| </span> | |||
| <span>Nouveau RAG</span> | |||
| </button> | |||
| @if (IsLoadingRag) | |||
| { | |||
| <div class="loading">Chargement...</div> | |||
| } | |||
| else if (RagConversations.Any()) | |||
| { | |||
| <div class="conversations-list"> | |||
| @foreach (var conversation in RagConversations) | |||
| { | |||
| <div class="conversation-item @(CurrentConversationId == conversation.Id ? "active" : "")" | |||
| @onclick="() => OnSelectConversation(conversation.Id, 2)"> | |||
| <span class="conversation-title"> | |||
| @if (!string.IsNullOrEmpty(conversation.Title)) | |||
| { | |||
| @conversation.Title | |||
| } | |||
| else | |||
| { | |||
| @($"RAG du {conversation.Date:dd/MM/yyyy}") | |||
| } | |||
| </span> | |||
| </div> | |||
| } | |||
| </div> | |||
| } | |||
| else | |||
| { | |||
| <div class="empty-state">Aucune conversation RAG</div> | |||
| } | |||
| </div> | |||
| } | |||
| else | |||
| { | |||
| <button class="sidebar-icon-button" aria-label="RAG"> | |||
| <span class="icon"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-folder" viewBox="0 0 16 16"> | |||
| <path d="M.54 3.87.5 3a2 2 0 0 1 2-2h3.672a2 2 0 0 1 1.414.586l.828.828A2 2 0 0 0 9.828 3h3.982a2 2 0 0 1 1.992 2.181l-.637 7A2 2 0 0 1 13.174 14H2.826a2 2 0 0 1-1.991-1.819l-.637-7a2 2 0 0 1 .342-1.31zM2.19 4a1 1 0 0 0-.996 1.09l.637 7a1 1 0 0 0 .995.91h10.348a1 1 0 0 0 .995-.91l.637-7A1 1 0 0 0 13.81 4zm4.69-1.707A1 1 0 0 0 6.172 2H2.5a1 1 0 0 0-1 .981l.006.139q.323-.119.684-.12h5.396z" /> | |||
| </svg> | |||
| </span> | |||
| </button> | |||
| } | |||
| </div> | |||
| @if (IsCollapsed) | |||
| { | |||
| <div class="sidebar-footer sidebar-footer-collapsed"> | |||
| <button class="footer-button" aria-label="Aide"> | |||
| <span class="icon">❓</span> | |||
| </button> | |||
| <button class="footer-button" @onclick='() => NavigateTo("parametres_mail")' aria-label="Paramètres"> | |||
| <span class="icon">⚙️</span> | |||
| </button> | |||
| </div> | |||
| } | |||
| else | |||
| { | |||
| <div class="sidebar-footer"> | |||
| <button class="footer-button" aria-label="Aide"> | |||
| <span class="icon">❓</span> | |||
| <span>Aide</span> | |||
| </button> | |||
| <button class="footer-button" @onclick='() => NavigateTo("parametres_mail")' aria-label="Paramètres"> | |||
| <span class="icon">⚙️</span> | |||
| <span>Paramètres</span> | |||
| </button> | |||
| </div> | |||
| } | |||
| </div> | |||
| <!-- Bootstrap JS --> | |||
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> | |||
| @code { | |||
| private bool collapseNavMenu = false; | |||
| private bool IsCollapsed = false; | |||
| private string CurrentConversationId = ""; | |||
| private List<ConversationDto> ChatConversations { get; set; } = new(); | |||
| private List<ConversationDto> RagConversations { get; set; } = new(); | |||
| private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; | |||
| private bool IsLoadingChat = false; | |||
| private bool IsLoadingRag = false; | |||
| private void ToggleNavMenu() | |||
| protected override async Task OnInitializedAsync() | |||
| { | |||
| collapseNavMenu = !collapseNavMenu; | |||
| await LoadChatConversations(); | |||
| await LoadRagConversations(); | |||
| } | |||
| private AuthenticationState? authState; | |||
| private System.Security.Claims.ClaimsPrincipal? user; | |||
| private void ToggleSidebar() | |||
| { | |||
| IsCollapsed = !IsCollapsed; | |||
| } | |||
| protected override async Task OnInitializedAsync() | |||
| private async Task LoadChatConversations() | |||
| { | |||
| if (string.IsNullOrEmpty(AuthService.ID)) | |||
| { | |||
| return; | |||
| } | |||
| IsLoadingChat = true; | |||
| StateHasChanged(); | |||
| try | |||
| { | |||
| var url = $"/api/ChatRoom/conversations/{AuthService.ID}/1"; | |||
| var allConversations = await Http.GetFromJsonAsync<List<ConversationDto>>(url) ?? new(); | |||
| // Filtrer uniquement celles avec TypeConv = "LLM" | |||
| ChatConversations = allConversations | |||
| .Where(c => c.TypeConv == "LLM") | |||
| .OrderByDescending(c => c.Messages.Any() | |||
| ? c.Messages.Max(m => m.CreatedAt) | |||
| : c.Date) | |||
| .ToList(); | |||
| } | |||
| catch (Exception ex) | |||
| { | |||
| ChatConversations = new(); | |||
| } | |||
| finally | |||
| { | |||
| IsLoadingChat = false; | |||
| StateHasChanged(); | |||
| } | |||
| } | |||
| private async Task LoadRagConversations() | |||
| { | |||
| if (string.IsNullOrEmpty(AuthService.ID)) | |||
| { | |||
| return; | |||
| } | |||
| IsLoadingRag = true; | |||
| StateHasChanged(); | |||
| try | |||
| { | |||
| var url = $"/api/ChatRoom/conversations/{AuthService.ID}/2"; | |||
| var allConversations = await Http.GetFromJsonAsync<List<ConversationDto>>(url) ?? new(); | |||
| // Filtrer uniquement celles avec TypeConv = "RAG" | |||
| RagConversations = allConversations | |||
| .Where(c => c.TypeConv == "RAG") | |||
| .OrderByDescending(c => c.Messages.Any() | |||
| ? c.Messages.Max(m => m.CreatedAt) | |||
| : c.Date) | |||
| .ToList(); | |||
| } | |||
| catch (Exception ex) | |||
| { | |||
| RagConversations = new(); | |||
| } | |||
| finally | |||
| { | |||
| IsLoadingRag = false; | |||
| StateHasChanged(); | |||
| } | |||
| } | |||
| private void OnNewChat() | |||
| { | |||
| Navigation.NavigateTo(""); | |||
| } | |||
| private void OnNewRagChat() | |||
| { | |||
| Navigation.NavigateTo("chatroom_nav/2"); | |||
| } | |||
| private void OnSelectConversation(string conversationId, int typeLLM) | |||
| { | |||
| CurrentConversationId = conversationId; | |||
| Navigation.NavigateTo($"chatroom_nav/{typeLLM}?conversationId={conversationId}"); | |||
| } | |||
| private void NavigateTo(string route) | |||
| { | |||
| Navigation.NavigateTo(route); | |||
| } | |||
| public async Task RefreshChatConversations() | |||
| { | |||
| await LoadChatConversations(); | |||
| } | |||
| public async Task RefreshRagConversations() | |||
| { | |||
| authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); | |||
| user = authState.User; | |||
| await LoadRagConversations(); | |||
| } | |||
| } | |||
| @@ -1,130 +0,0 @@ | |||
| /* NavMenu.razor.css */ | |||
| .nav-menu { | |||
| padding: 1rem; | |||
| height: 100%; | |||
| } | |||
| /* Éléments de navigation */ | |||
| .nav-item { | |||
| margin-bottom: 0.5rem; | |||
| } | |||
| .nav-link2 { | |||
| display: flex; | |||
| align-items: center; | |||
| padding: 0.75rem 1rem; | |||
| color: white !important; | |||
| text-decoration: none; | |||
| border-radius: 8px; | |||
| transition: all 0.2s ease; | |||
| font-weight: 500; | |||
| } | |||
| .nav-link2:hover { | |||
| background-color: rgba(255, 255, 255, 0.1); | |||
| color: white !important; | |||
| } | |||
| .nav-link2.active { | |||
| background-color: rgba(255, 255, 255, 0.2); | |||
| color: white !important; | |||
| font-weight: 600; | |||
| } | |||
| .nav-icon { | |||
| margin-right: 0.75rem; | |||
| font-size: 1.1rem; | |||
| } | |||
| /* Sections avec détails */ | |||
| .nav-section { | |||
| margin-bottom: 0.5rem; | |||
| } | |||
| .nav-section details { | |||
| border-radius: 8px; | |||
| } | |||
| .nav-section details[open] { | |||
| background-color: rgba(0, 0, 0, 0.1); | |||
| } | |||
| .nav-section-header { | |||
| display: flex; | |||
| align-items: center; | |||
| padding: 0.75rem 1rem; | |||
| color: white; | |||
| cursor: pointer; | |||
| user-select: none; | |||
| border-radius: 8px; | |||
| transition: all 0.2s ease; | |||
| font-weight: 500; | |||
| } | |||
| .nav-section-header::after { | |||
| content: '▶'; | |||
| position: absolute; | |||
| right: 1rem; | |||
| font-size: 0.7rem; | |||
| transition: transform 0.2s ease; | |||
| opacity: 0.7; | |||
| } | |||
| details[open] .nav-section-header::after { | |||
| transform: rotate(90deg); | |||
| } | |||
| .nav-section-header:hover { | |||
| background-color: rgba(255, 255, 255, 0.1); | |||
| color: white; | |||
| } | |||
| .nav-section-content { | |||
| padding: 0.5rem 0; | |||
| } | |||
| /* Sous-liens - couleur ivoire */ | |||
| .sub-link { | |||
| padding-left: 3rem; | |||
| font-size: 0.9rem; | |||
| color: ivory !important; | |||
| font-weight: 400; | |||
| } | |||
| .sub-link:hover { | |||
| background-color: rgba(255, 255, 255, 0.08); | |||
| color: white !important; | |||
| } | |||
| .sub-link.active { | |||
| background-color: rgba(255, 255, 255, 0.15); | |||
| color: white !important; | |||
| } | |||
| /* Remove default details marker */ | |||
| details summary::-webkit-details-marker { | |||
| display: none; | |||
| } | |||
| details summary::marker { | |||
| display: none; | |||
| } | |||
| /* Animation pour l'ouverture/fermeture */ | |||
| details[open] .nav-section-content { | |||
| animation: slideDown 0.2s ease-out; | |||
| } | |||
| @keyframes slideDown { | |||
| from { | |||
| opacity: 0; | |||
| transform: translateY(-10px); | |||
| } | |||
| to { | |||
| opacity: 1; | |||
| transform: translateY(0); | |||
| } | |||
| } | |||
| @@ -1,213 +1,536 @@ | |||
| .chatroom-container { | |||
| /* ======================================== | |||
| CHATROOM - AI DASHBOARD | |||
| ======================================== */ | |||
| .chatroom-container { | |||
| display: flex; | |||
| flex-direction: column; | |||
| height: 100%; | |||
| height: 100vh; | |||
| background: var(--ai-bg, #eaf8ff); | |||
| } | |||
| /* ======================================== | |||
| HEADER | |||
| ======================================== */ | |||
| .chatroom-header { | |||
| display: flex; | |||
| justify-content: space-between; | |||
| align-items: center; | |||
| padding: 1rem 2rem; | |||
| background: white; | |||
| border-bottom: 1px solid var(--ai-border, #e0e0e0); | |||
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); | |||
| } | |||
| .top-bar { | |||
| .chatroom-header-left { | |||
| display: flex; | |||
| gap: 20px; | |||
| padding: 10px; | |||
| align-items: center; | |||
| gap: 1rem; | |||
| } | |||
| .main-grid { | |||
| display: grid; | |||
| grid-template-columns: 200px 1fr; | |||
| height: calc(100% - 60px); | |||
| .chatroom-title { | |||
| font-size: 1.5rem; | |||
| font-weight: 600; | |||
| color: var(--ai-text-dark, #243b5d); | |||
| margin: 0; | |||
| } | |||
| .left-panel { | |||
| .chatroom-header-right { | |||
| display: flex; | |||
| flex-direction: column; | |||
| padding: 10px; | |||
| align-items: center; | |||
| gap: 1rem; | |||
| } | |||
| .conv-list { | |||
| height: 350px; | |||
| overflow-y: auto; | |||
| border: 1px solid #ccc; | |||
| .domain-selector { | |||
| display: flex; | |||
| align-items: center; | |||
| gap: 0.5rem; | |||
| } | |||
| .conv-item { | |||
| padding: 5px; | |||
| .domain-selector label { | |||
| font-size: 0.9rem; | |||
| color: var(--ai-text-light, #6c757d); | |||
| margin: 0; | |||
| } | |||
| .domain-selector select { | |||
| padding: 0.5rem 2rem 0.5rem 0.75rem; | |||
| border: 1px solid var(--ai-border, #e0e0e0); | |||
| border-radius: 8px; | |||
| font-size: 0.9rem; | |||
| background: white; | |||
| cursor: pointer; | |||
| min-width: 150px; | |||
| } | |||
| .btn-icon { | |||
| width: 40px; | |||
| height: 40px; | |||
| border-radius: 50%; | |||
| border: none; | |||
| background: transparent; | |||
| color: var(--ai-text-dark, #243b5d); | |||
| font-size: 1.1rem; | |||
| cursor: pointer; | |||
| transition: all 0.2s ease; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| } | |||
| .conv-item.selected { | |||
| background-color: #cce5ff; | |||
| .btn-icon:hover { | |||
| background: var(--ai-bg, #eaf8ff); | |||
| } | |||
| .doc-list { | |||
| flex: 1; | |||
| overflow-y: auto; | |||
| border: 1px solid #ccc; | |||
| margin-top: 5px; | |||
| .btn-back:hover { | |||
| background: var(--ai-primary, #243b5d); | |||
| color: white; | |||
| } | |||
| .chat-panel { | |||
| display: flex; | |||
| flex-direction: column; | |||
| padding: 10px; | |||
| } | |||
| /* ======================================== | |||
| MESSAGES AREA | |||
| ======================================== */ | |||
| .chat-history { | |||
| .chatroom-messages { | |||
| flex: 1; | |||
| overflow-y: auto; | |||
| padding: 2rem; | |||
| display: flex; | |||
| flex-direction: column; | |||
| gap: 1.5rem; | |||
| } | |||
| .chat-row { | |||
| .chatroom-empty { | |||
| display: flex; | |||
| padding: 5px; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| justify-content: center; | |||
| height: 100%; | |||
| color: var(--ai-text-light, #6c757d); | |||
| text-align: center; | |||
| } | |||
| .chat-row.user { | |||
| justify-content: flex-end; | |||
| } | |||
| .chat-row.assistant { | |||
| justify-content: flex-start; | |||
| } | |||
| .chat-bubble { | |||
| max-width: 700px; | |||
| padding: 10px; | |||
| border-radius: 10px; | |||
| margin: 5px; | |||
| white-space: pre-wrap; | |||
| .empty-icon { | |||
| font-size: 4rem; | |||
| color: var(--ai-secondary, #2984a1); | |||
| margin-bottom: 1rem; | |||
| opacity: 0.5; | |||
| } | |||
| .chat-bubble.user { | |||
| background: #0084ff; | |||
| color: white; | |||
| } | |||
| .chat-bubble.assistant { | |||
| background: #e5e5e5; | |||
| color: black; | |||
| } | |||
| .msg-input { | |||
| width: 100%; | |||
| height: 70px; | |||
| .chatroom-empty h3 { | |||
| font-size: 1.5rem; | |||
| color: var(--ai-text-dark, #243b5d); | |||
| margin-bottom: 0.5rem; | |||
| } | |||
| .toast { | |||
| position: fixed; | |||
| bottom: 20px; | |||
| right: 20px; | |||
| background: #323232; | |||
| color: white; | |||
| padding: 16px; | |||
| border-radius: 8px; | |||
| box-shadow: 0 4px 12px rgba(0,0,0,.4); | |||
| .chatroom-empty p { | |||
| font-size: 1rem; | |||
| margin: 0; | |||
| } | |||
| .messages { | |||
| flex: 1; | |||
| overflow-y: auto; | |||
| padding: 20px; | |||
| background: #f5f7fb; | |||
| } | |||
| /* Ligne message */ | |||
| /* Messages */ | |||
| .message-row { | |||
| display: flex; | |||
| align-items: flex-start; | |||
| margin-bottom: 18px; | |||
| gap: 10px; | |||
| gap: 0.75rem; | |||
| animation: fadeIn 0.3s ease; | |||
| } | |||
| /* Alignement User / Assistant */ | |||
| .message-row.user { | |||
| justify-content: flex-end; | |||
| @keyframes fadeIn { | |||
| from { | |||
| opacity: 0; | |||
| transform: translateY(10px); | |||
| } | |||
| .message-row.assistant { | |||
| justify-content: flex-start; | |||
| to { | |||
| opacity: 1; | |||
| transform: translateY(0); | |||
| } | |||
| } | |||
| .message-row.user { | |||
| flex-direction: row-reverse; | |||
| justify-content: flex-start; | |||
| } | |||
| .message-row.assistant { | |||
| flex-direction: row; | |||
| justify-content: flex-start; | |||
| } | |||
| /* Avatars */ | |||
| .avatar { | |||
| width: 38px; | |||
| height: 38px; | |||
| font-size: 20px; | |||
| width: 40px; | |||
| height: 40px; | |||
| border-radius: 50%; | |||
| display: flex; | |||
| justify-content: center; | |||
| align-items: center; | |||
| justify-content: center; | |||
| font-size: 1.2rem; | |||
| flex-shrink: 0; | |||
| } | |||
| .avatar-user { | |||
| background-color: #007bff; | |||
| background: linear-gradient(135deg, var(--ai-secondary, #2984a1) 0%, var(--ai-primary, #243b5d) 100%); | |||
| color: white; | |||
| } | |||
| .avatar-assistant { | |||
| background-color: #6c757d; | |||
| background: linear-gradient(135deg, var(--ai-accent, #f63e63) 0%, #e02851 100%); | |||
| color: white; | |||
| } | |||
| /* Bulles de messages */ | |||
| /* Message content */ | |||
| .message-content-wrapper { | |||
| display: flex; | |||
| flex-direction: column; | |||
| max-width: 70%; | |||
| gap: 0.5rem; | |||
| } | |||
| .message-row.user .message-content-wrapper { | |||
| align-items: flex-end; | |||
| } | |||
| .message-row.assistant .message-content-wrapper { | |||
| align-items: flex-start; | |||
| } | |||
| .bubble { | |||
| max-width: 60%; | |||
| padding: 12px 18px; | |||
| border-radius: 18px; | |||
| padding: 1rem 1.25rem; | |||
| border-radius: 16px; | |||
| font-size: 1rem; | |||
| line-height: 1.6; | |||
| word-wrap: break-word; | |||
| white-space: pre-wrap; | |||
| box-shadow: 0 3px 8px rgba(0,0,0,0.15); | |||
| font-size: 15px; | |||
| } | |||
| .bubble-user { | |||
| background-color: #007bff; | |||
| background: linear-gradient(135deg, var(--ai-secondary, #2984a1) 0%, var(--ai-primary, #243b5d) 100%); | |||
| color: white; | |||
| border-bottom-right-radius: 4px; | |||
| } | |||
| .bubble-assistant { | |||
| background-color: white; | |||
| color: #333; | |||
| background: white; | |||
| color: var(--ai-text-dark, #243b5d); | |||
| box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); | |||
| border-bottom-left-radius: 4px; | |||
| } | |||
| /* Zone de saisie */ | |||
| .chat-input { | |||
| padding: 15px; | |||
| border-top: 1px solid #ddd; | |||
| /* Message actions */ | |||
| .message-actions { | |||
| display: flex; | |||
| gap: 0.5rem; | |||
| } | |||
| .btn-message-action { | |||
| width: 32px; | |||
| height: 32px; | |||
| border-radius: 6px; | |||
| border: none; | |||
| background: transparent; | |||
| color: var(--ai-text-light, #6c757d); | |||
| cursor: pointer; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| font-size: 0.9rem; | |||
| transition: all 0.2s ease; | |||
| } | |||
| .btn-message-action:hover { | |||
| background: var(--ai-bg, #eaf8ff); | |||
| color: var(--ai-primary, #243b5d); | |||
| } | |||
| /* Typing indicator */ | |||
| .typing-indicator { | |||
| display: flex; | |||
| gap: 0.4rem; | |||
| padding: 0.5rem 0; | |||
| } | |||
| .typing-indicator span { | |||
| width: 8px; | |||
| height: 8px; | |||
| border-radius: 50%; | |||
| background-color: var(--ai-secondary, #2984a1); | |||
| animation: typing 1.4s infinite; | |||
| } | |||
| .typing-indicator span:nth-child(2) { | |||
| animation-delay: 0.2s; | |||
| } | |||
| .typing-indicator span:nth-child(3) { | |||
| animation-delay: 0.4s; | |||
| } | |||
| @keyframes typing { | |||
| 0%, 60%, 100% { | |||
| transform: translateY(0); | |||
| opacity: 0.7; | |||
| } | |||
| 30% { | |||
| transform: translateY(-10px); | |||
| opacity: 1; | |||
| } | |||
| } | |||
| /* ======================================== | |||
| UPLOADED DOCUMENTS PREVIEW | |||
| ======================================== */ | |||
| .uploaded-docs-preview { | |||
| display: flex; | |||
| gap: 0.75rem; | |||
| padding: 0.75rem 2rem; | |||
| background: white; | |||
| border-top: 1px solid var(--ai-border, #e0e0e0); | |||
| overflow-x: auto; | |||
| } | |||
| textarea { | |||
| .doc-preview-item { | |||
| display: flex; | |||
| align-items: center; | |||
| gap: 0.5rem; | |||
| padding: 0.5rem 0.75rem; | |||
| background: var(--ai-bg, #eaf8ff); | |||
| border-radius: 8px; | |||
| font-size: 0.9rem; | |||
| white-space: nowrap; | |||
| } | |||
| .doc-preview-item i { | |||
| color: var(--ai-secondary, #2984a1); | |||
| font-size: 1rem; | |||
| } | |||
| .btn-remove-doc { | |||
| width: 20px; | |||
| height: 20px; | |||
| border-radius: 50%; | |||
| border: none; | |||
| background: rgba(0, 0, 0, 0.1); | |||
| color: var(--ai-text-dark, #243b5d); | |||
| cursor: pointer; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| font-size: 0.9rem; | |||
| transition: all 0.2s ease; | |||
| padding: 0; | |||
| } | |||
| .btn-remove-doc:hover { | |||
| background: var(--ai-accent, #f63e63); | |||
| color: white; | |||
| } | |||
| /* ======================================== | |||
| INPUT AREA | |||
| ======================================== */ | |||
| .chatroom-input-container { | |||
| padding: 1.5rem 2rem; | |||
| background: white; | |||
| border-top: 1px solid var(--ai-border, #e0e0e0); | |||
| } | |||
| .chatroom-input-wrapper { | |||
| max-width: 1200px; | |||
| margin: 0 auto; | |||
| background: var(--ai-bg, #eaf8ff); | |||
| border-radius: 16px; | |||
| padding: 1rem 1.25rem; | |||
| } | |||
| .chatroom-input { | |||
| width: 100%; | |||
| height: 80px; | |||
| border-radius: 12px; | |||
| padding: 12px; | |||
| border: 1px solid #ccc; | |||
| resize: none; | |||
| border: none; | |||
| outline: none; | |||
| font-size: 1rem; | |||
| padding: 0.5rem 0; | |||
| background: transparent; | |||
| color: var(--ai-text-dark, #243b5d); | |||
| font-family: 'Montserrat', sans-serif; | |||
| margin-bottom: 0.75rem; | |||
| resize: none; | |||
| min-height: 24px; | |||
| max-height: 150px; | |||
| } | |||
| button { | |||
| margin-top: 10px; | |||
| } | |||
| .document-upload { | |||
| margin-top: 10px; | |||
| .chatroom-input::placeholder { | |||
| color: #a0a0a0; | |||
| } | |||
| .chatroom-input:disabled { | |||
| opacity: 0.6; | |||
| cursor: not-allowed; | |||
| } | |||
| .chatroom-input-actions { | |||
| display: flex; | |||
| justify-content: space-between; | |||
| align-items: center; | |||
| gap: 1rem; | |||
| } | |||
| .doc-list { | |||
| margin-top: 10px; | |||
| padding: 10px; | |||
| background: #f1f1f1; | |||
| .btn-chat-action { | |||
| display: flex; | |||
| align-items: center; | |||
| gap: 0.5rem; | |||
| padding: 0.5rem 0.75rem; | |||
| border-radius: 8px; | |||
| border: none; | |||
| background: transparent; | |||
| color: var(--ai-text-light, #6c757d); | |||
| cursor: pointer; | |||
| font-size: 0.9rem; | |||
| transition: all 0.2s ease; | |||
| font-family: 'Montserrat', sans-serif; | |||
| } | |||
| .doc-item { | |||
| .btn-chat-action:hover:not(:disabled) { | |||
| background: white; | |||
| color: var(--ai-primary, #243b5d); | |||
| } | |||
| .btn-chat-action:disabled { | |||
| opacity: 0.5; | |||
| cursor: not-allowed; | |||
| } | |||
| .btn-chat-label { | |||
| display: none; | |||
| } | |||
| @media (min-width: 768px) { | |||
| .btn-chat-label { | |||
| display: inline; | |||
| } | |||
| } | |||
| .btn-chat-submit { | |||
| width: 40px; | |||
| height: 40px; | |||
| border-radius: 50%; | |||
| border: none; | |||
| background: var(--ai-accent, #f63e63); | |||
| color: white; | |||
| cursor: pointer; | |||
| display: flex; | |||
| justify-content: space-between; | |||
| padding: 4px 0; | |||
| align-items: center; | |||
| justify-content: center; | |||
| font-size: 1.2rem; | |||
| transition: all 0.3s ease; | |||
| flex-shrink: 0; | |||
| } | |||
| .btn-chat-submit:hover:not(:disabled) { | |||
| background: #e02851; | |||
| transform: scale(1.05); | |||
| box-shadow: 0 4px 12px rgba(246, 62, 99, 0.3); | |||
| } | |||
| .btn-chat-submit:disabled { | |||
| opacity: 0.5; | |||
| cursor: not-allowed; | |||
| transform: none; | |||
| } | |||
| /* ======================================== | |||
| SCROLLBAR | |||
| ======================================== */ | |||
| .chatroom-messages::-webkit-scrollbar { | |||
| width: 8px; | |||
| } | |||
| .chatroom-messages::-webkit-scrollbar-track { | |||
| background: transparent; | |||
| } | |||
| .chatroom-messages::-webkit-scrollbar-thumb { | |||
| background: var(--ai-secondary, #2984a1); | |||
| border-radius: 4px; | |||
| } | |||
| .chatroom-messages::-webkit-scrollbar-thumb:hover { | |||
| background: var(--ai-primary, #243b5d); | |||
| } | |||
| .uploaded-docs-preview::-webkit-scrollbar { | |||
| height: 6px; | |||
| } | |||
| .uploaded-docs-preview::-webkit-scrollbar-track { | |||
| background: transparent; | |||
| } | |||
| .uploaded-docs-preview::-webkit-scrollbar-thumb { | |||
| background: rgba(0, 0, 0, 0.2); | |||
| border-radius: 3px; | |||
| } | |||
| .doc-item button { | |||
| margin-left: 10px; | |||
| /* ======================================== | |||
| RESPONSIVE | |||
| ======================================== */ | |||
| @media (max-width: 768px) { | |||
| .chatroom-header { | |||
| padding: 1rem; | |||
| } | |||
| .chatroom-title { | |||
| font-size: 1.25rem; | |||
| } | |||
| .chatroom-messages { | |||
| padding: 1rem; | |||
| } | |||
| .message-content-wrapper { | |||
| max-width: 85%; | |||
| } | |||
| .chatroom-input-container { | |||
| padding: 1rem; | |||
| } | |||
| .chatroom-input-wrapper { | |||
| padding: 0.75rem 1rem; | |||
| } | |||
| .domain-selector { | |||
| flex-direction: column; | |||
| align-items: flex-start; | |||
| gap: 0.25rem; | |||
| } | |||
| } | |||
| @media (max-width: 480px) { | |||
| .bubble { | |||
| padding: 0.875rem 1rem; | |||
| font-size: 0.95rem; | |||
| } | |||
| .avatar { | |||
| width: 36px; | |||
| height: 36px; | |||
| font-size: 1.1rem; | |||
| } | |||
| .chatroom-header-right { | |||
| gap: 0.5rem; | |||
| } | |||
| .btn-icon { | |||
| width: 36px; | |||
| height: 36px; | |||
| font-size: 1rem; | |||
| } | |||
| } | |||
| @@ -1,16 +1,187 @@ | |||
| @page "/" | |||
| @using System.Text | |||
| @using ReAct_PME.WebUI.ServicesUI | |||
| <div class="page-container"> | |||
| <!-- En-tête avec dégradé --> | |||
| <div class="home-header"> | |||
| <p class="home-welcome"> | |||
| Bienvenue, <strong>@AuthService.FirstName @AuthService.LastName</strong> | |||
| sur votre application AI-100-SaaS | |||
| </p> | |||
| @using ReAct_PME.Domain | |||
| <div class="home-container"> | |||
| <div class="home-content"> | |||
| <!-- Section bienvenue --> | |||
| <div class="welcome-section"> | |||
| <h1 class="welcome-title">Bonjour !</h1> | |||
| <p class="welcome-subtitle">Qu'est-ce qu'on fait aujourd'hui ?</p> | |||
| </div> | |||
| <!-- Zone de saisie --> | |||
| <div class="input-container"> | |||
| @if (UploadedDocuments.Any()) | |||
| { | |||
| <div class="input-files"> | |||
| @foreach (var doc in UploadedDocuments) | |||
| { | |||
| <div class="file-item"> | |||
| <div class="file-info"> | |||
| <span class="file-name">@doc.FileName</span> | |||
| </div> | |||
| <button class="remove-file-button" @onclick="() => RemoveDocument(doc)" aria-label="Supprimer le fichier"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16"> | |||
| <path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z" /> | |||
| </svg> | |||
| </button> | |||
| </div> | |||
| } | |||
| </div> | |||
| } | |||
| <div class="input-wrapper @(UploadedDocuments.Any() ? "has-files" : "")"> | |||
| <textarea @bind="message" | |||
| @bind:event="oninput" | |||
| placeholder="Nouvelle conversation..." | |||
| rows="1" | |||
| disabled="@isDisabled"></textarea> | |||
| <div class="input-actions"> | |||
| <button class="attach-button" @onclick="OpenFileDialog" aria-label="Importer un fichier"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> | |||
| <path d="M4.5 3a2.5 2.5 0 0 1 5 0v9a1.5 1.5 0 0 1-3 0V5a.5.5 0 0 1 1 0v7a.5.5 0 0 0 1 0V3a1.5 1.5 0 1 0-3 0v9a2.5 2.5 0 0 0 5 0V5a.5.5 0 0 1 1 0v7a3.5 3.5 0 1 1-7 0z" /> | |||
| </svg> | |||
| <span>Importer un fichier</span> | |||
| </button> | |||
| <div class="input-right-actions"> | |||
| <button class="voice-button" @onclick="RecordVoice" aria-label="Message vocal"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> | |||
| <path fill-rule="evenodd" d="M8.5 2a.5.5 0 0 1 .5.5v11a.5.5 0 0 1-1 0v-11a.5.5 0 0 1 .5-.5m-2 2a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5m4 0a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5m-6 1.5A.5.5 0 0 1 5 6v4a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m8 0a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m-10 1A.5.5 0 0 1 3 7v2a.5.5 0 0 1-1 0V7a.5.5 0 0 1 .5-.5m12 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0V7a.5.5 0 0 1 .5-.5" /> | |||
| </svg> | |||
| </button> | |||
| <button class="send-button" | |||
| @onclick="SendMessage" | |||
| disabled="@((string.IsNullOrWhiteSpace(message) && !UploadedDocuments.Any()) || isDisabled)" | |||
| aria-label="Envoyer le message"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> | |||
| <path fill-rule="evenodd" d="M8 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L7.5 2.707V14.5a.5.5 0 0 0 .5.5" /> | |||
| </svg> | |||
| </button> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <InputFile id="fileInput" OnChange="HandleFileSelection" multiple style="display: none;" /> | |||
| </div> | |||
| <!-- Cartes des agents --> | |||
| <div class="agents-grid"> | |||
| <div class="agent-card" @onclick="() => SelectAgent(1)"> | |||
| <div class="agent-icon"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" fill="currentColor" viewBox="0 0 16 16"> | |||
| <path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325" /> | |||
| </svg> | |||
| </div> | |||
| <div class="agent-content"> | |||
| <h3 class="agent-name">Par défaut</h3> | |||
| <p class="agent-description"> | |||
| Discutez avec un agent IA ayant une base de données importante dans votre domaine | |||
| </p> | |||
| </div> | |||
| </div> | |||
| <div class="agent-card" @onclick="() => SelectAgent(2)"> | |||
| <div class="agent-icon"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" fill="currentColor" viewBox="0 0 16 16"> | |||
| <path fill-rule="evenodd" d="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5M3.854 2.146a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 1 1 .708-.708L2 3.293l1.146-1.147a.5.5 0 0 1 .708 0m0 4a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 1 1 .708-.708L2 7.293l1.146-1.147a.5.5 0 0 1 .708 0m0 4a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 0 1 .708-.708l.146.147 1.146-1.147a.5.5 0 0 1 .708 0" /> | |||
| </svg> | |||
| </div> | |||
| <div class="agent-content"> | |||
| <h3 class="agent-name">Agent Audit</h3> | |||
| <p class="agent-description"> | |||
| Un agent IA entraîné dans la création de bilan comptable sur la base de vos comptes-rendus | |||
| </p> | |||
| </div> | |||
| </div> | |||
| <div class="agent-card" @onclick="() => SelectAgent(3)"> | |||
| <div class="agent-icon"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" fill="currentColor" viewBox="0 0 16 16"> | |||
| <path fill-rule="evenodd" d="M10.854 6.146a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7.5 8.793l2.646-2.647a.5.5 0 0 1 .708 0" /> | |||
| <path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2" /> | |||
| <path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1z" /> | |||
| </svg> | |||
| </div> | |||
| <div class="agent-content"> | |||
| <h3 class="agent-name">L'agent Audit</h3> | |||
| <p class="agent-description"> | |||
| Un agent IA spécialisé dans l'étude de vos documents et dans la réalisation d'audit financier | |||
| </p> | |||
| </div> | |||
| </div> | |||
| <div class="agent-card" @onclick="() => SelectAgent(4)"> | |||
| <div class="agent-icon"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" fill="currentColor" viewBox="0 0 16 16"> | |||
| <path d="M.05 3.555A2 2 0 0 1 2 2h12a2 2 0 0 1 1.95 1.555L8 8.414zM0 4.697v7.104l5.803-3.558zM6.761 8.83l-6.57 4.027A2 2 0 0 0 2 14h12a2 2 0 0 0 1.808-1.144l-6.57-4.027L8 9.586zm3.436-.586L16 11.801V4.697z" /> | |||
| </svg> | |||
| </div> | |||
| <div class="agent-content"> | |||
| <h3 class="agent-name">L'agent mail spécialisé</h3> | |||
| <p class="agent-description"> | |||
| Un agent IA spécialisé dans la rédaction de mail professionnel avec une approche humaine et experte | |||
| </p> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @code { | |||
| private string message = ""; | |||
| private bool isDisabled = false; | |||
| private List<UploadedDoc> UploadedDocuments = new(); | |||
| private void OpenFileDialog() | |||
| { | |||
| // JavaScript interop pour ouvrir le sélecteur de fichiers | |||
| // await JSRuntime.InvokeVoidAsync("document.getElementById('fileInput').click()"); | |||
| ToastService.ShowInfo("Sélection de fichiers"); | |||
| } | |||
| private async Task HandleFileSelection(InputFileChangeEventArgs e) | |||
| { | |||
| foreach (var file in e.GetMultipleFiles()) | |||
| { | |||
| using var stream = file.OpenReadStream(maxAllowedSize: 20 * 1024 * 1024); | |||
| using var ms = new MemoryStream(); | |||
| await stream.CopyToAsync(ms); | |||
| UploadedDocuments.Add(new UploadedDoc | |||
| { | |||
| FileName = file.Name, | |||
| Bytes = ms.ToArray() | |||
| }); | |||
| } | |||
| StateHasChanged(); | |||
| } | |||
| private void RemoveDocument(UploadedDoc doc) | |||
| { | |||
| UploadedDocuments.Remove(doc); | |||
| StateHasChanged(); | |||
| } | |||
| private void SendMessage() | |||
| { | |||
| if (!string.IsNullOrWhiteSpace(message) || UploadedDocuments.Any()) | |||
| { | |||
| ToastService.ShowInfo("Création d'une conversation"); | |||
| // Navigation.NavigateTo($"/chatroom?message={Uri.EscapeDataString(message)}"); | |||
| } | |||
| } | |||
| private void SelectAgent(int agentId) | |||
| { | |||
| ToastService.ShowInfo($"Agent {agentId} sélectionné"); | |||
| Navigation.NavigateTo($"/chatroom_nav/{agentId}"); | |||
| } | |||
| private void RecordVoice() | |||
| { | |||
| ToastService.ShowInfo("Fonctionnalité d'enregistrement vocal en cours de développement"); | |||
| } | |||
| } | |||