| | <!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> |
| |
|