|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>AI Chat Assistant</title> |
|
<style> |
|
:root { |
|
--primary-color: #2dd4bf; |
|
--secondary-color: #1e293b; |
|
--bg-color: #0f172a; |
|
--text-primary: #f8fafc; |
|
--text-secondary: #94a3b8; |
|
--accent-color: #818cf8; |
|
--border-color: #334155; |
|
--hover-color: #1e293b; |
|
--gradient-1: linear-gradient(135deg, #2dd4bf20, #818cf820); |
|
--gradient-2: linear-gradient(45deg, #2dd4bf, #818cf8); |
|
--glow-shadow: 0 0 20px rgba(45, 212, 191, 0.2); |
|
--message-user-bg: linear-gradient(135deg, #2dd4bf, #818cf8); |
|
--message-ai-bg: rgba(30, 41, 59, 0.5); |
|
--message-user-gradient: linear-gradient(135deg, #2563eb, #1d4ed8); |
|
--message-user-text: #ffffff; |
|
--message-user-shadow: 0 4px 15px rgba(45, 212, 191, 0.2); |
|
} |
|
|
|
body { |
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; |
|
margin: 0; |
|
padding: 0; |
|
background-color: var(--bg-color); |
|
color: var(--text-primary); |
|
display: grid; |
|
grid-template-columns: 260px 1fr; |
|
min-height: 100vh; |
|
background: var(--bg-color); |
|
background-image: |
|
radial-gradient(circle at 10% 20%, rgba(0, 255, 170, 0.05) 0%, transparent 20%), |
|
radial-gradient(circle at 90% 80%, rgba(0, 200, 255, 0.05) 0%, transparent 20%); |
|
transition: all 0.3s ease; |
|
} |
|
|
|
|
|
.sidebar { |
|
background-color: var(--secondary-color); |
|
backdrop-filter: blur(10px); |
|
border-right: 1px solid rgba(255, 255, 255, 0.1); |
|
padding: 16px; |
|
display: flex; |
|
flex-direction: column; |
|
gap: 16px; |
|
animation: slideIn 0.5s ease; |
|
} |
|
|
|
.new-chat-btn { |
|
background: var(--message-user-bg); |
|
color: white; |
|
border: none; |
|
padding: 12px; |
|
border-radius: 12px; |
|
cursor: pointer; |
|
font-weight: 600; |
|
transition: all 0.3s ease; |
|
box-shadow: var(--message-user-shadow); |
|
display: flex; |
|
align-items: center; |
|
gap: 8px; |
|
} |
|
|
|
.new-chat-btn:hover { |
|
transform: translateY(-2px); |
|
box-shadow: 0 6px 20px rgba(45, 212, 191, 0.3); |
|
background: var(--accent-color); |
|
} |
|
|
|
.chat-list { |
|
flex-grow: 1; |
|
overflow-y: auto; |
|
} |
|
|
|
.chat-item { |
|
padding: 10px; |
|
border-radius: 6px; |
|
cursor: pointer; |
|
display: flex; |
|
align-items: center; |
|
justify-content: space-between; |
|
color: var(--text-secondary); |
|
transition: all 0.3s ease; |
|
background: transparent; |
|
border: 1px solid transparent; |
|
} |
|
|
|
.chat-item:hover { |
|
background: var(--hover-color); |
|
border-color: var(--primary-color); |
|
transform: translateX(5px); |
|
} |
|
|
|
.chat-item.active { |
|
background: var(--hover-color); |
|
border-left: 2px solid var(--primary-color); |
|
} |
|
|
|
.delete-chat { |
|
opacity: 0; |
|
transition: opacity 0.2s ease; |
|
color: var(--text-secondary); |
|
background: none; |
|
border: none; |
|
cursor: pointer; |
|
padding: 4px; |
|
} |
|
|
|
.chat-item:hover .delete-chat { |
|
opacity: 1; |
|
} |
|
|
|
|
|
.main-container { |
|
display: flex; |
|
flex-direction: column; |
|
height: 100vh; |
|
} |
|
|
|
.chat-header { |
|
padding: 16px; |
|
border-bottom: 1px solid var(--border-color); |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
position: relative; |
|
background: rgba(26, 31, 44, 0.8); |
|
backdrop-filter: blur(10px); |
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1); |
|
} |
|
|
|
.chat-title { |
|
font-size: 1.1rem; |
|
color: var(--primary-color); |
|
margin: 0; |
|
text-align: center; |
|
font-weight: 500; |
|
max-width: 60%; |
|
overflow: hidden; |
|
text-overflow: ellipsis; |
|
white-space: nowrap; |
|
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); |
|
letter-spacing: 0.5px; |
|
} |
|
|
|
.chat-messages { |
|
flex-grow: 1; |
|
overflow-y: auto; |
|
padding: 20px; |
|
scroll-behavior: smooth; |
|
height: calc(100vh - 140px); |
|
font-size: 16px !important; |
|
} |
|
|
|
.message { |
|
max-width: 80%; |
|
padding: 12px 16px; |
|
margin-bottom: 16px; |
|
font-size: 16px !important; |
|
line-height: 1.5; |
|
border-radius: 18px; |
|
position: relative; |
|
display: inline-flex; |
|
gap: 12px; |
|
align-items: flex-start; |
|
width: fit-content; |
|
} |
|
|
|
.message.user-message { |
|
margin-left: auto; |
|
background: linear-gradient(135deg, #2dd4bf, #0ea5e9); |
|
border-bottom-right-radius: 4px; |
|
flex-direction: row-reverse; |
|
box-shadow: 0 2px 8px rgba(45, 212, 191, 0.2); |
|
float: right; |
|
clear: both; |
|
} |
|
|
|
.message.ai-message { |
|
margin-right: auto; |
|
background: var(--secondary-color); |
|
border-bottom-left-radius: 4px; |
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
|
float: left; |
|
clear: both; |
|
} |
|
|
|
.avatar { |
|
width: 32px; |
|
height: 32px; |
|
border-radius: 50%; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
font-weight: 600; |
|
font-size: 14px; |
|
flex-shrink: 0; |
|
margin-top: 4px; |
|
} |
|
|
|
.user-avatar { |
|
background: white; |
|
color: var(--primary-color); |
|
box-shadow: 0 2px 8px rgba(45, 212, 191, 0.2); |
|
} |
|
|
|
.ai-avatar { |
|
background: white; |
|
color: var(--secondary-color); |
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
.message-content { |
|
font-size: 16px !important; |
|
line-height: 1.5; |
|
padding: 0 4px; |
|
word-wrap: break-word; |
|
white-space: pre-wrap; |
|
} |
|
|
|
.user-message .message-content { |
|
color: white; |
|
text-align: left; |
|
} |
|
|
|
.ai-message .message-content { |
|
color: var(--text-primary); |
|
} |
|
|
|
|
|
.input-container { |
|
padding: 20px; |
|
border-top: 1px solid var(--border-color); |
|
max-width: 900px; |
|
margin: 0 auto; |
|
width: calc(100% - 40px); |
|
position: relative; |
|
} |
|
|
|
.input-wrapper { |
|
display: flex; |
|
gap: 12px; |
|
background: var(--message-ai-bg); |
|
border: 1px solid rgba(45, 212, 191, 0.2); |
|
padding: 12px 16px; |
|
border-radius: 12px; |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.input-wrapper:focus-within { |
|
border-color: var(--primary-color); |
|
box-shadow: 0 0 15px rgba(45, 212, 191, 0.2); |
|
} |
|
|
|
#user-input { |
|
flex-grow: 1; |
|
padding: 8px 0; |
|
border: none; |
|
background: transparent; |
|
font-size: 16px; |
|
color: var(--text-primary); |
|
outline: none; |
|
resize: none; |
|
min-height: 24px; |
|
max-height: 200px; |
|
line-height: 1.5; |
|
} |
|
|
|
.send-button { |
|
background: var(--message-user-bg); |
|
border: none; |
|
border-radius: 8px; |
|
width: 32px; |
|
height: 32px; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
cursor: pointer; |
|
transition: all 0.3s ease; |
|
padding: 0; |
|
margin: auto 0; |
|
box-shadow: var(--message-user-shadow); |
|
} |
|
|
|
.send-button:hover { |
|
transform: translateY(-2px) scale(1.05); |
|
box-shadow: 0 6px 20px rgba(45, 212, 191, 0.3); |
|
background: var(--accent-color); |
|
} |
|
|
|
.send-button:active { |
|
transform: translateY(0); |
|
} |
|
|
|
.send-button svg { |
|
width: 16px; |
|
height: 16px; |
|
stroke: white; |
|
} |
|
|
|
.send-button.disabled { |
|
background-color: var(--text-secondary); |
|
cursor: not-allowed; |
|
opacity: 0.5; |
|
} |
|
|
|
|
|
|
|
|
|
.message .code-block { |
|
position: relative; |
|
background: #1e1e1e; |
|
border-radius: 8px; |
|
margin: 12px 0; |
|
font-family: 'Fira Code', 'Consolas', monospace; |
|
border: 1px solid rgba(255, 255, 255, 0.1); |
|
} |
|
|
|
.code-block pre { |
|
margin: 0; |
|
padding: 16px; |
|
padding-top: 32px; |
|
overflow-x: auto; |
|
color: #e0e0e0; |
|
font-size: 14px; |
|
line-height: 1.5; |
|
} |
|
|
|
.code-block .copy-button { |
|
position: absolute; |
|
top: 8px; |
|
right: 8px; |
|
background: rgba(255, 255, 255, 0.1); |
|
color: #fff; |
|
border: none; |
|
border-radius: 4px; |
|
padding: 4px 8px; |
|
font-size: 12px; |
|
cursor: pointer; |
|
display: flex; |
|
align-items: center; |
|
gap: 4px; |
|
transition: all 0.2s ease; |
|
opacity: 0; |
|
} |
|
|
|
.code-block:hover .copy-button { |
|
opacity: 1; |
|
} |
|
|
|
.code-block .copy-button:hover { |
|
background: rgba(255, 255, 255, 0.2); |
|
} |
|
|
|
.code-block .copy-button svg { |
|
width: 14px; |
|
height: 14px; |
|
} |
|
|
|
.code-block .language-label { |
|
position: absolute; |
|
top: 8px; |
|
left: 8px; |
|
color: #888; |
|
font-size: 12px; |
|
font-family: 'Inter', sans-serif; |
|
} |
|
|
|
|
|
.code-block .keyword { color: #569CD6; } |
|
.code-block .string { color: #CE9178; } |
|
.code-block .comment { color: #6A9955; } |
|
.code-block .number { color: #B5CEA8; } |
|
.code-block .function { color: #DCDCAA; } |
|
.code-block .operator { color: #D4D4D4; } |
|
.code-block .class { color: #4EC9B0; } |
|
.code-block .property { color: #9CDCFE; } |
|
|
|
|
|
.thinking { |
|
display: flex; |
|
align-items: center; |
|
gap: 12px; |
|
} |
|
|
|
.loading-dots { |
|
display: flex; |
|
gap: 4px; |
|
} |
|
|
|
.loading-dots span { |
|
width: 8px; |
|
height: 8px; |
|
border-radius: 50%; |
|
background: var(--primary-color); |
|
animation: pulse 1.5s infinite ease-in-out; |
|
} |
|
|
|
.loading-dots span:nth-child(2) { animation-delay: 0.2s; } |
|
.loading-dots span:nth-child(3) { animation-delay: 0.4s; } |
|
|
|
@keyframes pulse { |
|
0%, 100% { transform: scale(0.5); opacity: 0.5; } |
|
50% { transform: scale(1); opacity: 1; } |
|
} |
|
|
|
|
|
::-webkit-scrollbar { |
|
width: 6px; |
|
} |
|
|
|
::-webkit-scrollbar-track { |
|
background: transparent; |
|
} |
|
|
|
::-webkit-scrollbar-thumb { |
|
background: var(--primary-color); |
|
border-radius: 3px; |
|
} |
|
|
|
|
|
@keyframes slideIn { |
|
from { |
|
transform: translateX(-100%); |
|
opacity: 0; |
|
} |
|
to { |
|
transform: translateX(0); |
|
opacity: 1; |
|
} |
|
} |
|
|
|
@keyframes messageSlide { |
|
from { |
|
transform: translateY(20px); |
|
opacity: 0; |
|
} |
|
to { |
|
transform: translateY(0); |
|
opacity: 1; |
|
} |
|
} |
|
|
|
|
|
.message { |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
.message.user-message::after { |
|
content: ''; |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
bottom: 0; |
|
background: linear-gradient( |
|
45deg, |
|
transparent, |
|
rgba(45, 212, 191, 0.1), |
|
transparent |
|
); |
|
animation: shine 2s infinite; |
|
} |
|
|
|
@keyframes shine { |
|
0% { |
|
transform: translateX(-100%) translateY(-100%); |
|
} |
|
50%, 100% { |
|
transform: translateX(100%) translateY(100%); |
|
} |
|
} |
|
|
|
|
|
.avatar:hover { |
|
transform: scale(1.05); |
|
transition: transform 0.2s ease; |
|
} |
|
|
|
|
|
.scroll-button { |
|
position: fixed; |
|
right: 30px; |
|
width: 45px; |
|
height: 45px; |
|
border-radius: 50%; |
|
background: #2dd4bf; |
|
color: white; |
|
border: none; |
|
cursor: pointer; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
opacity: 0; |
|
visibility: hidden; |
|
transition: opacity 0.3s; |
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
.scroll-button.visible { |
|
opacity: 1; |
|
visibility: visible; |
|
} |
|
|
|
.scroll-top-button { |
|
bottom: 100px; |
|
} |
|
|
|
.scroll-bottom-button { |
|
bottom: 40px; |
|
} |
|
|
|
|
|
.scroll-button::after { |
|
content: ''; |
|
position: absolute; |
|
width: 100%; |
|
height: 100%; |
|
border-radius: 50%; |
|
background: inherit; |
|
filter: blur(8px); |
|
opacity: 0; |
|
transition: opacity 0.3s ease; |
|
z-index: -1; |
|
} |
|
|
|
.scroll-button:hover::after { |
|
opacity: 0.5; |
|
} |
|
|
|
|
|
.chat-messages { |
|
scroll-behavior: smooth; |
|
} |
|
|
|
|
|
@keyframes messageAppear { |
|
from { |
|
opacity: 0; |
|
transform: translateY(10px); |
|
} |
|
to { |
|
opacity: 1; |
|
transform: translateY(0); |
|
} |
|
} |
|
|
|
.message { |
|
animation: messageAppear 0.3s ease-out; |
|
} |
|
|
|
|
|
.chat-messages::after { |
|
content: ''; |
|
display: table; |
|
clear: both; |
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
body { |
|
grid-template-columns: 1fr; |
|
} |
|
|
|
.sidebar { |
|
position: fixed; |
|
left: -100%; |
|
top: 0; |
|
bottom: 0; |
|
width: 280px; |
|
z-index: 1000; |
|
transition: left 0.3s ease; |
|
padding: 12px; |
|
background: var(--secondary-color); |
|
backdrop-filter: blur(10px); |
|
box-shadow: none; |
|
} |
|
|
|
.sidebar.active { |
|
left: 0; |
|
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3); |
|
} |
|
|
|
.menu-button { |
|
position: fixed; |
|
left: 15px; |
|
top: 15px; |
|
z-index: 1001; |
|
background: var(--primary-color); |
|
border: none; |
|
border-radius: 8px; |
|
width: 36px; |
|
height: 36px; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
cursor: pointer; |
|
color: white; |
|
} |
|
|
|
.chat-header { |
|
padding: 15px 70px; |
|
height: 50px; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
} |
|
|
|
.chat-title { |
|
font-size: 16px; |
|
max-width: 80%; |
|
} |
|
|
|
.main-container { |
|
padding-top: 0; |
|
height: 100vh; |
|
margin-left: 0; |
|
width: 100%; |
|
position: relative; |
|
z-index: 1; |
|
} |
|
|
|
.message { |
|
max-width: 90%; |
|
padding: 10px 12px; |
|
} |
|
|
|
.input-container { |
|
padding: 12px; |
|
width: calc(100% - 24px); |
|
} |
|
|
|
.scroll-button { |
|
right: 10px; |
|
width: 40px; |
|
height: 40px; |
|
} |
|
|
|
|
|
.code-block { |
|
max-width: 100%; |
|
overflow-x: auto; |
|
} |
|
|
|
.code-block pre { |
|
padding: 12px; |
|
font-size: 12px; |
|
} |
|
|
|
.chat-list { |
|
padding-bottom: 20px; |
|
height: calc(100vh - 80px); |
|
overflow-y: auto; |
|
} |
|
|
|
.chat-item { |
|
padding: 12px 10px; |
|
font-size: 14px; |
|
margin-bottom: 4px; |
|
} |
|
|
|
.chat-item span { |
|
max-width: 200px; |
|
overflow: hidden; |
|
text-overflow: ellipsis; |
|
white-space: nowrap; |
|
} |
|
|
|
|
|
.new-chat-btn { |
|
margin: 0 0 12px 0; |
|
width: calc(100% - 24px); |
|
padding: 12px; |
|
font-size: 14px; |
|
} |
|
} |
|
|
|
|
|
.overlay { |
|
display: none; |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
bottom: 0; |
|
background: rgba(0, 0, 0, 0.5); |
|
z-index: 999; |
|
} |
|
|
|
.overlay.active { |
|
display: block; |
|
} |
|
|
|
|
|
body { |
|
background: linear-gradient(135deg, #0f172a 0%, #1e1b4b 100%); |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
|
|
.background-effects { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
bottom: 0; |
|
z-index: 0; |
|
pointer-events: none; |
|
} |
|
|
|
.background-effects::before, |
|
.background-effects::after { |
|
content: ''; |
|
position: absolute; |
|
width: 300px; |
|
height: 300px; |
|
border-radius: 50%; |
|
filter: blur(100px); |
|
opacity: 0.15; |
|
animation: floatAround 20s infinite ease-in-out; |
|
} |
|
|
|
.background-effects::before { |
|
background: #00ffaa; |
|
top: -150px; |
|
left: -150px; |
|
} |
|
|
|
.background-effects::after { |
|
background: #00c8ff; |
|
bottom: -150px; |
|
right: -150px; |
|
animation-delay: -10s; |
|
} |
|
|
|
@keyframes floatAround { |
|
0%, 100% { transform: translate(0, 0); } |
|
25% { transform: translate(100px, 100px); } |
|
50% { transform: translate(0, 200px); } |
|
75% { transform: translate(-100px, 100px); } |
|
} |
|
|
|
|
|
.welcome-message { |
|
background: rgba(255, 255, 255, 0.05); |
|
border-radius: 12px; |
|
padding: 20px; |
|
margin: 10px 20px 24px 20px; |
|
backdrop-filter: blur(10px); |
|
border: 1px solid rgba(255, 255, 255, 0.1); |
|
animation: fadeIn 0.5s ease-out; |
|
max-width: calc(100% - 40px); |
|
} |
|
|
|
.welcome-message h3 { |
|
color: var(--primary-color); |
|
margin: 0 0 12px 0; |
|
font-size: 1.2rem; |
|
} |
|
|
|
.welcome-message p { |
|
margin: 0 0 16px 0; |
|
line-height: 1.5; |
|
font-size: 0.95rem; |
|
} |
|
|
|
.quick-actions { |
|
display: flex; |
|
gap: 8px; |
|
flex-wrap: wrap; |
|
margin-top: 16px; |
|
} |
|
|
|
.quick-action-btn { |
|
background: rgba(255, 255, 255, 0.1); |
|
border: none; |
|
padding: 8px 16px; |
|
border-radius: 20px; |
|
color: var(--text-primary); |
|
cursor: pointer; |
|
transition: all 0.3s ease; |
|
font-size: 14px; |
|
white-space: nowrap; |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
.quick-action-btn:hover { |
|
background: var(--primary-color); |
|
transform: translateY(-2px); |
|
box-shadow: 0 4px 12px rgba(45, 212, 191, 0.3); |
|
} |
|
|
|
.quick-action-btn:active { |
|
transform: translateY(0); |
|
} |
|
|
|
|
|
.quick-action-btn::after { |
|
content: ''; |
|
position: absolute; |
|
width: 100%; |
|
height: 100%; |
|
top: 0; |
|
left: 0; |
|
pointer-events: none; |
|
background-image: radial-gradient(circle, #fff 10%, transparent 10.01%); |
|
background-repeat: no-repeat; |
|
background-position: 50%; |
|
transform: scale(10, 10); |
|
opacity: 0; |
|
transition: transform .5s, opacity 1s; |
|
} |
|
|
|
.quick-action-btn:active::after { |
|
transform: scale(0, 0); |
|
opacity: .3; |
|
transition: 0s; |
|
} |
|
|
|
|
|
.quick-action-btn:hover::before { |
|
content: ''; |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
bottom: 0; |
|
border-radius: 20px; |
|
background: var(--primary-color); |
|
z-index: -1; |
|
filter: blur(8px); |
|
opacity: 0.5; |
|
transition: opacity 0.3s ease; |
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
.quick-action-btn { |
|
padding: 10px 16px; |
|
} |
|
|
|
.quick-action-btn:active { |
|
background: var(--primary-color); |
|
transform: scale(0.98); |
|
} |
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
.welcome-message { |
|
margin: 10px 10px 20px 10px; |
|
padding: 15px; |
|
max-width: calc(100% - 20px); |
|
} |
|
|
|
.welcome-message h3 { |
|
font-size: 1.1rem; |
|
margin-bottom: 10px; |
|
} |
|
|
|
.welcome-message p { |
|
font-size: 0.9rem; |
|
margin-bottom: 12px; |
|
} |
|
|
|
.quick-actions { |
|
gap: 6px; |
|
margin-top: 12px; |
|
} |
|
|
|
.quick-action-btn { |
|
padding: 6px 12px; |
|
font-size: 13px; |
|
flex: 1 1 calc(50% - 6px); |
|
text-align: center; |
|
min-width: calc(50% - 6px); |
|
max-width: calc(50% - 6px); |
|
} |
|
} |
|
|
|
|
|
@keyframes fadeIn { |
|
from { |
|
opacity: 0; |
|
transform: translateY(10px); |
|
} |
|
to { |
|
opacity: 1; |
|
transform: translateY(0); |
|
} |
|
} |
|
|
|
|
|
.input-container { |
|
position: relative; |
|
backdrop-filter: blur(10px); |
|
} |
|
|
|
.input-wrapper { |
|
position: relative; |
|
} |
|
|
|
.input-actions { |
|
position: absolute; |
|
right: 50px; |
|
top: 50%; |
|
transform: translateY(-50%); |
|
display: flex; |
|
gap: 8px; |
|
} |
|
|
|
.input-action-btn { |
|
background: none; |
|
border: none; |
|
color: var(--text-secondary); |
|
cursor: pointer; |
|
padding: 4px; |
|
transition: all 0.2s ease; |
|
} |
|
|
|
.input-action-btn:hover { |
|
color: var(--primary-color); |
|
} |
|
|
|
|
|
.settings-button { |
|
position: absolute; |
|
right: 20px; |
|
top: 50%; |
|
transform: translateY(-50%); |
|
width: 40px; |
|
height: 40px; |
|
border-radius: 10px; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
cursor: pointer; |
|
color: var(--text-secondary); |
|
transition: all 0.3s ease; |
|
background: rgba(255, 255, 255, 0.1); |
|
} |
|
|
|
.settings-button:hover { |
|
background: var(--primary-color); |
|
color: white; |
|
transform: translateY(-50%) scale(1.05); |
|
} |
|
|
|
|
|
.settings-modal { |
|
display: none; |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
bottom: 0; |
|
background: rgba(0, 0, 0, 0.5); |
|
z-index: 1000; |
|
backdrop-filter: blur(5px); |
|
} |
|
|
|
.settings-modal.active { |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
} |
|
|
|
.settings-content { |
|
background: var(--secondary-color); |
|
border-radius: 12px; |
|
width: 90%; |
|
max-width: 500px; |
|
position: relative; |
|
animation: modalSlide 0.3s ease; |
|
} |
|
|
|
.settings-header { |
|
padding: 20px; |
|
border-bottom: 1px solid var(--border-color); |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
} |
|
|
|
.settings-header h2 { |
|
margin: 0; |
|
color: var(--text-primary); |
|
} |
|
|
|
.close-settings { |
|
background: none; |
|
border: none; |
|
color: var(--text-secondary); |
|
font-size: 24px; |
|
cursor: pointer; |
|
padding: 0; |
|
} |
|
|
|
.settings-body { |
|
padding: 20px; |
|
} |
|
|
|
.settings-section { |
|
margin-bottom: 24px; |
|
} |
|
|
|
.settings-section h3 { |
|
margin: 0 0 12px 0; |
|
color: var(--text-primary); |
|
} |
|
|
|
.theme-options { |
|
display: flex; |
|
gap: 8px; |
|
} |
|
|
|
.theme-btn { |
|
padding: 8px 16px; |
|
border-radius: 8px; |
|
border: 1px solid var(--border-color); |
|
background: transparent; |
|
color: var(--text-primary); |
|
cursor: pointer; |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.theme-btn.active { |
|
background: var(--primary-color); |
|
border-color: var(--primary-color); |
|
} |
|
|
|
.language-select { |
|
width: 100%; |
|
padding: 8px; |
|
border-radius: 8px; |
|
background: var(--bg-color); |
|
color: var(--text-primary); |
|
border: 1px solid var(--border-color); |
|
} |
|
|
|
@keyframes modalSlide { |
|
from { |
|
opacity: 0; |
|
transform: translateY(20px); |
|
} |
|
to { |
|
opacity: 1; |
|
transform: translateY(0); |
|
} |
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
.settings-button { |
|
right: 15px; |
|
width: 36px; |
|
height: 36px; |
|
} |
|
|
|
.settings-content { |
|
width: 95%; |
|
margin: 20px; |
|
} |
|
} |
|
|
|
|
|
.landing-page { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
background: linear-gradient(135deg, #0f172a 0%, #1e1b4b 100%); |
|
z-index: 9999; |
|
overflow-y: auto; |
|
transition: opacity 0.5s ease, transform 0.5s ease; |
|
-webkit-overflow-scrolling: touch; |
|
} |
|
|
|
.landing-page.hidden { |
|
opacity: 0; |
|
transform: translateY(-20px); |
|
pointer-events: none; |
|
} |
|
|
|
.landing-container { |
|
max-width: 1200px; |
|
margin: 0 auto; |
|
padding: 40px 20px; |
|
} |
|
|
|
.hero-section { |
|
text-align: center; |
|
padding: 60px 0; |
|
animation: fadeIn 1s ease-out; |
|
} |
|
|
|
.hero-title { |
|
font-size: 3.5rem; |
|
margin-bottom: 20px; |
|
background: linear-gradient(135deg, #2dd4bf, #818cf8); |
|
-webkit-background-clip: text; |
|
background-clip: text; |
|
-webkit-text-fill-color: transparent; |
|
} |
|
|
|
.hero-subtitle { |
|
font-size: 1.2rem; |
|
color: var(--text-secondary); |
|
margin-bottom: 40px; |
|
} |
|
|
|
.features-grid { |
|
display: grid; |
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); |
|
gap: 30px; |
|
padding: 40px 0; |
|
} |
|
|
|
.feature-card { |
|
background: rgba(255, 255, 255, 0.05); |
|
border-radius: 15px; |
|
padding: 30px; |
|
backdrop-filter: blur(10px); |
|
border: 1px solid rgba(255, 255, 255, 0.1); |
|
transition: transform 0.3s ease; |
|
} |
|
|
|
.feature-card:hover { |
|
transform: translateY(-5px); |
|
} |
|
|
|
.feature-icon { |
|
font-size: 2rem; |
|
margin-bottom: 20px; |
|
color: var(--primary-color); |
|
} |
|
|
|
.feature-title { |
|
font-size: 1.5rem; |
|
margin-bottom: 15px; |
|
color: var(--primary-color); |
|
} |
|
|
|
.feature-description { |
|
color: var(--text-secondary); |
|
} |
|
|
|
.cta-button { |
|
display: inline-block; |
|
background: linear-gradient(135deg, #2dd4bf, #818cf8); |
|
color: white; |
|
padding: 15px 40px; |
|
border-radius: 30px; |
|
text-decoration: none; |
|
font-weight: 600; |
|
font-size: 1.1rem; |
|
transition: all 0.3s ease; |
|
border: none; |
|
cursor: pointer; |
|
margin-top: 40px; |
|
} |
|
|
|
.cta-button:hover { |
|
transform: translateY(-2px); |
|
box-shadow: 0 10px 20px rgba(45, 212, 191, 0.2); |
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
.hero-title { |
|
font-size: 2.5rem; |
|
} |
|
|
|
.hero-subtitle { |
|
font-size: 1rem; |
|
padding: 0 20px; |
|
} |
|
|
|
.features-grid { |
|
grid-template-columns: 1fr; |
|
padding: 20px; |
|
} |
|
|
|
.feature-card { |
|
padding: 20px; |
|
} |
|
} |
|
|
|
|
|
.landing-page { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
background: linear-gradient(135deg, #0f172a 0%, #1e1b4b 100%); |
|
z-index: 9999; |
|
overflow-y: auto; |
|
transition: opacity 0.5s ease, transform 0.5s ease; |
|
-webkit-overflow-scrolling: touch; |
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
.landing-container { |
|
padding: 20px 15px; |
|
} |
|
|
|
.hero-section { |
|
padding: 40px 0; |
|
} |
|
|
|
.hero-title { |
|
font-size: 2.2rem; |
|
padding: 0 10px; |
|
margin-bottom: 15px; |
|
} |
|
|
|
.hero-subtitle { |
|
font-size: 1rem; |
|
padding: 0 15px; |
|
margin-bottom: 30px; |
|
} |
|
|
|
.features-grid { |
|
grid-template-columns: 1fr; |
|
gap: 15px; |
|
padding: 20px 0; |
|
} |
|
|
|
.feature-card { |
|
padding: 20px; |
|
margin: 0 10px; |
|
} |
|
|
|
.feature-title { |
|
font-size: 1.2rem; |
|
} |
|
|
|
.feature-description { |
|
font-size: 0.9rem; |
|
} |
|
|
|
.cta-button { |
|
padding: 12px 30px; |
|
font-size: 1rem; |
|
margin-top: 30px; |
|
width: 80%; |
|
max-width: 300px; |
|
} |
|
} |
|
|
|
|
|
@media (max-width: 380px) { |
|
.hero-title { |
|
font-size: 1.8rem; |
|
} |
|
|
|
.feature-card { |
|
padding: 15px; |
|
} |
|
|
|
.cta-button { |
|
padding: 10px 25px; |
|
font-size: 0.9rem; |
|
} |
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
body { |
|
grid-template-columns: 1fr; |
|
} |
|
|
|
.main-container { |
|
width: 100%; |
|
height: 100vh; |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
.chat-messages { |
|
height: calc(100vh - 180px); |
|
padding: 10px; |
|
overflow-y: auto; |
|
-webkit-overflow-scrolling: touch; |
|
position: relative; |
|
margin-bottom: 60px; |
|
} |
|
|
|
.welcome-message { |
|
position: relative; |
|
width: calc(100% - 20px); |
|
margin: 10px auto; |
|
z-index: 1; |
|
} |
|
|
|
.input-container { |
|
position: fixed; |
|
bottom: 0; |
|
left: 0; |
|
right: 0; |
|
background: var(--bg-color); |
|
padding: 10px; |
|
border-top: 1px solid var(--border-color); |
|
z-index: 100; |
|
width: 100%; |
|
max-width: 100%; |
|
margin: 0; |
|
box-sizing: border-box; |
|
} |
|
|
|
.input-wrapper { |
|
max-width: 100%; |
|
margin: 0; |
|
} |
|
|
|
#user-input { |
|
font-size: 16px; |
|
padding: 8px; |
|
} |
|
|
|
.message { |
|
max-width: 85%; |
|
margin-bottom: 10px; |
|
} |
|
|
|
|
|
.scroll-button { |
|
width: 36px; |
|
height: 36px; |
|
right: 10px; |
|
z-index: 101; |
|
} |
|
|
|
.scroll-top-button { |
|
bottom: 80px; |
|
} |
|
|
|
.scroll-bottom-button { |
|
bottom: 130px; |
|
} |
|
|
|
|
|
.chat-header { |
|
padding: 10px; |
|
height: auto; |
|
z-index: 99; |
|
} |
|
|
|
|
|
.quick-actions { |
|
display: grid; |
|
grid-template-columns: repeat(2, 1fr); |
|
gap: 8px; |
|
padding: 0 5px; |
|
} |
|
|
|
.quick-action-btn { |
|
width: 100%; |
|
padding: 8px; |
|
font-size: 14px; |
|
text-align: center; |
|
white-space: normal; |
|
} |
|
} |
|
|
|
|
|
@media (max-width: 380px) { |
|
.chat-messages { |
|
height: calc(100vh - 160px); |
|
} |
|
|
|
.message { |
|
max-width: 90%; |
|
padding: 8px 12px; |
|
} |
|
|
|
.input-container { |
|
padding: 8px; |
|
} |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="landing-page" id="landing-page"> |
|
<div class="landing-container"> |
|
<section class="hero-section"> |
|
<h1 class="hero-title">Welcome to Rxple AI</h1> |
|
<p class="hero-subtitle">Experience the future of AI-powered conversations with our advanced chatbot</p> |
|
</section> |
|
|
|
<div class="features-grid"> |
|
<div class="feature-card"> |
|
<div class="feature-icon">🤖</div> |
|
<h3 class="feature-title">Advanced AI Technology</h3> |
|
<p class="feature-description"> |
|
Powered by state-of-the-art language models, our AI understands context and provides accurate, relevant responses. |
|
</p> |
|
</div> |
|
|
|
<div class="feature-card"> |
|
<div class="feature-icon">💡</div> |
|
<h3 class="feature-title">Smart Assistance</h3> |
|
<p class="feature-description"> |
|
Get help with coding, writing, analysis, and more. Our AI adapts to your needs and learning style. |
|
</p> |
|
</div> |
|
|
|
<div class="feature-card"> |
|
<div class="feature-icon">🔒</div> |
|
<h3 class="feature-title">Secure & Private</h3> |
|
<p class="feature-description"> |
|
Your conversations are private and secure. We prioritize your data protection and privacy. |
|
</p> |
|
</div> |
|
|
|
<div class="feature-card"> |
|
<div class="feature-icon">⚡</div> |
|
<h3 class="feature-title">Real-time Responses</h3> |
|
<p class="feature-description"> |
|
Get instant answers to your questions with our lightning-fast response system. |
|
</p> |
|
</div> |
|
|
|
<div class="feature-card"> |
|
<div class="feature-icon">📱</div> |
|
<h3 class="feature-title">Mobile Friendly</h3> |
|
<p class="feature-description"> |
|
Access our AI assistant from any device with a seamless, responsive design. |
|
</p> |
|
</div> |
|
|
|
<div class="feature-card"> |
|
<div class="feature-icon">🔄</div> |
|
<h3 class="feature-title">Continuous Learning</h3> |
|
<p class="feature-description"> |
|
Our AI constantly improves and updates its knowledge to provide better assistance. |
|
</p> |
|
</div> |
|
</div> |
|
|
|
<section class="hero-section"> |
|
<button class="cta-button" onclick="startChat()">Start Chatting with AI</button> |
|
</section> |
|
</div> |
|
</div> |
|
|
|
<aside class="sidebar"> |
|
<button class="new-chat-btn" onclick="createNewChat()"> |
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
<line x1="12" y1="5" x2="12" y2="19"></line> |
|
<line x1="5" y1="12" x2="19" y2="12"></line> |
|
</svg> |
|
New Chat |
|
</button> |
|
<div class="chat-list" id="chat-list"> |
|
|
|
</div> |
|
</aside> |
|
|
|
<main class="main-container"> |
|
<div class="chat-header"> |
|
<div class="settings-button" id="settings-button" title="Settings"> |
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
<path d="M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/> |
|
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/> |
|
</svg> |
|
</div> |
|
<h1 class="chat-title" id="current-chat-title">New Chat</h1> |
|
</div> |
|
<div class="chat-messages" id="chat-messages"></div> |
|
|
|
<button id="scroll-top" class="scroll-button scroll-top-button" title="Scroll to top"> |
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
<path d="M18 15l-6-6-6 6"/> |
|
</svg> |
|
</button> |
|
|
|
<button id="scroll-bottom" class="scroll-button scroll-bottom-button" title="Scroll to bottom"> |
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
<path d="M6 9l6 6 6-6"/> |
|
</svg> |
|
</button> |
|
|
|
<div class="input-container"> |
|
<div class="input-wrapper"> |
|
<input |
|
type="text" |
|
id="user-input" |
|
placeholder="Send a message..." |
|
autocomplete="off" |
|
autofocus |
|
> |
|
<button class="send-button" id="send-button" onclick="sendMessage()"> |
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
<path d="M22 2L11 13M22 2L15 22L11 13L2 9L22 2Z"></path> |
|
</svg> |
|
</button> |
|
</div> |
|
</div> |
|
</main> |
|
|
|
<button class="menu-button" id="menu-button" style="display: none;"> |
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
<line x1="3" y1="12" x2="21" y2="12"></line> |
|
<line x1="3" y1="6" x2="21" y2="6"></line> |
|
<line x1="3" y1="18" x2="21" y2="18"></line> |
|
</svg> |
|
</button> |
|
|
|
<div class="overlay" id="overlay"></div> |
|
|
|
<div class="background-effects"></div> |
|
|
|
<div class="welcome-message"> |
|
<h3>👋 Welcome to AI Chat Assistant</h3> |
|
<p>I'm here to help you with any questions or tasks. Here are some things I can do:</p> |
|
<div class="quick-actions"> |
|
<button class="quick-action-btn" onclick="sendQuickAction('Tell me a joke')">Tell me a joke</button> |
|
<button class="quick-action-btn" onclick="sendQuickAction('Write a poem')">Write a poem</button> |
|
<button class="quick-action-btn" onclick="sendQuickAction('Explain quantum physics')">Explain quantum physics</button> |
|
<button class="quick-action-btn" onclick="sendQuickAction('Help with coding')">Help with coding</button> |
|
</div> |
|
</div> |
|
|
|
<div class="settings-modal" id="settings-modal"> |
|
<div class="settings-content"> |
|
<div class="settings-header"> |
|
<h2>Settings</h2> |
|
<button class="close-settings">×</button> |
|
</div> |
|
<div class="settings-body"> |
|
<div class="settings-section"> |
|
<h3>Theme</h3> |
|
<div class="theme-options"> |
|
<button class="theme-btn active" data-theme="dark">Dark</button> |
|
<button class="theme-btn" data-theme="light">Light</button> |
|
<button class="theme-btn" data-theme="system">System</button> |
|
</div> |
|
</div> |
|
<div class="settings-section"> |
|
<h3>Language</h3> |
|
<select class="language-select"> |
|
<option value="en">English</option> |
|
<option value="es">Español</option> |
|
<option value="fr">Français</option> |
|
</select> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
|
|
const MISTRAL_API_KEY = 'UgKksYvcKnoxvJ13q5UBjL3AdU8Mu1DQ'; |
|
const chatMessages = document.getElementById('chat-messages'); |
|
const userInput = document.getElementById('user-input'); |
|
const sendButton = document.getElementById('send-button'); |
|
const scrollTopBtn = document.getElementById('scroll-top'); |
|
const scrollBottomBtn = document.getElementById('scroll-bottom'); |
|
let lastScrollTop = 0; |
|
let scrollCount = 0; |
|
let scrollTimeout; |
|
let chats = []; |
|
let currentChatId = null; |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
initializeScrollButtons(); |
|
|
|
|
|
if (chats.length === 0) { |
|
createNewChat(); |
|
} |
|
|
|
|
|
userInput.addEventListener('keypress', (e) => { |
|
if (e.key === 'Enter' && !e.shiftKey) { |
|
e.preventDefault(); |
|
sendMessage(); |
|
} |
|
}); |
|
|
|
userInput.addEventListener('input', () => { |
|
const isEmpty = userInput.value.trim() === ''; |
|
sendButton.classList.toggle('disabled', isEmpty); |
|
}); |
|
|
|
|
|
sendButton.classList.add('disabled'); |
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function addMessage(text, sender, save = true) { |
|
const messageDiv = document.createElement('div'); |
|
messageDiv.className = `message ${sender}-message`; |
|
|
|
const avatar = document.createElement('div'); |
|
avatar.className = `avatar ${sender}-avatar`; |
|
avatar.textContent = sender === 'user' ? 'U' : 'AI'; |
|
|
|
const content = document.createElement('div'); |
|
content.className = 'message-content'; |
|
|
|
if (text === 'Thinking...') { |
|
content.innerHTML = ` |
|
<div class="thinking"> |
|
<span>Thinking</span> |
|
<div class="loading-dots"> |
|
<span></span> |
|
<span></span> |
|
<span></span> |
|
</div> |
|
</div>`; |
|
} else { |
|
content.innerHTML = formatMessage(text); |
|
|
|
|
|
content.querySelectorAll('.copy-button').forEach(button => { |
|
button.addEventListener('click', handleCopyClick); |
|
}); |
|
} |
|
|
|
messageDiv.appendChild(avatar); |
|
messageDiv.appendChild(content); |
|
|
|
const id = Date.now(); |
|
messageDiv.id = `message-${id}`; |
|
|
|
chatMessages.appendChild(messageDiv); |
|
|
|
|
|
if (save && currentChatId) { |
|
const chat = chats.find(c => c.id === currentChatId); |
|
if (chat) { |
|
chat.messages.push({ content: text, sender }); |
|
|
|
if (chat.title === 'New Chat' && sender === 'user') { |
|
const title = text.slice(0, 30) + (text.length > 30 ? '...' : ''); |
|
updateChatTitle(title); |
|
} |
|
} |
|
} |
|
|
|
|
|
const shouldScroll = chatMessages.scrollTop + chatMessages.clientHeight >= chatMessages.scrollHeight - 100; |
|
|
|
|
|
setTimeout(() => { |
|
if (shouldScroll) { |
|
chatMessages.scrollTo({ |
|
top: chatMessages.scrollHeight, |
|
behavior: 'smooth' |
|
}); |
|
} |
|
handleScroll(); |
|
}, 100); |
|
|
|
|
|
setTimeout(() => { |
|
chatMessages.scrollTop = chatMessages.scrollHeight; |
|
}, 100); |
|
|
|
return id; |
|
} |
|
|
|
function formatMessage(text) { |
|
const codeBlockRegex = /```(\w*)\n([\s\S]*?)```/g; |
|
let formattedText = text; |
|
|
|
|
|
formattedText = formattedText.replace(codeBlockRegex, (match, language, code) => { |
|
const highlightedCode = highlightSyntax(code.trim(), language); |
|
return ` |
|
<div class="code-block" data-language="${language || 'plaintext'}"> |
|
<span class="language-label">${language || 'plaintext'}</span> |
|
<pre><code>${highlightedCode}</code></pre> |
|
<button class="copy-button" data-code="${encodeURIComponent(code.trim())}"> |
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
<path d="M8 4v12a2 2 0 002 2h8a2 2 0 002-2V7.242a2 2 0 00-.602-1.43L16.083 2.57A2 2 0 0014.685 2H10a2 2 0 00-2 2z"/> |
|
<path d="M16 18v2a2 2 0 01-2 2H6a2 2 0 01-2-2V9a2 2 0 012-2h2"/> |
|
</svg> |
|
Copy |
|
</button> |
|
</div> |
|
`; |
|
}); |
|
|
|
return formattedText; |
|
} |
|
|
|
function highlightSyntax(code, language) { |
|
|
|
return code |
|
.replace(/&/g, '&') |
|
.replace(/</g, '<') |
|
.replace(/>/g, '>') |
|
|
|
.replace(/\b(function|const|let|var|if|else|return|class|import|export|default|new|this|for|while|break|continue)\b/g, '<span class="keyword">$1</span>') |
|
|
|
.replace(/(".*?"|'.*?'|`.*?`)/g, '<span class="string">$1</span>') |
|
|
|
.replace(/(\/\/.*|\/\*[\s\S]*?\*\/)/g, '<span class="comment">$1</span>') |
|
|
|
.replace(/\b(\d+)\b/g, '<span class="number">$1</span>') |
|
|
|
.replace(/(\w+)\(/g, '<span class="function">$1</span>(') |
|
|
|
.replace(/\b([A-Z]\w*)\b/g, '<span class="class">$1</span>') |
|
|
|
.replace(/\.(\w+)\b/g, '.<span class="property">$1</span>'); |
|
} |
|
|
|
function handleCopyClick(event) { |
|
const button = event.target.closest('.copy-button'); |
|
if (!button) return; |
|
|
|
const code = decodeURIComponent(button.dataset.code); |
|
|
|
navigator.clipboard.writeText(code).then(() => { |
|
const originalText = button.innerHTML; |
|
button.innerHTML = ` |
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
<path d="M20 6L9 17l-5-5"/> |
|
</svg> |
|
Copied! |
|
`; |
|
button.style.background = '#10B981'; |
|
|
|
setTimeout(() => { |
|
button.innerHTML = originalText; |
|
button.style.background = ''; |
|
}, 2000); |
|
}).catch(err => { |
|
console.error('Failed to copy:', err); |
|
button.textContent = 'Failed'; |
|
}); |
|
} |
|
|
|
async function sendMessage() { |
|
const message = userInput.value.trim(); |
|
if (!message) return; |
|
|
|
try { |
|
addMessage(message, 'user'); |
|
userInput.value = ''; |
|
scrollToBottom(true); |
|
|
|
const loadingId = addMessage('Thinking...', 'ai'); |
|
scrollToBottom(true); |
|
|
|
const response = await fetch('https://api.mistral.ai/v1/chat/completions', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
'Authorization': `Bearer ${MISTRAL_API_KEY}`, |
|
'Accept': 'application/json' |
|
}, |
|
body: JSON.stringify({ |
|
model: "mistral-small", |
|
messages: [ |
|
{ |
|
role: "system", |
|
content: "You are a helpful AI assistant. Provide clear and concise responses." |
|
}, |
|
{ |
|
role: "user", |
|
content: message |
|
} |
|
], |
|
max_tokens: 1000, |
|
temperature: 0.7 |
|
}) |
|
}); |
|
|
|
if (!response.ok) { |
|
const errorData = await response.json().catch(() => ({})); |
|
throw new Error( |
|
`API Error (${response.status}): ${errorData.error?.message || 'Unknown error'}` |
|
); |
|
} |
|
|
|
const data = await response.json(); |
|
removeMessage(loadingId); |
|
|
|
if (data.choices && data.choices[0] && data.choices[0].message) { |
|
removeMessage(loadingId); |
|
addMessage(data.choices[0].message.content, 'ai'); |
|
scrollToBottom(); |
|
} else { |
|
console.error('Unexpected API response:', data); |
|
addMessage('Sorry, I received an unexpected response format.', 'ai'); |
|
scrollToBottom(); |
|
} |
|
} catch (error) { |
|
console.error('Error details:', error); |
|
removeMessage(loadingId); |
|
addMessage(`Sorry, I encountered an error: ${error.message}`, 'ai'); |
|
scrollToBottom(); |
|
} finally { |
|
userInput.disabled = false; |
|
sendButton.classList.remove('disabled'); |
|
userInput.focus(); |
|
} |
|
} |
|
|
|
function removeMessage(id) { |
|
const message = document.getElementById(`message-${id}`); |
|
if (message) { |
|
message.remove(); |
|
} |
|
} |
|
|
|
function initializeScrollButtons() { |
|
const scrollTopBtn = document.getElementById('scroll-top'); |
|
const scrollBottomBtn = document.getElementById('scroll-bottom'); |
|
const chatMessages = document.getElementById('chat-messages'); |
|
|
|
chatMessages.addEventListener('scroll', () => { |
|
|
|
if (chatMessages.scrollTop > 500) { |
|
scrollTopBtn.classList.add('visible'); |
|
} else { |
|
scrollTopBtn.classList.remove('visible'); |
|
} |
|
|
|
|
|
const isAtBottom = chatMessages.scrollHeight - chatMessages.scrollTop - chatMessages.clientHeight < 100; |
|
if (!isAtBottom) { |
|
scrollBottomBtn.classList.add('visible'); |
|
} else { |
|
scrollBottomBtn.classList.remove('visible'); |
|
} |
|
}); |
|
|
|
|
|
scrollTopBtn.addEventListener('click', () => { |
|
chatMessages.scrollTo({ top: 0, behavior: 'smooth' }); |
|
}); |
|
|
|
|
|
scrollBottomBtn.addEventListener('click', () => { |
|
chatMessages.scrollTo({ top: chatMessages.scrollHeight, behavior: 'smooth' }); |
|
}); |
|
} |
|
|
|
function handleScroll() { |
|
const scrollTop = chatMessages.scrollTop; |
|
const scrollHeight = chatMessages.scrollHeight; |
|
const clientHeight = chatMessages.clientHeight; |
|
|
|
if (scrollTop > 100) { |
|
scrollTopBtn.classList.add('visible'); |
|
} else { |
|
scrollTopBtn.classList.remove('visible'); |
|
} |
|
|
|
if (scrollTop < lastScrollTop) { |
|
scrollCount++; |
|
if (scrollCount >= 2) { |
|
scrollBottomBtn.classList.add('visible'); |
|
} |
|
} else { |
|
scrollCount = 0; |
|
scrollBottomBtn.classList.remove('visible'); |
|
} |
|
|
|
clearTimeout(scrollTimeout); |
|
scrollTimeout = setTimeout(() => { |
|
scrollCount = 0; |
|
}, 1000); |
|
|
|
lastScrollTop = scrollTop; |
|
|
|
if (scrollHeight - scrollTop - clientHeight < 20) { |
|
scrollBottomBtn.classList.remove('visible'); |
|
} |
|
} |
|
|
|
function scrollToTop() { |
|
chatMessages.scrollTo({ |
|
top: 0, |
|
behavior: 'smooth' |
|
}); |
|
} |
|
|
|
function scrollToBottom(immediate = false) { |
|
const chatMessages = document.getElementById('chat-messages'); |
|
if (chatMessages) { |
|
const scrollOptions = { |
|
top: chatMessages.scrollHeight, |
|
behavior: immediate ? 'auto' : 'smooth' |
|
}; |
|
|
|
|
|
if (chatMessages.scrollTo) { |
|
chatMessages.scrollTo(scrollOptions); |
|
} else { |
|
chatMessages.scrollTop = chatMessages.scrollHeight; |
|
} |
|
} |
|
} |
|
|
|
|
|
createNewChat(); |
|
|
|
function createNewChat() { |
|
const chatId = Date.now(); |
|
const chat = { |
|
id: chatId, |
|
title: 'New Chat', |
|
messages: [] |
|
}; |
|
|
|
chats.push(chat); |
|
currentChatId = chatId; |
|
|
|
|
|
clearMessages(); |
|
|
|
|
|
updateChatList(); |
|
updateChatTitle('New Chat'); |
|
|
|
|
|
const welcomeMessage = document.createElement('div'); |
|
welcomeMessage.className = 'welcome-message'; |
|
welcomeMessage.innerHTML = ` |
|
<h3>👋 Welcome to Rxple AI Chat Assistant</h3> |
|
<p>I'm here to help you with any questions or tasks. Here are some things I can do:</p> |
|
<div class="quick-actions"> |
|
<button class="quick-action-btn" onclick="sendQuickAction('Tell me a joke')">Tell me a joke</button> |
|
<button class="quick-action-btn" onclick="sendQuickAction('Write a poem')">Write a poem</button> |
|
<button class="quick-action-btn" onclick="sendQuickAction('Explain quantum physics')">Explain quantum physics</button> |
|
<button class="quick-action-btn" onclick="sendQuickAction('Help with coding')">Help with coding</button> |
|
</div> |
|
`; |
|
chatMessages.appendChild(welcomeMessage); |
|
} |
|
|
|
function updateChatList() { |
|
const chatList = document.getElementById('chat-list'); |
|
chatList.innerHTML = ''; |
|
|
|
chats.forEach(chat => { |
|
const chatItem = document.createElement('div'); |
|
chatItem.className = `chat-item ${chat.id === currentChatId ? 'active' : ''}`; |
|
chatItem.innerHTML = ` |
|
<span>${chat.title}</span> |
|
<button class="delete-chat" onclick="deleteChat(${chat.id})"> |
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
<path d="M3 6h18"></path> |
|
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path> |
|
<path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path> |
|
</svg> |
|
</button> |
|
`; |
|
chatItem.onclick = (e) => { |
|
if (!e.target.closest('.delete-chat')) { |
|
switchChat(chat.id); |
|
} |
|
}; |
|
chatList.appendChild(chatItem); |
|
}); |
|
} |
|
|
|
function deleteChat(chatId) { |
|
if (confirm('Are you sure you want to delete this chat?')) { |
|
chats = chats.filter(chat => chat.id !== chatId); |
|
if (currentChatId === chatId) { |
|
if (chats.length > 0) { |
|
switchChat(chats[0].id); |
|
} else { |
|
createNewChat(); |
|
} |
|
} |
|
updateChatList(); |
|
} |
|
} |
|
|
|
function switchChat(chatId) { |
|
currentChatId = chatId; |
|
const chat = chats.find(c => c.id === chatId); |
|
clearMessages(); |
|
chat.messages.forEach(msg => { |
|
addMessage(msg.content, msg.sender, false); |
|
}); |
|
updateChatTitle(chat.title); |
|
updateChatList(); |
|
} |
|
|
|
function updateChatTitle(title) { |
|
document.getElementById('current-chat-title').textContent = title; |
|
if (currentChatId) { |
|
const chat = chats.find(c => c.id === currentChatId); |
|
if (chat) { |
|
chat.title = title; |
|
updateChatList(); |
|
} |
|
} |
|
} |
|
|
|
function clearMessages() { |
|
chatMessages.innerHTML = ''; |
|
} |
|
|
|
|
|
const menuButton = document.getElementById('menu-button'); |
|
const sidebar = document.querySelector('.sidebar'); |
|
const overlay = document.getElementById('overlay'); |
|
|
|
function checkScreenSize() { |
|
if (window.innerWidth <= 768) { |
|
menuButton.style.display = 'flex'; |
|
menuButton.style.opacity = sidebar.classList.contains('active') ? '0' : '1'; |
|
} else { |
|
menuButton.style.display = 'none'; |
|
menuButton.style.opacity = '1'; |
|
sidebar.classList.remove('active'); |
|
overlay.classList.remove('active'); |
|
} |
|
} |
|
|
|
menuButton.addEventListener('click', () => { |
|
sidebar.classList.toggle('active'); |
|
overlay.classList.toggle('active'); |
|
|
|
menuButton.style.opacity = sidebar.classList.contains('active') ? '0' : '1'; |
|
}); |
|
|
|
overlay.addEventListener('click', () => { |
|
sidebar.classList.remove('active'); |
|
overlay.classList.remove('active'); |
|
|
|
menuButton.style.opacity = '1'; |
|
}); |
|
|
|
|
|
window.addEventListener('load', checkScreenSize); |
|
window.addEventListener('resize', checkScreenSize); |
|
|
|
|
|
document.addEventListener('click', (e) => { |
|
if (window.innerWidth <= 768 && |
|
!e.target.closest('.sidebar') && |
|
!e.target.closest('.menu-button') && |
|
sidebar.classList.contains('active')) { |
|
sidebar.classList.remove('active'); |
|
overlay.classList.remove('active'); |
|
} |
|
}); |
|
|
|
|
|
function updateScrollButtonPositions() { |
|
const inputHeight = document.querySelector('.input-container').offsetHeight; |
|
const scrollTopBtn = document.getElementById('scroll-top'); |
|
const scrollBottomBtn = document.getElementById('scroll-bottom'); |
|
|
|
if (window.innerWidth <= 768) { |
|
scrollBottomBtn.style.bottom = `${inputHeight + 20}px`; |
|
scrollTopBtn.style.bottom = `${inputHeight + 80}px`; |
|
} else { |
|
scrollBottomBtn.style.bottom = '40px'; |
|
scrollTopBtn.style.bottom = '100px'; |
|
} |
|
} |
|
|
|
|
|
window.addEventListener('load', updateScrollButtonPositions); |
|
window.addEventListener('resize', updateScrollButtonPositions); |
|
|
|
|
|
const style = document.createElement('style'); |
|
style.textContent = ` |
|
.menu-button { |
|
transition: opacity 0.3s ease; |
|
} |
|
`; |
|
document.head.appendChild(style); |
|
|
|
function sendQuickAction(text) { |
|
userInput.value = text; |
|
sendMessage(); |
|
} |
|
|
|
|
|
const settingsButton = document.getElementById('settings-button'); |
|
const settingsModal = document.getElementById('settings-modal'); |
|
const closeSettings = document.querySelector('.close-settings'); |
|
|
|
settingsButton.addEventListener('click', () => { |
|
settingsModal.classList.add('active'); |
|
}); |
|
|
|
closeSettings.addEventListener('click', () => { |
|
settingsModal.classList.remove('active'); |
|
}); |
|
|
|
|
|
settingsModal.addEventListener('click', (e) => { |
|
if (e.target === settingsModal) { |
|
settingsModal.classList.remove('active'); |
|
} |
|
}); |
|
|
|
|
|
const themeButtons = document.querySelectorAll('.theme-btn'); |
|
themeButtons.forEach(button => { |
|
button.addEventListener('click', () => { |
|
themeButtons.forEach(btn => btn.classList.remove('active')); |
|
button.classList.add('active'); |
|
|
|
}); |
|
}); |
|
|
|
function startChat() { |
|
document.getElementById('landing-page').classList.add('hidden'); |
|
|
|
} |
|
|
|
|
|
function setMobileHeight() { |
|
const vh = window.innerHeight * 0.01; |
|
document.documentElement.style.setProperty('--vh', `${vh}px`); |
|
} |
|
|
|
window.addEventListener('load', setMobileHeight); |
|
window.addEventListener('resize', setMobileHeight); |
|
</script> |
|
</body> |
|
</html> |
|
|