luca-chatbot-embed
Version:
Luca AI Chatbot - Non-intrusive popup widget for websites
1,197 lines (1,056 loc) • 41.4 kB
JavaScript
(function() {
'use strict';
// CSS Styles - Embedded directly in the script
const styles = `
/* CSS Variables for theming */
:root {
--bg-primary: #1a1a1a;
--bg-secondary: #2d2d2d;
--bg-tertiary: #3a3a3a;
--text-primary: #ffffff;
--text-secondary: rgba(255, 255, 255, 0.8);
--text-muted: rgba(255, 255, 255, 0.6);
--border-color: #404040;
--shadow-color: rgba(0, 0, 0, 0.3);
--accent-primary: #512feb;
--accent-secondary: #6a5acd;
--accent-hover: #4a1fd1;
--success-color: #10b981;
--error-color: #ef4444;
--warning-color: #f59e0b;
--scrollbar-color: #666666;
--scrollbar-hover-color: #888888;
}
/* Light mode colors */
[data-theme="light"] {
--bg-primary: #ffffff;
--bg-secondary: #f8f9fa;
--bg-tertiary: #e9ecef;
--text-primary: #1a1a1a;
--text-secondary: rgba(26, 26, 26, 0.8);
--text-muted: rgba(26, 26, 26, 0.6);
--border-color: #dee2e6;
--shadow-color: rgba(0, 0, 0, 0.1);
--accent-primary: #512feb;
--accent-secondary: #6a5acd;
--accent-hover: #4a1fd1;
--success-color: #10b981;
--error-color: #ef4444;
--warning-color: #f59e0b;
--scrollbar-color: #c1c1c1;
--scrollbar-hover-color: #a8a8a8;
}
/* Luca Chatbot Container */
.luca-chatbot-container {
position: fixed;
bottom: 0;
right: 0;
z-index: 10000;
font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-size: 16px;
line-height: 1.5;
color: var(--text-primary);
pointer-events: none;
}
.luca-chatbot-container * {
box-sizing: border-box;
}
/* Toggle Button */
.luca-chatbot-toggle {
position: fixed;
bottom: 30px;
right: 35px;
border: none;
height: 50px;
width: 50px;
display: flex;
cursor: pointer;
align-items: center;
justify-content: center;
border-radius: 50%;
background: var(--accent-primary);
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
transform: scale(1);
animation: luca-float 4s ease-in-out infinite;
box-shadow: 0 8px 25px rgba(81, 47, 235, 0.3);
will-change: transform, box-shadow;
z-index: 10000;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
pointer-events: auto;
}
@keyframes luca-float {
0%, 100% {
transform: translateY(0px) scale(1);
box-shadow: 0 8px 25px rgba(81, 47, 235, 0.3);
}
50% {
transform: translateY(-8px) scale(1.02);
box-shadow: 0 15px 35px rgba(81, 47, 235, 0.4);
}
}
.luca-chatbot-toggle:hover {
transform: scale(1.15);
box-shadow: 0 12px 35px rgba(81, 47, 235, 0.5);
animation-play-state: paused;
}
.luca-chatbot-toggle:active {
transform: scale(0.9);
transition: all 0.15s cubic-bezier(0.4, 0, 0.6, 1);
box-shadow: 0 4px 15px rgba(81, 47, 235, 0.4);
}
.luca-chatbot-toggle.show-chatbot {
transform: rotate(135deg) scale(1.1);
animation: none;
box-shadow: 0 10px 30px rgba(81, 47, 235, 0.4);
}
.luca-chatbot-toggle span {
color: #fff;
position: absolute;
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
transform: scale(1);
will-change: transform, opacity;
font-family: 'Material Symbols Rounded', sans-serif;
font-size: 24px;
}
.luca-chatbot-toggle span:last-child,
.luca-chatbot-toggle.show-chatbot span:first-child {
opacity: 0;
transform: scale(0.8) rotate(-90deg);
}
.luca-chatbot-toggle.show-chatbot span:last-child {
opacity: 1;
transform: scale(1) rotate(0deg);
}
.luca-chatbot-toggle.show-chatbot span:first-child {
opacity: 0;
transform: scale(0.8) rotate(90deg);
}
/* Chatbot Popup */
.luca-chatbot-popup {
position: fixed;
right: 35px;
bottom: 90px;
width: 380px;
height: 700px;
overflow: hidden;
background: var(--bg-primary);
border: 1px solid var(--border-color);
border-radius: 20px;
opacity: 0;
pointer-events: none;
transform: scale(0.3) translateY(30px) rotateX(10deg);
transform-origin: bottom right;
transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
backdrop-filter: blur(15px);
box-shadow: 0 20px 60px var(--shadow-color);
will-change: transform, opacity;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
touch-action: none;
z-index: 9999;
isolation: isolate;
contain: layout style paint;
}
.luca-chatbot-container.show-chatbot .luca-chatbot-popup {
opacity: 1;
pointer-events: auto;
transform: scale(1) translateY(0) rotateX(0deg);
user-select: auto;
-webkit-user-select: auto;
-moz-user-select: auto;
-ms-user-select: auto;
touch-action: auto;
contain: none;
}
/* Ensure all child elements of the closed chatbot don't interfere */
.luca-chatbot-popup * {
pointer-events: none !important;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
touch-action: none;
}
/* Re-enable interactions for child elements when chatbot is open */
.luca-chatbot-container.show-chatbot .luca-chatbot-popup * {
pointer-events: auto;
user-select: auto;
-webkit-user-select: auto;
-moz-user-select: auto;
-ms-user-select: auto;
touch-action: auto;
}
/* Chat Header */
.luca-chat-header {
display: flex;
align-items: center;
padding: 15px 22px;
background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%);
justify-content: space-between;
position: relative;
overflow: hidden;
}
.luca-header-info {
display: flex;
gap: 12px;
align-items: center;
}
.luca-profile-container {
position: relative;
flex-shrink: 0;
}
.luca-chatbot-logo {
width: 40px;
height: 40px;
flex-shrink: 0;
object-fit: cover;
border-radius: 50%;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
animation: luca-pulse 2s ease-in-out infinite;
}
.luca-online-indicator {
position: absolute;
bottom: 2px;
left: 2px;
width: 12px;
height: 12px;
background: #FFD700;
border: 2px solid #fff;
border-radius: 50%;
animation: luca-pulse 2s ease-in-out infinite;
}
@keyframes luca-pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.luca-user-info {
display: flex;
flex-direction: column;
gap: 2px;
}
.luca-logo-text {
color: #fff;
font-weight: 600;
font-size: 1.1rem;
letter-spacing: 0.02rem;
margin: 0;
}
.luca-activity-status {
color: rgba(255, 255, 255, 0.8);
font-size: 0.8rem;
font-weight: 400;
}
.luca-header-controls {
display: flex;
align-items: center;
gap: 8px;
}
.luca-header-controls button {
border: none;
color: #fff;
height: 35px;
width: 35px;
font-size: 1.2rem;
cursor: pointer;
border-radius: 50%;
background: none;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
font-family: 'Material Symbols Rounded', sans-serif;
}
.luca-header-controls button::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255, 255, 255, 0.1);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: all 0.3s ease;
}
.luca-header-controls button:hover::before {
width: 100%;
height: 100%;
}
.luca-header-controls button:hover {
transform: scale(1.1);
background: rgba(255, 255, 255, 0.1);
}
/* Chat Body */
.luca-chat-body {
padding: 25px 22px 40px 22px;
gap: 20px;
display: flex;
height: calc(100% - 160px);
overflow-y: auto;
flex-direction: column;
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-color) transparent;
position: relative;
background: var(--bg-primary);
scroll-behavior: smooth;
overscroll-behavior: contain;
}
.luca-chat-body::-webkit-scrollbar {
width: 6px;
}
.luca-chat-body::-webkit-scrollbar-track {
background: transparent;
}
.luca-chat-body::-webkit-scrollbar-thumb {
background: var(--scrollbar-color);
border-radius: 3px;
transition: all 0.3s ease;
}
.luca-chat-body::-webkit-scrollbar-thumb:hover {
background: var(--scrollbar-hover-color);
}
.luca-message {
display: flex;
gap: 11px;
align-items: center;
animation: luca-messageSlideIn 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
transform: translateY(0);
opacity: 1;
will-change: transform, opacity;
}
@keyframes luca-messageSlideIn {
0% {
opacity: 0;
transform: translateY(30px) scale(0.95);
filter: blur(1px);
}
70% {
transform: translateY(-2px) scale(1.01);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
filter: blur(0);
}
}
.luca-message.user-message {
animation: luca-userMessageSlideIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes luca-userMessageSlideIn {
0% {
opacity: 0;
transform: translateY(25px) translateX(25px) scale(0.9);
filter: blur(1px);
}
60% {
transform: translateY(-3px) translateX(-3px) scale(1.02);
}
100% {
opacity: 1;
transform: translateY(0) translateX(0) scale(1);
filter: blur(0);
}
}
.luca-message .luca-bot-avatar {
width: 35px;
height: 35px;
flex-shrink: 0;
margin-bottom: 2px;
align-self: flex-end;
border-radius: 50%;
object-fit: cover;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
animation: luca-avatarBounce 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
@keyframes luca-avatarBounce {
0% {
transform: scale(0) rotate(-180deg);
}
50% {
transform: scale(1.2) rotate(-90deg);
}
100% {
transform: scale(1) rotate(0deg);
}
}
.luca-message .luca-message-text {
padding: 12px 16px;
max-width: 75%;
font-size: 0.95rem;
word-wrap: normal;
word-break: normal;
overflow-wrap: normal;
white-space: normal;
hyphens: none;
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
transform: scale(1);
will-change: transform;
color: var(--text-primary);
}
.luca-message .luca-message-text:hover {
transform: scale(1.03);
filter: brightness(1.05);
}
.luca-bot-message .luca-message-text {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 18px 18px 18px 4px;
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
max-width: 75%;
color: var(--text-primary);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
position: relative;
}
.luca-user-message {
flex-direction: column;
align-items: flex-end;
}
.luca-user-message .luca-message-text {
color: #fff;
background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%);
border-radius: 18px 18px 4px 18px;
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
box-shadow: 0 4px 12px rgba(81, 47, 235, 0.3);
}
/* Chat Footer */
.luca-chat-footer {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 110px;
background: var(--bg-primary);
border-top: 1px solid var(--border-color);
padding: 15px 22px 40px;
z-index: 20;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
}
.luca-chat-form {
display: flex;
align-items: center;
position: relative;
background: var(--bg-secondary);
border-radius: 32px;
outline: 1px solid var(--border-color);
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
transform: translateY(0);
will-change: transform, box-shadow;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.luca-chat-form:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
}
.luca-chat-form:focus-within {
outline: 2px solid var(--accent-primary);
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(81, 47, 235, 0.2);
}
.luca-message-input {
width: 100%;
height: 47px;
outline: none;
resize: none;
border: none;
max-height: 180px;
scrollbar-width: none;
-ms-overflow-style: none;
border-radius: inherit;
font-size: 0.95rem;
padding: 14px 0 12px 18px;
background: transparent;
color: var(--text-primary);
transition: all 0.3s ease;
line-height: 1.4;
font-family: inherit;
}
.luca-message-input::-webkit-scrollbar {
display: none;
}
.luca-message-input::placeholder {
color: var(--text-muted);
transition: opacity 0.3s ease;
}
.luca-message-input:focus::placeholder {
opacity: 0.7;
}
.luca-chat-controls {
gap: 3px;
height: 47px;
display: flex;
padding-right: 6px;
align-items: center;
align-self: flex-end;
}
.luca-chat-controls button {
height: 35px;
width: 35px;
border: none;
cursor: pointer;
color: var(--text-secondary);
border-radius: 50%;
font-size: 1.15rem;
background: none;
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
position: relative;
overflow: hidden;
will-change: transform, color;
font-family: 'Material Symbols Rounded', sans-serif;
}
.luca-chat-controls button::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: var(--accent-primary);
opacity: 0.1;
border-radius: 50%;
transform: translate(-50%, -50%);
transition: all 0.3s ease;
}
.luca-chat-controls button:hover::before {
width: 100%;
height: 100%;
}
.luca-chat-controls button:hover {
color: var(--accent-hover);
transform: scale(1.2);
filter: drop-shadow(0 2px 4px rgba(81, 47, 235, 0.3));
}
.luca-chat-controls .luca-send-message {
color: #fff;
display: none;
background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%);
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
box-shadow: 0 2px 8px rgba(81, 47, 235, 0.3);
}
.luca-chat-controls .luca-send-message:hover {
background: linear-gradient(135deg, var(--accent-hover) 0%, var(--accent-primary) 100%);
transform: scale(1.15);
box-shadow: 0 4px 12px rgba(81, 47, 235, 0.5);
}
.luca-chat-controls .luca-send-message:active {
transform: scale(0.95);
transition: all 0.1s ease;
}
.luca-message-input:valid ~ .luca-chat-controls .luca-send-message {
display: block;
}
/* Action Buttons */
.luca-action-buttons-container {
display: flex;
justify-content: flex-end;
margin-top: 15px;
padding: 0;
margin-bottom: 30px;
position: relative;
z-index: 1;
}
.luca-action-buttons {
display: flex;
flex-wrap: wrap;
gap: 10px;
max-width: 100%;
justify-content: flex-end;
position: relative;
z-index: 1;
}
.luca-action-button {
background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%);
color: white;
border: none;
border-radius: 30px;
padding: 14px 24px;
font-size: 0.9rem;
font-weight: 500;
cursor: pointer;
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
display: flex;
align-items: center;
gap: 8px;
min-width: 140px;
justify-content: center;
position: relative;
overflow: hidden;
animation: luca-buttonSlideIn 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
box-shadow: 0 4px 15px rgba(81, 47, 235, 0.3);
will-change: transform, box-shadow;
font-family: inherit;
}
.luca-action-button::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: all 0.5s ease;
}
.luca-action-button:hover::before {
left: 100%;
}
.luca-action-button:hover {
background: linear-gradient(135deg, var(--accent-hover) 0%, var(--accent-primary) 100%);
transform: translateY(-4px) scale(1.05);
box-shadow: 0 8px 25px rgba(81, 47, 235, 0.4);
}
.luca-action-button:active {
transform: translateY(-1px) scale(0.98);
transition: all 0.15s ease;
box-shadow: 0 2px 10px rgba(81, 47, 235, 0.3);
}
@keyframes luca-buttonSlideIn {
0% {
opacity: 0;
transform: translateY(30px) scale(0.8) rotateX(30deg);
filter: blur(2px);
}
60% {
transform: translateY(-5px) scale(1.05) rotateX(-5deg);
}
100% {
opacity: 1;
transform: translateY(0) scale(1) rotateX(0deg);
filter: blur(0);
}
}
/* Watermark */
.luca-chat-watermark {
position: absolute;
bottom: 8px;
left: 50%;
transform: translateX(-50%);
font-size: 0.65rem;
color: var(--text-muted);
opacity: 0.6;
text-align: center;
z-index: 15;
}
.luca-chat-watermark a {
color: var(--accent-primary);
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
}
.luca-chat-watermark a:hover {
color: var(--accent-hover);
opacity: 1;
}
/* Mobile Responsive */
@media (max-width: 520px) {
.luca-chatbot-toggle {
right: 20px;
bottom: 20px;
width: 56px;
height: 56px;
font-size: 1.5rem;
animation: luca-float-mobile 6s ease-in-out infinite;
}
@keyframes luca-float-mobile {
0%, 100% {
transform: translateY(0px) scale(1);
box-shadow: 0 8px 25px rgba(81, 47, 235, 0.3);
}
50% {
transform: translateY(-4px) scale(1.01);
box-shadow: 0 12px 30px rgba(81, 47, 235, 0.35);
}
}
.luca-chatbot-popup {
right: 0;
bottom: 0;
height: 100vh;
border-radius: 0;
width: 100vw;
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.luca-chat-header {
padding: 12px 15px;
height: 60px;
min-height: 60px;
display: flex;
align-items: center;
}
.luca-logo-text {
font-size: 1rem;
}
.luca-activity-status {
font-size: 0.75rem;
}
.luca-chat-body {
height: calc(100vh - 60px - 110px);
padding: 15px 15px 120px 15px;
margin-bottom: 110px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
position: relative;
overscroll-behavior: contain;
}
.luca-chat-footer {
padding: 10px 15px 15px;
height: 110px;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
z-index: 20;
background: var(--bg-primary);
border-top: 1px solid var(--border-color);
}
.luca-chat-form {
position: relative;
z-index: 25;
background: var(--bg-primary);
border-radius: 25px;
min-height: 50px;
}
.luca-message-input {
font-size: 16px;
padding: 15px 0 15px 18px;
min-height: 50px;
line-height: 1.4;
}
.luca-action-buttons-container {
margin-bottom: 120px;
padding: 0 5px;
}
.luca-action-buttons {
flex-direction: column;
gap: 12px;
margin-bottom: 20px;
}
.luca-action-button {
width: 100%;
min-width: auto;
padding: 16px 20px;
font-size: 1rem;
border-radius: 25px;
min-height: 56px;
display: flex;
align-items: center;
justify-content: center;
}
.luca-message {
margin-bottom: 12px;
gap: 8px;
}
.luca-message .luca-bot-avatar {
width: 32px;
height: 32px;
}
.luca-message .luca-message-text {
max-width: 85%;
font-size: 0.95rem;
padding: 12px 16px;
line-height: 1.5;
}
.luca-chat-controls button {
width: 40px;
height: 40px;
font-size: 1.2rem;
}
.luca-header-controls button {
width: 40px;
height: 40px;
font-size: 1.1rem;
}
}
/* Material Icons Font */
@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@48,400,1,0&display=swap');
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap');
`;
// Inject CSS
function injectStyles() {
if (document.getElementById('luca-chatbot-styles')) {
return; // Already injected
}
const styleSheet = document.createElement('style');
styleSheet.id = 'luca-chatbot-styles';
styleSheet.textContent = styles;
document.head.appendChild(styleSheet);
}
// Create chatbot HTML structure
function createChatbotHTML() {
const container = document.createElement('div');
container.className = 'luca-chatbot-container';
container.innerHTML = `
<button class="luca-chatbot-toggle" id="luca-chatbot-toggle">
<span class="material-symbols-rounded">mode_comment</span>
<span class="material-symbols-rounded">close</span>
</button>
<div class="luca-chatbot-popup" id="luca-chatbot-popup">
<div class="luca-chat-header">
<div class="luca-header-info">
<div class="luca-profile-container">
<img class="luca-chatbot-logo" src="https://i.imgur.com/rAOFxqL.png" alt="Luca Chatbot" width="40" height="40">
<div class="luca-online-indicator"></div>
</div>
<div class="luca-user-info">
<h2 class="luca-logo-text">Luca</h2>
<span class="luca-activity-status">Active now</span>
</div>
</div>
<div class="luca-header-controls">
<button id="luca-theme-toggle" class="material-symbols-rounded" title="Toggle theme">dark_mode</button>
<button id="luca-close-chatbot" class="material-symbols-rounded">keyboard_arrow_down</button>
</div>
</div>
<div class="luca-chat-body" id="luca-chat-body">
<div class="luca-message luca-bot-message">
<img class="luca-bot-avatar" src="https://i.imgur.com/rAOFxqL.png" alt="Luca" width="35" height="35">
<div class="luca-message-text">
Hei! 👋 Olen Luca, Reppyn 24/7 AI-assistentti. Mitä aihetta asiasi koskee?
</div>
</div>
<div class="luca-action-buttons-container" id="luca-action-buttons-container">
<div class="luca-action-buttons">
<button class="luca-action-button" data-action="general">
<span class="material-symbols-rounded">help</span>
Yleiset kysymykset
</button>
<button class="luca-action-button" data-action="support">
<span class="material-symbols-rounded">support_agent</span>
Tekninen tuki
</button>
<button class="luca-action-button" data-action="pricing">
<span class="material-symbols-rounded">payments</span>
Hinnoittelu
</button>
</div>
</div>
</div>
<div class="luca-chat-footer">
<form class="luca-chat-form" id="luca-chat-form">
<textarea
class="luca-message-input"
id="luca-message-input"
placeholder="Viesti..."
required
></textarea>
<div class="luca-chat-controls">
<button type="button" id="luca-restart-chat" class="material-symbols-rounded" title="Aloita keskustelu uudelleen">refresh</button>
<button type="submit" id="luca-send-message" class="material-symbols-rounded luca-send-message">arrow_upward</button>
</div>
</form>
<div class="luca-chat-watermark">
Powered by <a href="https://reppy.fi" target="_blank">Reppy.fi</a>
</div>
</div>
</div>
`;
return container;
}
// Chatbot functionality
class LucaChatbot {
constructor() {
this.container = null;
this.isOpen = false;
this.messages = [];
this.currentTheme = 'dark';
this.init();
}
init() {
// Inject styles
injectStyles();
// Create and append chatbot
this.container = createChatbotHTML();
document.body.appendChild(this.container);
// Initialize event listeners
this.initEventListeners();
// Set initial theme
this.setTheme(this.currentTheme);
}
initEventListeners() {
const toggle = document.getElementById('luca-chatbot-toggle');
const closeBtn = document.getElementById('luca-close-chatbot');
const themeToggle = document.getElementById('luca-theme-toggle');
const chatForm = document.getElementById('luca-chat-form');
const messageInput = document.getElementById('luca-message-input');
const restartBtn = document.getElementById('luca-restart-chat');
const actionButtons = document.querySelectorAll('.luca-action-button');
// Toggle chatbot
toggle.addEventListener('click', () => this.toggleChatbot());
// Close chatbot
closeBtn.addEventListener('click', () => this.closeChatbot());
// Theme toggle
themeToggle.addEventListener('click', () => this.toggleTheme());
// Send message
chatForm.addEventListener('submit', (e) => {
e.preventDefault();
this.sendMessage();
});
// Auto-resize textarea
messageInput.addEventListener('input', () => {
this.autoResizeTextarea(messageInput);
});
// Restart chat
restartBtn.addEventListener('click', () => this.restartChat());
// Action buttons
actionButtons.forEach(button => {
button.addEventListener('click', () => {
const action = button.getAttribute('data-action');
this.handleActionButton(action, button.textContent.trim());
});
});
// Close on escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && this.isOpen) {
this.closeChatbot();
}
});
}
toggleChatbot() {
if (this.isOpen) {
this.closeChatbot();
} else {
this.openChatbot();
}
}
openChatbot() {
this.container.classList.add('show-chatbot');
this.isOpen = true;
this.scrollToBottom();
// Focus on input
setTimeout(() => {
const input = document.getElementById('luca-message-input');
input.focus();
}, 500);
}
closeChatbot() {
this.container.classList.remove('show-chatbot');
this.isOpen = false;
}
toggleTheme() {
this.currentTheme = this.currentTheme === 'dark' ? 'light' : 'dark';
this.setTheme(this.currentTheme);
}
setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
const themeBtn = document.getElementById('luca-theme-toggle');
themeBtn.textContent = theme === 'dark' ? 'light_mode' : 'dark_mode';
}
sendMessage() {
const input = document.getElementById('luca-message-input');
const message = input.value.trim();
if (!message) return;
// Add user message
this.addMessage(message, 'user');
input.value = '';
this.autoResizeTextarea(input);
// Simulate bot response
setTimeout(() => {
this.addMessage(this.generateResponse(message), 'bot');
}, 1000);
}
addMessage(content, type) {
const chatBody = document.getElementById('luca-chat-body');
const messageDiv = document.createElement('div');
messageDiv.className = `luca-message ${type}-message`;
if (type === 'user') {
messageDiv.innerHTML = `
<div class="luca-message-text">${content}</div>
`;
} else {
messageDiv.innerHTML = `
<img class="luca-bot-avatar" src="https://i.imgur.com/rAOFxqL.png" alt="Luca" width="35" height="35">
<div class="luca-message-text">${content}</div>
`;
}
chatBody.appendChild(messageDiv);
this.scrollToBottom();
}
handleActionButton(action, buttonText) {
this.addMessage(buttonText, 'user');
setTimeout(() => {
let response = '';
switch(action) {
case 'general':
response = 'Yleisiä kysymyksiä käsittelemme mielellämme! Mitä haluaisit tietää?';
break;
case 'support':
response = 'Teknisessä tuessa olen aina valmis auttamaan. Kerro ongelmasi yksityiskohtaisesti.';
break;
case 'pricing':
response = 'Hinnoittelumme on kilpailukykyinen ja läpinäkyvä. Haluatko tarkempia tietoja?';
break;
default:
response = 'Kiitos kysymyksestäsi! Miten voin auttaa sinua tarkemmin?';
}
this.addMessage(response, 'bot');
}, 1000);
}
generateResponse(message) {
const responses = [
'Kiitos viestistäsi! Miten voin auttaa sinua tarkemmin?',
'Ymmärrän kysymyksesi. Haluatko lisätietoja jostain tietystä aiheesta?',
'Olen täällä auttaakseni! Onko sinulla muita kysymyksiä?',
'Kiitos yhteydenotosta! Miten voin parhaiten palvella sinua?'
];
return responses[Math.floor(Math.random() * responses.length)];
}
restartChat() {
const chatBody = document.getElementById('luca-chat-body');
const actionButtonsContainer = document.getElementById('luca-action-buttons-container');
// Keep only the first bot message
const messages = chatBody.querySelectorAll('.luca-message');
for (let i = 1; i < messages.length; i++) {
messages[i].remove();
}
// Restore action buttons if they were removed
if (!actionButtonsContainer.querySelector('.luca-action-buttons')) {
actionButtonsContainer.innerHTML = `
<div class="luca-action-buttons">
<button class="luca-action-button" data-action="general">
<span class="material-symbols-rounded">help</span>
Yleiset kysymykset
</button>
<button class="luca-action-button" data-action="support">
<span class="material-symbols-rounded">support_agent</span>
Tekninen tuki
</button>
<button class="luca-action-button" data-action="pricing">
<span class="material-symbols-rounded">payments</span>
Hinnoittelu
</button>
</div>
`;
// Re-add event listeners
const actionButtons = actionButtonsContainer.querySelectorAll('.luca-action-button');
actionButtons.forEach(button => {
button.addEventListener('click', () => {
const action = button.getAttribute('data-action');
this.handleActionButton(action, button.textContent.trim());
});
});
}
this.scrollToBottom();
}
autoResizeTextarea(textarea) {
textarea.style.height = 'auto';
textarea.style.height = Math.min(textarea.scrollHeight, 180) + 'px';
}
scrollToBottom() {
const chatBody = document.getElementById('luca-chat-body');
setTimeout(() => {
chatBody.scrollTop = chatBody.scrollHeight;
}, 100);
}
}
// Initialize chatbot when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
new LucaChatbot();
});
} else {
new LucaChatbot();
}
// Expose to global scope for external access
window.LucaChatbot = LucaChatbot;
})();