- Add professional loading spinner with "Se încarcă răspunsul..." text - Implement full dark mode support for loading overlay and API response containers - Add automatic theme detection for Flowise chatbot initialization - Add inline script to set theme before page render for instant visibility - Simplify theme toggle to reload page and reinitialize chatbot with new theme - Prevent textarea search when page is called with GET parameter - Fix theme toggle visibility in dark mode 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1262 lines
51 KiB
HTML
1262 lines
51 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ro">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Maria ChatBot - Romfast Suport</title>
|
||
<meta name="description" content="Maria ChatBot - Specialist suport tehnic Romfast pentru ROA. Răspunsuri expert la întrebări despre sistem și link-uri partajabile.">
|
||
|
||
<!-- Tailwind CSS -->
|
||
<script src="https://cdn.tailwindcss.com"></script>
|
||
<!-- Flowbite -->
|
||
<script src="https://cdn.jsdelivr.net/npm/flowbite@2.0.0/dist/flowbite.min.js"></script>
|
||
<!-- Lucide Icons -->
|
||
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
|
||
<!-- Google Fonts -->
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Merriweather:wght@300;400;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||
<!-- Professional Theme CSS -->
|
||
<link href="professional-theme.css" rel="stylesheet">
|
||
|
||
<style>
|
||
/* Enhanced professional styling for Maria's advanced features */
|
||
body {
|
||
font-family: var(--font-sans) !important;
|
||
background: var(--background) !important;
|
||
color: var(--foreground) !important;
|
||
letter-spacing: var(--tracking-normal) !important;
|
||
line-height: 1.6 !important;
|
||
}
|
||
|
||
/* Professional styling for link generation button */
|
||
.link-button-small {
|
||
background: transparent !important;
|
||
border: none !important;
|
||
padding: 0 !important;
|
||
margin: 0 0 0 8px !important;
|
||
height: 56px !important;
|
||
width: 56px !important;
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
justify-content: center !important;
|
||
cursor: pointer !important;
|
||
transition: all 0.2s ease !important;
|
||
border-radius: var(--radius) !important;
|
||
font-size: 18px !important;
|
||
color: var(--primary) !important;
|
||
opacity: 0.8 !important;
|
||
flex-shrink: 0 !important;
|
||
}
|
||
|
||
.link-button-small:hover {
|
||
background-color: var(--card-hover) !important;
|
||
opacity: 1 !important;
|
||
transform: scale(1.05) !important;
|
||
color: var(--secondary) !important;
|
||
}
|
||
|
||
.link-button-small:active {
|
||
transform: scale(0.95) !important;
|
||
}
|
||
|
||
.link-button-small.success {
|
||
color: var(--accent) !important;
|
||
background-color: rgba(184, 85, 85, 0.1) !important;
|
||
}
|
||
|
||
/* Professional toast notifications */
|
||
.toast {
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
background: var(--primary) !important;
|
||
color: var(--primary-foreground) !important;
|
||
padding: 12px 20px;
|
||
border-radius: var(--radius-lg) !important;
|
||
z-index: 10000;
|
||
opacity: 0;
|
||
transform: translateX(100%);
|
||
transition: all 0.3s ease;
|
||
box-shadow: var(--shadow-lg) !important;
|
||
font-size: 14px;
|
||
font-family: var(--font-sans) !important;
|
||
}
|
||
|
||
.toast.show {
|
||
opacity: 1;
|
||
transform: translateX(0);
|
||
}
|
||
|
||
.toast.error {
|
||
background: var(--accent) !important;
|
||
color: var(--accent-foreground) !important;
|
||
}
|
||
|
||
/* Professional API message container */
|
||
.api-message-container {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: rgba(250, 251, 252, 0.95);
|
||
backdrop-filter: blur(8px);
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 9999;
|
||
padding: 20px;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.api-message-box {
|
||
background: var(--card) !important;
|
||
border-radius: var(--radius-xl) !important;
|
||
box-shadow: var(--shadow-2xl) !important;
|
||
border: 1px solid var(--border) !important;
|
||
max-width: 600px;
|
||
width: 90%;
|
||
max-height: 90vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.api-message-header {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 20px 20px 10px 20px;
|
||
border-bottom: 1px solid var(--border) !important;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.api-message-avatar {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
margin-right: 15px;
|
||
background: var(--primary) !important;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--primary-foreground) !important;
|
||
font-weight: bold;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.api-message-title {
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
color: var(--foreground) !important;
|
||
font-family: var(--font-sans) !important;
|
||
}
|
||
|
||
.api-message-scrollable {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 0 20px;
|
||
}
|
||
|
||
.api-message-content {
|
||
font-size: 16px;
|
||
line-height: 1.6;
|
||
color: var(--foreground) !important;
|
||
white-space: pre-wrap;
|
||
word-wrap: break-word;
|
||
padding: 15px 0;
|
||
font-family: var(--font-sans) !important;
|
||
}
|
||
|
||
.api-message-footer {
|
||
padding: 20px;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
border-top: 1px solid var(--border) !important;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.api-message-button {
|
||
background: var(--button-gradient) !important;
|
||
color: var(--primary-foreground) !important;
|
||
border: none;
|
||
border-radius: var(--radius-lg) !important;
|
||
padding: 12px 24px;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: opacity 0.2s;
|
||
font-family: var(--font-sans) !important;
|
||
}
|
||
|
||
.api-message-button:hover {
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.user-query {
|
||
background: var(--muted) !important;
|
||
color: var(--muted-foreground) !important;
|
||
padding: 10px 15px;
|
||
border-radius: var(--radius-lg) !important;
|
||
margin-bottom: 15px;
|
||
display: inline-block;
|
||
max-width: 100%;
|
||
font-size: 15px;
|
||
word-wrap: break-word;
|
||
font-family: var(--font-sans) !important;
|
||
}
|
||
|
||
.api-message-scrollable::-webkit-scrollbar {
|
||
width: 8px;
|
||
}
|
||
|
||
.api-message-scrollable::-webkit-scrollbar-track {
|
||
background: #f1f1f1;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.api-message-scrollable::-webkit-scrollbar-thumb {
|
||
background: #c1c1c1;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.api-message-scrollable::-webkit-scrollbar-thumb:hover {
|
||
background: #a8a8a8;
|
||
}
|
||
|
||
/* Professional loading overlay */
|
||
.loading-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: rgba(255, 255, 255, 0.98);
|
||
backdrop-filter: blur(12px);
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 99999;
|
||
opacity: 0;
|
||
transition: opacity 0.3s ease;
|
||
}
|
||
|
||
.loading-overlay.show {
|
||
opacity: 1;
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 56px;
|
||
height: 56px;
|
||
border: 5px solid rgba(59, 129, 246, 0.2);
|
||
border-top-color: #3B81F6;
|
||
border-radius: 50%;
|
||
animation: spin 1s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes spin {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
|
||
.loading-text {
|
||
margin-top: 24px;
|
||
font-size: 20px;
|
||
color: #000000 !important;
|
||
font-family: var(--font-sans) !important;
|
||
font-weight: 700;
|
||
text-shadow: none;
|
||
letter-spacing: 0.5px;
|
||
opacity: 1 !important;
|
||
}
|
||
|
||
/* Dark mode support for loading overlay */
|
||
.dark-mode .loading-overlay,
|
||
body.dark-mode .loading-overlay {
|
||
background-color: rgba(34, 40, 49, 0.98) !important;
|
||
}
|
||
|
||
.dark-mode .loading-spinner,
|
||
body.dark-mode .loading-spinner {
|
||
border-color: rgba(59, 129, 246, 0.3) !important;
|
||
border-top-color: #5B9BFF !important;
|
||
}
|
||
|
||
.dark-mode .loading-text,
|
||
body.dark-mode .loading-text {
|
||
color: #ffffff !important;
|
||
}
|
||
|
||
/* Dark mode support for API message container */
|
||
.dark-mode .api-message-container,
|
||
body.dark-mode .api-message-container {
|
||
background-color: rgba(34, 40, 49, 0.95) !important;
|
||
}
|
||
|
||
.dark-mode .api-message-box,
|
||
body.dark-mode .api-message-box {
|
||
background: #2a2a2a !important;
|
||
border-color: #3a3a3a !important;
|
||
}
|
||
|
||
.dark-mode .api-message-header,
|
||
body.dark-mode .api-message-header {
|
||
border-bottom-color: #3a3a3a !important;
|
||
}
|
||
|
||
.dark-mode .api-message-title,
|
||
body.dark-mode .api-message-title {
|
||
color: #ffffff !important;
|
||
}
|
||
|
||
.dark-mode .api-message-content,
|
||
body.dark-mode .api-message-content {
|
||
color: #e0e0e0 !important;
|
||
}
|
||
|
||
.dark-mode .api-message-footer,
|
||
body.dark-mode .api-message-footer {
|
||
border-top-color: #3a3a3a !important;
|
||
}
|
||
|
||
.dark-mode .user-query,
|
||
body.dark-mode .user-query {
|
||
background: #3a3a3a !important;
|
||
color: #e0e0e0 !important;
|
||
}
|
||
|
||
.dark-mode .api-message-scrollable::-webkit-scrollbar-track,
|
||
body.dark-mode .api-message-scrollable::-webkit-scrollbar-track {
|
||
background: #2a2a2a !important;
|
||
}
|
||
|
||
.dark-mode .api-message-scrollable::-webkit-scrollbar-thumb,
|
||
body.dark-mode .api-message-scrollable::-webkit-scrollbar-thumb {
|
||
background: #555555 !important;
|
||
}
|
||
|
||
.dark-mode .api-message-scrollable::-webkit-scrollbar-thumb:hover,
|
||
body.dark-mode .api-message-scrollbar-thumb:hover {
|
||
background: #666666 !important;
|
||
}
|
||
|
||
/* Dark mode support for header theme toggle button */
|
||
.dark-mode #theme-toggle,
|
||
body.dark-mode #theme-toggle {
|
||
color: #ffffff !important;
|
||
opacity: 1 !important;
|
||
}
|
||
|
||
.dark-mode #theme-toggle:hover,
|
||
body.dark-mode #theme-toggle:hover {
|
||
background-color: rgba(255, 255, 255, 0.2) !important;
|
||
}
|
||
</style>
|
||
</style>
|
||
|
||
<!-- Set theme BEFORE page renders to prevent flash and ensure toggle visibility -->
|
||
<script>
|
||
(function() {
|
||
const theme = localStorage.getItem('theme') || 'light';
|
||
if (theme === 'dark') {
|
||
document.documentElement.classList.add('dark-mode');
|
||
}
|
||
})();
|
||
</script>
|
||
</head>
|
||
<body class="min-h-screen">
|
||
<!-- Soft Professional Blue Header -->
|
||
<header class="professional-navbar sticky top-0 z-50">
|
||
<nav class="container mx-auto px-4 py-4">
|
||
<div class="flex items-center justify-between">
|
||
<!-- Logo Section -->
|
||
<div class="flex items-center space-x-3">
|
||
<img src="images/romfast_logo.png" alt="Romfast Logo" class="romfast-logo">
|
||
<div class="hidden md:block">
|
||
<p class="text-white text-sm italic font-light">Aduce informația în mâinile tale</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Centered Navigation -->
|
||
<div class="hidden lg:flex items-center space-x-8">
|
||
<a href="index.html" class="text-white hover:text-blue-200 transition-colors font-medium nav-link">Prima pagina</a>
|
||
<a href="menu/desprenoi.html" class="text-white hover:text-blue-200 transition-colors nav-link">Despre noi</a>
|
||
<a href="roa/aplicatii-erp.html" class="text-white hover:text-blue-200 transition-colors nav-link">ROA</a>
|
||
<div class="relative group">
|
||
<button class="text-white hover:text-blue-200 transition-colors flex items-center space-x-1 nav-link">
|
||
<span>Servicii</span>
|
||
<i data-lucide="chevron-down" class="w-4 h-4"></i>
|
||
</button>
|
||
<div class="absolute top-full left-0 mt-2 w-48 bg-white rounded-lg shadow-lg border border-gray-200 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-300">
|
||
<a href="menu/analiza.html" class="block px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-800 rounded-t-lg">Analiza</a>
|
||
<a href="menu/implementare.html" class="block px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-800">Implementare</a>
|
||
<a href="menu/roa-suport-tehnic.html" class="block px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-800">Suport tehnic ROA</a>
|
||
<a href="menu/alteservicii.html" class="block px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-800 rounded-b-lg">Alte servicii</a>
|
||
</div>
|
||
</div>
|
||
<a href="menu/referinte.html" class="text-white hover:text-blue-200 transition-colors nav-link">Referinte</a>
|
||
<a href="menu/angajari.html" class="text-white hover:text-blue-200 transition-colors nav-link">Angajari</a>
|
||
<a href="menu/contact.html" class="text-white hover:text-blue-200 transition-colors nav-link">Contact</a>
|
||
</div>
|
||
|
||
<!-- Theme Toggle & Mobile Menu -->
|
||
<div class="flex items-center space-x-4">
|
||
<button id="theme-toggle" class="text-white p-2 rounded-lg hover:bg-white hover:bg-opacity-20 transition-all duration-300">
|
||
<i data-lucide="sun" class="w-5 h-5"></i>
|
||
</button>
|
||
<button id="mobile-menu-toggle" class="lg:hidden text-white p-2 rounded-lg hover:bg-white hover:bg-opacity-20 transition-all duration-300">
|
||
<i data-lucide="menu" class="w-6 h-6" id="menu-icon"></i>
|
||
<i data-lucide="x" class="w-6 h-6 hidden" id="close-icon"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Mobile Menu -->
|
||
<div id="mobile-menu" class="lg:hidden hidden bg-white border-t border-gray-200 shadow-lg">
|
||
<div class="px-4 py-4 space-y-3">
|
||
<a href="index.html" class="block text-gray-700 hover:text-blue-600 transition-colors font-medium py-2">Prima pagina</a>
|
||
<a href="menu/desprenoi.html" class="block text-gray-700 hover:text-blue-600 transition-colors py-2">Despre noi</a>
|
||
<a href="roa/aplicatii-erp.html" class="block text-gray-700 hover:text-blue-600 transition-colors py-2">ROA</a>
|
||
<div class="border-l-2 border-gray-300 pl-4 space-y-2">
|
||
<p class="text-gray-600 font-medium text-sm">Servicii</p>
|
||
<a href="menu/analiza.html" class="block text-gray-600 hover:text-blue-600 transition-colors py-1 text-sm">Analiza</a>
|
||
<a href="menu/implementare.html" class="block text-gray-600 hover:text-blue-600 transition-colors py-1 text-sm">Implementare</a>
|
||
<a href="menu/roa-suport-tehnic.html" class="block text-gray-600 hover:text-blue-600 transition-colors py-1 text-sm">Suport tehnic ROA</a>
|
||
<a href="menu/alteservicii.html" class="block text-gray-600 hover:text-blue-600 transition-colors py-1 text-sm">Alte servicii</a>
|
||
</div>
|
||
<a href="menu/referinte.html" class="block text-gray-700 hover:text-blue-600 transition-colors py-2">Referinte</a>
|
||
<a href="menu/angajari.html" class="block text-gray-700 hover:text-blue-600 transition-colors py-2">Angajari</a>
|
||
<a href="menu/contact.html" class="block text-gray-700 hover:text-blue-600 transition-colors py-2">Contact</a>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
</header>
|
||
|
||
<!-- Main Content Container -->
|
||
<main class="container mx-auto px-4 py-8 max-w-7xl">
|
||
|
||
<!-- Chatbot Container -->
|
||
<div class="professional-card p-8 max-w-4xl mx-auto">
|
||
|
||
<!-- Flowise Chatbot -->
|
||
<div class="flex justify-center">
|
||
<flowise-fullchatbot></flowise-fullchatbot>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<!-- Professional Footer -->
|
||
<footer class="professional-navbar mt-16">
|
||
<div class="container mx-auto px-4 py-8 text-center">
|
||
<div class="text-white">
|
||
<p class="mb-2">© 2025 Romfast. Toate drepturile rezervate.</p>
|
||
<p class="text-sm opacity-80">ROA - Romfast Applications - Sisteme informatice pentru managementul afacerii</p>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
<script type="module">
|
||
import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
|
||
|
||
// Funcție pentru a obține parametrii din URL
|
||
function getUrlParameter(name) {
|
||
try {
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
const value = urlParams.get(name);
|
||
|
||
if (value === null) {
|
||
return '';
|
||
}
|
||
|
||
return value;
|
||
} catch (error) {
|
||
console.error("Eroare cu URLSearchParams:", error);
|
||
|
||
try {
|
||
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
|
||
var results = regex.exec(location.search);
|
||
|
||
if (results === null) {
|
||
return '';
|
||
}
|
||
|
||
let rawValue = results[1];
|
||
|
||
function safeDecodeURIComponent(str) {
|
||
str = str.replace(/\+/g, ' ');
|
||
|
||
const chunks = str.split('%');
|
||
let result = chunks[0];
|
||
|
||
for (let i = 1; i < chunks.length; i++) {
|
||
const chunk = chunks[i];
|
||
if (chunk.length >= 2) {
|
||
const hexCode = chunk.substring(0, 2);
|
||
const rest = chunk.substring(2);
|
||
|
||
if (/^[0-9A-Fa-f]{2}$/.test(hexCode)) {
|
||
try {
|
||
result += decodeURIComponent('%' + hexCode) + rest;
|
||
} catch (e) {
|
||
result += '%' + chunk;
|
||
}
|
||
} else {
|
||
result += '%' + chunk;
|
||
}
|
||
} else {
|
||
result += '%' + chunk;
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
const decoded = safeDecodeURIComponent(rawValue);
|
||
return decoded;
|
||
|
||
} catch (fallbackError) {
|
||
console.error("Eroare și la fallback sigur:", fallbackError);
|
||
return '';
|
||
}
|
||
}
|
||
}
|
||
|
||
// Obține mesajul inițial din parametrul URL (dacă există)
|
||
const initialMessage = getUrlParameter('message');
|
||
|
||
// Definește prompt-urile inițiale standard
|
||
const defaultStarterPrompts = [
|
||
'Cum se actualizeaza tokenul eFactura?',
|
||
'Cand se completeaza codul de plata pentru declaratia SAFT?',
|
||
'Cum se configurează o politică de prețuri? Afișeaza pașii complet',
|
||
'Care sunt pasii pentru emiterea unei facturi service auto?',
|
||
'Cum se valideaza o comanda service auto?',
|
||
'Cum se deschide o comanda service auto?',
|
||
'Cum se modifica datele initiale ale unei comenzi service auto (ex: nr. km)?'
|
||
];
|
||
|
||
// Determină dacă să afișeze prompt-urile inițiale sau nu
|
||
const starterPrompts = initialMessage ? [] : defaultStarterPrompts;
|
||
|
||
// Detectează tema activă (dark-mode sau light-mode)
|
||
const isDarkMode = document.body.classList.contains('dark-mode') ||
|
||
document.documentElement.classList.contains('dark-mode') ||
|
||
localStorage.getItem('theme') === 'dark';
|
||
|
||
console.log('🎨 Current theme:', isDarkMode ? 'dark' : 'light');
|
||
|
||
// Configurează culorile în funcție de temă
|
||
const themeColors = isDarkMode ? {
|
||
backgroundColor: "#2a2a2a",
|
||
botMessageBg: "#3a3a3a",
|
||
botMessageText: "#e0e0e0",
|
||
userMessageBg: "#5B9BFF",
|
||
userMessageText: "#ffffff",
|
||
inputBg: "#3a3a3a",
|
||
inputText: "#e0e0e0",
|
||
sendButtonColor: "#5B9BFF",
|
||
feedbackColor: "#e0e0e0",
|
||
footerTextColor: "#e0e0e0"
|
||
} : {
|
||
backgroundColor: "#ffffff",
|
||
botMessageBg: "#f7f8ff",
|
||
botMessageText: "#303235",
|
||
userMessageBg: "#3B81F6",
|
||
userMessageText: "#ffffff",
|
||
inputBg: "#ffffff",
|
||
inputText: "#303235",
|
||
sendButtonColor: "#3B81F6",
|
||
feedbackColor: "#303235",
|
||
footerTextColor: "#303235"
|
||
};
|
||
|
||
// Inițializează chatbot-ul cu tema detectată
|
||
const chatbotInstance = Chatbot.initFull({
|
||
chatflowid: "d4911620-07fe-41f8-adb4-f2f52d6ec766",
|
||
apiHost: "https://mutual-special-koala.ngrok-free.app",
|
||
theme: {
|
||
chatWindow: {
|
||
showTitle: true,
|
||
title: 'Maria ChatBot - Romfast Suport',
|
||
titleAvatarSrc: 'https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg',
|
||
showAgentMessages: true,
|
||
welcomeMessage: 'Bună! Eu sunt Maria, specialistul dvs. de suport tehnic Romfast. Sunt aici pentru a vă ajuta cu orice întrebări sau probleme tehnice legate de utilizarea sistemului ROA. Cum vă pot ajuta astăzi?',
|
||
errorMessage: 'Am o eroare! Revino mai tarziu',
|
||
backgroundColor: themeColors.backgroundColor,
|
||
height: 700,
|
||
width: 500,
|
||
fontSize: 16,
|
||
starterPrompts: starterPrompts,
|
||
starterPromptFontSize: 15,
|
||
clearChatOnReload: true,
|
||
botMessage: {
|
||
backgroundColor: themeColors.botMessageBg,
|
||
textColor: themeColors.botMessageText,
|
||
showAvatar: true,
|
||
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png",
|
||
},
|
||
userMessage: {
|
||
backgroundColor: themeColors.userMessageBg,
|
||
textColor: themeColors.userMessageText,
|
||
showAvatar: true,
|
||
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png",
|
||
},
|
||
textInput: {
|
||
placeholder: 'Scrieți întrebarea dvs.',
|
||
backgroundColor: themeColors.inputBg,
|
||
textColor: themeColors.inputText,
|
||
sendButtonColor: themeColors.sendButtonColor,
|
||
maxChars: 2000,
|
||
maxCharsWarningMessage: 'Ați depășit limita de caractere. Vă rugăm să introduceți mai puțin de 2000 de caractere.',
|
||
autoFocus: true,
|
||
sendMessageSound: false,
|
||
receiveMessageSound: false,
|
||
},
|
||
feedback: {
|
||
color: themeColors.feedbackColor,
|
||
},
|
||
footer: {
|
||
textColor: themeColors.footerTextColor,
|
||
text: 'Powered by',
|
||
company: 'Romfast',
|
||
companyLink: 'https://www.romfast.ro',
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
// Funcție pentru a afișa răspunsul API direct în pagină
|
||
function displayApiResponse(question, response) {
|
||
// Ascunde indicatorul de loading
|
||
hideLoadingIndicator();
|
||
|
||
const container = document.createElement('div');
|
||
container.className = 'api-message-container';
|
||
|
||
const messageBox = document.createElement('div');
|
||
messageBox.className = 'api-message-box';
|
||
|
||
const header = document.createElement('div');
|
||
header.className = 'api-message-header';
|
||
|
||
const avatar = document.createElement('div');
|
||
avatar.className = 'api-message-avatar';
|
||
avatar.textContent = 'M';
|
||
|
||
const title = document.createElement('div');
|
||
title.className = 'api-message-title';
|
||
title.textContent = 'Maria - Asistent Romfast';
|
||
|
||
header.appendChild(avatar);
|
||
header.appendChild(title);
|
||
|
||
const scrollableArea = document.createElement('div');
|
||
scrollableArea.className = 'api-message-scrollable';
|
||
|
||
const userQuery = document.createElement('div');
|
||
userQuery.className = 'user-query';
|
||
userQuery.textContent = question;
|
||
|
||
const content = document.createElement('div');
|
||
content.className = 'api-message-content';
|
||
content.textContent = response.text || response;
|
||
|
||
scrollableArea.appendChild(userQuery);
|
||
scrollableArea.appendChild(content);
|
||
|
||
const footer = document.createElement('div');
|
||
footer.className = 'api-message-footer';
|
||
|
||
const button = document.createElement('button');
|
||
button.className = 'api-message-button';
|
||
button.textContent = 'Continuă conversația';
|
||
button.onclick = function() {
|
||
container.style.opacity = '0';
|
||
setTimeout(() => {
|
||
container.remove();
|
||
}, 300);
|
||
|
||
const chatHistory = [{
|
||
message: question,
|
||
type: 'userMessage'
|
||
}, {
|
||
message: response.text || response,
|
||
type: 'apiMessage'
|
||
}];
|
||
|
||
try {
|
||
localStorage.setItem('flowise-chatbot-history', JSON.stringify(chatHistory));
|
||
} catch (e) {
|
||
console.error('Eroare la salvarea istoricului în localStorage:', e);
|
||
}
|
||
|
||
const url = new URL(window.location.href);
|
||
url.searchParams.delete('message');
|
||
window.location.href = url.toString();
|
||
};
|
||
|
||
footer.appendChild(button);
|
||
|
||
messageBox.appendChild(header);
|
||
messageBox.appendChild(scrollableArea);
|
||
messageBox.appendChild(footer);
|
||
container.appendChild(messageBox);
|
||
|
||
document.body.appendChild(container);
|
||
|
||
setTimeout(() => {
|
||
container.style.opacity = '1';
|
||
}, 10);
|
||
}
|
||
|
||
// Funcție pentru a trimite mesajul direct prin API Flowise
|
||
async function sendMessageViaAPI(message) {
|
||
console.log('📡 sendMessageViaAPI started');
|
||
try {
|
||
const apiHost = "https://mutual-special-koala.ngrok-free.app";
|
||
const chatflowId = "d4911620-07fe-41f8-adb4-f2f52d6ec766";
|
||
|
||
const requestBody = {
|
||
question: message,
|
||
history: []
|
||
};
|
||
|
||
console.log('🔄 Sending request to API...');
|
||
const controller = new AbortController();
|
||
const timeoutId = setTimeout(() => controller.abort(), 30000);
|
||
|
||
const response = await fetch(`${apiHost}/api/v1/prediction/${chatflowId}`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(requestBody),
|
||
signal: controller.signal
|
||
});
|
||
|
||
clearTimeout(timeoutId);
|
||
|
||
if (response.ok) {
|
||
console.log('✅ API response received successfully');
|
||
const data = await response.json();
|
||
displayApiResponse(message, data);
|
||
return data;
|
||
} else {
|
||
console.error("❌ Eroare la apelul API:", response.status);
|
||
displayApiResponse(message, `Ne pare rău, a apărut o eroare în procesarea cererii dumneavoastră (cod: ${response.status}). Vă rugăm să încercați din nou mai târziu.`);
|
||
return null;
|
||
}
|
||
} catch (error) {
|
||
console.error("❌ Eroare la trimiterea mesajului prin API:", error);
|
||
|
||
// Ascunde indicatorul de loading în caz de eroare
|
||
hideLoadingIndicator();
|
||
|
||
let errorMessage = "Ne pare rău, a apărut o eroare în conectarea la serviciile noastre. Vă rugăm să verificați conexiunea la internet și să încercați din nou.";
|
||
|
||
if (error.name === 'AbortError') {
|
||
errorMessage = "Request-ul a fost întrerupt din cauza timeout-ului. Vă rugăm să încercați din nou.";
|
||
}
|
||
|
||
displayApiResponse(message, errorMessage);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// Funcție pentru a afișa toast-ul
|
||
function showToast(message, type = 'success') {
|
||
const toast = document.createElement('div');
|
||
toast.className = 'toast';
|
||
toast.textContent = message;
|
||
|
||
if (type === 'error') {
|
||
toast.classList.add('error');
|
||
}
|
||
|
||
document.body.appendChild(toast);
|
||
|
||
setTimeout(() => {
|
||
toast.classList.add('show');
|
||
}, 100);
|
||
|
||
setTimeout(() => {
|
||
toast.classList.remove('show');
|
||
setTimeout(() => {
|
||
if (document.body.contains(toast)) {
|
||
document.body.removeChild(toast);
|
||
}
|
||
}, 300);
|
||
}, 3000);
|
||
}
|
||
|
||
// Funcție pentru a afișa indicatorul de loading
|
||
function showLoadingIndicator() {
|
||
console.log('🔄 showLoadingIndicator called');
|
||
|
||
// Verifică dacă există deja un indicator de loading
|
||
if (document.querySelector('.loading-overlay')) {
|
||
console.log('⚠️ Loading overlay already exists');
|
||
return;
|
||
}
|
||
|
||
const overlay = document.createElement('div');
|
||
overlay.className = 'loading-overlay';
|
||
overlay.id = 'loading-indicator';
|
||
|
||
const spinner = document.createElement('div');
|
||
spinner.className = 'loading-spinner';
|
||
|
||
const text = document.createElement('div');
|
||
text.className = 'loading-text';
|
||
text.textContent = 'Se încarcă răspunsul...';
|
||
|
||
overlay.appendChild(spinner);
|
||
overlay.appendChild(text);
|
||
document.body.appendChild(overlay);
|
||
|
||
console.log('✅ Loading overlay created and added to DOM');
|
||
|
||
// Activează animația de fade-in
|
||
setTimeout(() => {
|
||
overlay.classList.add('show');
|
||
console.log('✅ Loading overlay faded in');
|
||
}, 10);
|
||
}
|
||
|
||
// Funcție pentru a ascunde indicatorul de loading
|
||
function hideLoadingIndicator() {
|
||
console.log('🔽 hideLoadingIndicator called');
|
||
|
||
const overlay = document.getElementById('loading-indicator');
|
||
if (overlay) {
|
||
overlay.classList.remove('show');
|
||
console.log('✅ Loading overlay fade-out started');
|
||
setTimeout(() => {
|
||
if (document.body.contains(overlay)) {
|
||
document.body.removeChild(overlay);
|
||
console.log('✅ Loading overlay removed from DOM');
|
||
}
|
||
}, 300);
|
||
} else {
|
||
console.log('⚠️ No loading overlay found to hide');
|
||
}
|
||
}
|
||
|
||
// Funcție pentru a găsi textarea-ul chatbot-ului cu MutationObserver
|
||
function waitForChatbotInput() {
|
||
return new Promise((resolve) => {
|
||
// Mai multe selectori posibili
|
||
const selectors = [
|
||
'textarea',
|
||
'input[type="text"]',
|
||
'input',
|
||
'textarea[placeholder*="Scrieți întrebarea"]',
|
||
'textarea[placeholder*="Type your message"]',
|
||
'.text-input',
|
||
'[contenteditable="true"]',
|
||
'[class*="text-input"]',
|
||
'[class*="textarea"]',
|
||
'[class*="input"]'
|
||
];
|
||
|
||
// Funcție pentru a căuta în shadow DOM
|
||
function searchInShadowDOM() {
|
||
const chatbotElement = document.querySelector('flowise-fullchatbot');
|
||
if (chatbotElement && chatbotElement.shadowRoot) {
|
||
for (const selector of selectors) {
|
||
const elements = chatbotElement.shadowRoot.querySelectorAll(selector);
|
||
for (const element of elements) {
|
||
if (element.offsetParent !== null && !element.disabled && !element.readOnly) {
|
||
return element;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// Încearcă să găsească textarea-ul imediat
|
||
for (const selector of selectors) {
|
||
const elements = document.querySelectorAll(selector);
|
||
for (const element of elements) {
|
||
if (element.offsetParent !== null && !element.disabled && !element.readOnly) {
|
||
resolve(element);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Caută în shadow DOM
|
||
const shadowElement = searchInShadowDOM();
|
||
if (shadowElement) {
|
||
resolve(shadowElement);
|
||
return;
|
||
}
|
||
|
||
// Dacă nu îl găsește, folosește MutationObserver
|
||
const observer = new MutationObserver((mutations) => {
|
||
// Caută în DOM normal
|
||
for (const selector of selectors) {
|
||
const elements = document.querySelectorAll(selector);
|
||
for (const element of elements) {
|
||
if (element.offsetParent !== null && !element.disabled && !element.readOnly) {
|
||
observer.disconnect();
|
||
resolve(element);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Caută în shadow DOM
|
||
const shadowElement = searchInShadowDOM();
|
||
if (shadowElement) {
|
||
observer.disconnect();
|
||
resolve(shadowElement);
|
||
return;
|
||
}
|
||
});
|
||
|
||
observer.observe(document.body, {
|
||
childList: true,
|
||
subtree: true
|
||
});
|
||
|
||
// Timeout după 15 secunde
|
||
setTimeout(() => {
|
||
observer.disconnect();
|
||
console.error('❌ Nu s-a găsit textarea-ul chatbot-ului în 15 secunde');
|
||
resolve(null);
|
||
}, 15000);
|
||
});
|
||
}
|
||
|
||
// Variabilă globală pentru a urmări dacă butonul a fost adăugat
|
||
let linkButtonAdded = false;
|
||
let intervalId = null;
|
||
|
||
// Funcție pentru a adăuga butonul mic lângă butonul de send
|
||
async function addLinkButtonToInput() {
|
||
// Dacă butonul a fost deja adăugat, nu mai continua
|
||
if (linkButtonAdded) {
|
||
return;
|
||
}
|
||
|
||
const textarea = await waitForChatbotInput();
|
||
if (!textarea) {
|
||
console.error('❌ Nu s-a găsit textarea-ul chatbot-ului');
|
||
return;
|
||
}
|
||
|
||
// Găsește containerul cu textarea
|
||
let inputContainer = textarea.parentElement;
|
||
let attempts = 0;
|
||
|
||
// Caută containerul potrivit mergând în sus prin DOM
|
||
while (inputContainer && attempts < 10) {
|
||
if (inputContainer.classList.contains('flex') ||
|
||
inputContainer.style.display === 'flex' ||
|
||
inputContainer.querySelector('button')) {
|
||
break;
|
||
}
|
||
inputContainer = inputContainer.parentElement;
|
||
attempts++;
|
||
}
|
||
|
||
if (!inputContainer) {
|
||
console.error('❌ Nu s-a găsit containerul input-ului');
|
||
return;
|
||
}
|
||
|
||
// Verifică dacă butonul există deja
|
||
if (inputContainer.querySelector('.link-button-small')) {
|
||
linkButtonAdded = true;
|
||
|
||
// Oprește intervalul dacă rulează
|
||
if (intervalId) {
|
||
clearInterval(intervalId);
|
||
intervalId = null;
|
||
}
|
||
return;
|
||
}
|
||
|
||
// Creează butonul mic
|
||
const linkButton = document.createElement('button');
|
||
linkButton.className = 'link-button-small';
|
||
linkButton.innerHTML = '🔗';
|
||
linkButton.title = 'Generează link pentru această întrebare';
|
||
linkButton.type = 'button';
|
||
|
||
// Adaugă stiluri inline pentru a fi sigur că se aplică în Shadow DOM
|
||
linkButton.style.cssText = `
|
||
background: transparent !important;
|
||
border: none !important;
|
||
padding: 0 !important;
|
||
margin: 0 0 0 8px !important;
|
||
height: 56px !important;
|
||
width: 56px !important;
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
justify-content: center !important;
|
||
cursor: pointer !important;
|
||
transition: all 0.2s ease !important;
|
||
border-radius: 6px !important;
|
||
font-size: 18px !important;
|
||
color: #3B81F6 !important;
|
||
opacity: 0.8 !important;
|
||
flex-shrink: 0 !important;
|
||
z-index: 1000 !important;
|
||
`;
|
||
|
||
// Adaugă event listener pentru hover
|
||
linkButton.addEventListener('mouseenter', () => {
|
||
linkButton.style.backgroundColor = 'rgba(59, 129, 246, 0.1)';
|
||
linkButton.style.opacity = '1';
|
||
linkButton.style.transform = 'scale(1.05)';
|
||
});
|
||
|
||
linkButton.addEventListener('mouseleave', () => {
|
||
linkButton.style.backgroundColor = 'transparent';
|
||
linkButton.style.opacity = '0.8';
|
||
linkButton.style.transform = 'scale(1)';
|
||
});
|
||
|
||
// Adaugă event listener pentru click
|
||
linkButton.addEventListener('click', (e) => {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
generateLinkFromInput(textarea, linkButton);
|
||
});
|
||
|
||
// Adaugă butonul în container
|
||
inputContainer.appendChild(linkButton);
|
||
|
||
console.log('✅ Butonul de link a fost adăugat cu succes');
|
||
|
||
// Marchează că butonul a fost adăugat
|
||
linkButtonAdded = true;
|
||
|
||
// Oprește intervalul dacă rulează
|
||
if (intervalId) {
|
||
clearInterval(intervalId);
|
||
intervalId = null;
|
||
}
|
||
|
||
// Verifică dacă butonul este vizibil (debugging final)
|
||
setTimeout(() => {
|
||
const rect = linkButton.getBoundingClientRect();
|
||
if (rect.width > 0 && rect.height > 0) {
|
||
console.log('✅ Butonul este vizibil și funcțional');
|
||
} else {
|
||
console.warn('⚠️ Butonul a fost adăugat dar nu este vizibil');
|
||
}
|
||
}, 100);
|
||
}
|
||
|
||
// Funcție pentru generarea linkului din input
|
||
function generateLinkFromInput(textarea, button) {
|
||
const message = textarea.value.trim();
|
||
|
||
if (!message) {
|
||
showToast('Vă rugăm să introduceți o întrebare în casuta de chat mai întâi!', 'error');
|
||
return;
|
||
}
|
||
|
||
// Generează URL-ul
|
||
const url = `${window.location.origin}${window.location.pathname}?message=${encodeURIComponent(message)}`;
|
||
|
||
// Feedback vizual pe buton
|
||
const originalHTML = button.innerHTML;
|
||
button.innerHTML = '✓';
|
||
button.classList.add('success');
|
||
|
||
// Copiază în clipboard
|
||
navigator.clipboard.writeText(url).then(() => {
|
||
showToast('Link-ul a fost copiat în clipboard!');
|
||
|
||
// Resetează butonul după 2 secunde
|
||
setTimeout(() => {
|
||
button.innerHTML = originalHTML;
|
||
button.classList.remove('success');
|
||
}, 2000);
|
||
}).catch(() => {
|
||
// Fallback pentru browsere mai vechi
|
||
const textArea = document.createElement('textarea');
|
||
textArea.value = url;
|
||
textArea.style.position = 'fixed';
|
||
textArea.style.opacity = '0';
|
||
document.body.appendChild(textArea);
|
||
textArea.focus();
|
||
textArea.select();
|
||
|
||
try {
|
||
document.execCommand('copy');
|
||
showToast('Link-ul a fost copiat în clipboard!');
|
||
} catch (err) {
|
||
showToast('Eroare la copierea linkului. Vă rugăm să încercați din nou.', 'error');
|
||
}
|
||
|
||
document.body.removeChild(textArea);
|
||
|
||
// Resetează butonul după 2 secunde
|
||
setTimeout(() => {
|
||
button.innerHTML = originalHTML;
|
||
button.classList.remove('success');
|
||
}, 2000);
|
||
});
|
||
}
|
||
|
||
// Inițializează adăugarea butonului când pagina se încarcă
|
||
window.addEventListener('load', () => {
|
||
// Nu căuta textarea dacă pagina a fost apelată cu parametru GET
|
||
if (initialMessage && initialMessage.trim() !== '') {
|
||
console.log('ℹ️ Page called with GET parameter - skipping textarea search');
|
||
return;
|
||
}
|
||
|
||
if (linkButtonAdded) return;
|
||
|
||
// Încearcă imediat
|
||
addLinkButtonToInput();
|
||
|
||
// Încearcă din nou doar dacă butonul nu a fost adăugat
|
||
setTimeout(() => {
|
||
if (!linkButtonAdded) {
|
||
addLinkButtonToInput();
|
||
}
|
||
}, 2000);
|
||
|
||
setTimeout(() => {
|
||
if (!linkButtonAdded) {
|
||
addLinkButtonToInput();
|
||
}
|
||
}, 5000);
|
||
|
||
setTimeout(() => {
|
||
if (!linkButtonAdded) {
|
||
addLinkButtonToInput();
|
||
}
|
||
}, 10000);
|
||
});
|
||
|
||
// Adaugă și un event listener pentru DOMContentLoaded
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
// Nu căuta textarea dacă pagina a fost apelată cu parametru GET
|
||
if (initialMessage && initialMessage.trim() !== '') {
|
||
console.log('ℹ️ DOMContentLoaded - Page called with GET parameter - skipping textarea search');
|
||
return;
|
||
}
|
||
|
||
if (linkButtonAdded) return;
|
||
|
||
setTimeout(() => {
|
||
if (!linkButtonAdded) {
|
||
addLinkButtonToInput();
|
||
}
|
||
}, 1000);
|
||
});
|
||
|
||
// Verifică periodic dacă butonul există și îl adaugă dacă lipsește
|
||
// Nu rula intervalul dacă pagina a fost apelată cu parametru GET
|
||
if (!initialMessage || initialMessage.trim() === '') {
|
||
intervalId = setInterval(() => {
|
||
// Oprește intervalul dacă butonul a fost adăugat
|
||
if (linkButtonAdded) {
|
||
clearInterval(intervalId);
|
||
intervalId = null;
|
||
return;
|
||
}
|
||
|
||
// Verifică dacă butonul există
|
||
const existingButton = document.querySelector('.link-button-small');
|
||
if (!existingButton) {
|
||
// Verifică dacă textarea-ul există
|
||
const textarea = document.querySelector('textarea') ||
|
||
document.querySelector('input[type="text"]');
|
||
|
||
if (textarea && textarea.offsetParent !== null) {
|
||
addLinkButtonToInput();
|
||
}
|
||
} else {
|
||
// Dacă butonul există, marchează că a fost adăugat și oprește intervalul
|
||
linkButtonAdded = true;
|
||
clearInterval(intervalId);
|
||
intervalId = null;
|
||
}
|
||
}, 3000); // Verifică la fiecare 3 secunde
|
||
} else {
|
||
console.log('ℹ️ Periodic interval - Page called with GET parameter - skipping textarea search');
|
||
}
|
||
|
||
// Dacă există un mesaj inițial, trimite-l direct prin API
|
||
if (initialMessage) {
|
||
console.log('📩 Initial message detected:', initialMessage.substring(0, 100) + '...');
|
||
if (initialMessage.trim() !== '') {
|
||
console.log('✅ Message is valid, proceeding with API call');
|
||
|
||
const chatbotElement = document.querySelector('flowise-fullchatbot');
|
||
if (chatbotElement) {
|
||
chatbotElement.style.display = 'none';
|
||
console.log('✅ Chatbot element hidden');
|
||
}
|
||
|
||
// Afișează indicatorul de loading
|
||
console.log('🔄 About to show loading indicator...');
|
||
showLoadingIndicator();
|
||
|
||
console.log('📡 Sending message to API...');
|
||
sendMessageViaAPI(initialMessage);
|
||
} else {
|
||
console.error("❌ Mesajul initial este gol după decodare");
|
||
}
|
||
} else {
|
||
console.log('ℹ️ No initial message parameter detected');
|
||
}
|
||
</script>
|
||
|
||
<!-- Professional Theme JavaScript -->
|
||
<script>
|
||
// Theme toggle functionality
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// Initialize Lucide icons
|
||
lucide.createIcons();
|
||
|
||
// Theme toggle
|
||
const themeToggle = document.getElementById('theme-toggle');
|
||
const body = document.body;
|
||
const html = document.documentElement;
|
||
|
||
// Check if dark-mode was already set by inline script
|
||
const isDarkMode = html.classList.contains('dark-mode');
|
||
|
||
if (isDarkMode) {
|
||
// Dark mode already set by inline script, just add to body and update icon
|
||
body.classList.add('dark-mode');
|
||
themeToggle.innerHTML = '<i data-lucide="moon" class="w-5 h-5"></i>';
|
||
// Reinitialize icons to render the moon icon
|
||
lucide.createIcons();
|
||
}
|
||
|
||
themeToggle.addEventListener('click', function() {
|
||
// Save the new theme preference
|
||
const newTheme = body.classList.contains('dark-mode') ? 'light' : 'dark';
|
||
localStorage.setItem('theme', newTheme);
|
||
|
||
// Reload page to reinitialize chatbot with new theme
|
||
window.location.reload();
|
||
});
|
||
|
||
// Mobile menu toggle
|
||
const mobileMenuToggle = document.getElementById('mobile-menu-toggle');
|
||
const mobileMenu = document.getElementById('mobile-menu');
|
||
const menuIcon = document.getElementById('menu-icon');
|
||
const closeIcon = document.getElementById('close-icon');
|
||
|
||
mobileMenuToggle.addEventListener('click', function() {
|
||
mobileMenu.classList.toggle('hidden');
|
||
menuIcon.classList.toggle('hidden');
|
||
closeIcon.classList.toggle('hidden');
|
||
});
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |