In today's digital age, effective communication is key. Whether you're building a customer support system or a social networking app, having well-designed chat interfaces can make all the difference.
Here, we present 10 chat examples that showcase the best practices in UI design. These examples will inspire you to create seamless and engaging chat experiences for your users.
CODE1
Here's the code:
CODETEXT1
CODE2
Here's the code:
CODETEXT2
CODE3
Here's the code:
CODETEXT3
CODE4
Here's the code:
CODETEXT4
CODE5
Here's the code:
CODETEXT5
Designers and developers, elevate your chat interfaces with Subframe's drag-and-drop interface and intuitive, responsive canvas. Create pixel-perfect UI effortlessly, every time.
Loved by professionals across the board, Subframe makes stunning design accessible to all. Start for free today!
CODE6
Here's the code:
CODETEXT6
CODE7
Here's the code:
CODETEXT7
CODE8
Here's the code:
CODETEXT8
CODE9
Here's the code:
CODETEXT9
CODE10
Here's the code:
CODETEXT10
Ready to elevate your UI design game? With Subframe, you can create pixel-perfect interfaces, including chat UIs, in minutes. Our drag-and-drop editor and beautifully crafted components make the process efficient and enjoyable.
Don't waitβstart for free and begin designing stunning UIs immediately. Your next great design is just a click away!
<html> <head> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Nunito', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } body { display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f7f9fc; padding: 20px; } .chat-container { position: relative; width: 100%; max-width: 380px; height: 600px; background-color: #fff; border-radius: 24px; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.08); overflow: hidden; display: flex; flex-direction: column; transition: transform 0.3s ease, box-shadow 0.3s ease; } .chat-container.minimized { height: 60px; } .chat-header { padding: 18px 20px; background: linear-gradient(135deg, #6e8efb, #a777e3); color: white; display: flex; align-items: center; justify-content: space-between; z-index: 2; cursor: pointer; transition: all 0.3s ease; } .chat-header-left { display: flex; align-items: center; } .chat-avatar { width: 36px; height: 36px; border-radius: 50%; background-color: #fff; display: flex; align-items: center; justify-content: center; margin-right: 12px; position: relative; overflow: hidden; } .avatar-img { width: 100%; height: 100%; object-fit: cover; } .status-indicator { position: absolute; bottom: 0; right: 0; width: 12px; height: 12px; background-color: #4CAF50; border-radius: 50%; border: 2px solid white; } .header-info h3 { font-size: 16px; font-weight: 600; margin-bottom: 2px; } .header-info p { font-size: 12px; opacity: 0.9; } .action-buttons { display: flex; gap: 10px; } .action-button { background: rgba(255, 255, 255, 0.2); border: none; border-radius: 50%; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; color: white; cursor: pointer; transition: background 0.2s ease; } .action-button:hover { background: rgba(255, 255, 255, 0.3); } .chat-body { flex: 1; padding: 20px; overflow-y: auto; background-color: #f5f8ff; transition: all 0.3s ease; display: flex; flex-direction: column; scroll-behavior: smooth; } .chat-body::-webkit-scrollbar { width: 6px; } .chat-body::-webkit-scrollbar-track { background: transparent; } .chat-body::-webkit-scrollbar-thumb { background-color: rgba(0, 0, 0, 0.1); border-radius: 3px; } .chat-bubble { max-width: 80%; margin-bottom: 16px; position: relative; animation: fadeIn 0.3s ease; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .chat-bubble.user { align-self: flex-end; } .chat-bubble.agent { align-self: flex-start; } .chat-content { padding: 12px 16px; border-radius: 18px; font-size: 14px; line-height: 1.5; position: relative; z-index: 1; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); } .chat-bubble.user .chat-content { background-color: #a777e3; color: white; border-bottom-right-radius: 4px; } .chat-bubble.agent .chat-content { background-color: white; color: #333; border-bottom-left-radius: 4px; } .timestamp { font-size: 10px; opacity: 0.7; margin-top: 4px; text-align: right; } .chat-bubble.user .timestamp { color: #666; } .chat-bubble.agent .timestamp { color: #888; } .typing-indicator { display: inline-flex; align-items: center; padding: 6px 12px; background-color: white; border-radius: 18px; margin-bottom: 16px; align-self: flex-start; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); } .typing-dot { width: 6px; height: 6px; background-color: #a777e3; border-radius: 50%; margin: 0 2px; opacity: 0.6; animation: typingAnimation 1.4s infinite ease-in-out; } .typing-dot:nth-child(1) { animation-delay: 0s; } .typing-dot:nth-child(2) { animation-delay: 0.2s; } .typing-dot:nth-child(3) { animation-delay: 0.4s; } @keyframes typingAnimation { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-6px); } } .quick-replies { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; animation: fadeIn 0.4s ease; } .quick-reply { background-color: white; border: 1px solid #ddd; border-radius: 16px; padding: 8px 14px; font-size: 13px; color: #6e8efb; cursor: pointer; transition: all 0.2s ease; } .quick-reply:hover { background-color: #f0f4ff; border-color: #6e8efb; transform: translateY(-2px); } .quick-reply.selected { background-color: #6e8efb; color: white; border-color: #6e8efb; } .chat-footer { padding: 14px 20px; background-color: white; border-top: 1px solid #f0f0f0; display: flex; align-items: center; z-index: 3; transition: all 0.3s ease; } .input-container { flex: 1; position: relative; } .chat-input { width: 100%; padding: 12px 40px 12px 16px; border: 1px solid #e1e5ee; border-radius: 24px; font-size: 14px; background-color: #f7f9fc; transition: all 0.2s ease; } .chat-input:focus { outline: none; border-color: #6e8efb; background-color: white; box-shadow: 0 0 0 3px rgba(110, 142, 251, 0.1); } .chat-input::placeholder { color: #a0a8b9; } .send-button { width: 36px; height: 36px; background: linear-gradient(135deg, #6e8efb, #a777e3); border: none; border-radius: 50%; color: white; display: flex; align-items: center; justify-content: center; cursor: pointer; margin-left: 10px; box-shadow: 0 2px 10px rgba(110, 142, 251, 0.3); transition: all 0.2s ease; opacity: 0; transform: scale(0.8); pointer-events: none; } .send-button.active { opacity: 1; transform: scale(1); pointer-events: auto; } .send-button:hover { transform: scale(1.05); box-shadow: 0 4px 14px rgba(110, 142, 251, 0.4); } .extra-options { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); display: flex; align-items: center; } .extra-option { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; color: #a0a8b9; cursor: pointer; transition: color 0.2s ease; } .extra-option:hover { color: #6e8efb; } .chat-button { position: fixed; bottom: 30px; right: 30px; width: 60px; height: 60px; background: linear-gradient(135deg, #6e8efb, #a777e3); border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15); cursor: pointer; z-index: 1000; transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .chat-button:hover { transform: scale(1.05); } .chat-button .open-icon, .chat-button .close-icon { position: absolute; transition: all 0.3s ease; } .chat-button .close-icon { opacity: 0; transform: rotate(-90deg); } .chat-button.opened .open-icon { opacity: 0; transform: rotate(90deg); } .chat-button.opened .close-icon { opacity: 1; transform: rotate(0deg); } .notification-badge { position: absolute; top: -6px; right: -6px; width: 20px; height: 20px; background-color: #ff5a5a; border-radius: 50%; color: white; font-size: 12px; display: flex; align-items: center; justify-content: center; font-weight: bold; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); animation: pulse 2s infinite; opacity: 0; pointer-events: none; } .notification-badge.active { opacity: 1; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } .support-agent-info { display: none; padding: 15px; background-color: rgba(110, 142, 251, 0.05); border-radius: 12px; margin-bottom: 15px; animation: fadeIn 0.5s ease; } .support-agent-info.visible { display: flex; align-items: center; } .agent-info-avatar { width: 50px; height: 50px; border-radius: 50%; margin-right: 15px; } .agent-info-details h4 { margin: 0 0 5px; font-size: 15px; color: #444; } .agent-info-details p { margin: 0; font-size: 13px; color: #666; } .emoji-picker { position: absolute; bottom: 60px; right: 10px; background-color: white; border-radius: 12px; box-shadow: 0 5px 25px rgba(0, 0, 0, 0.15); padding: 10px; display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; transition: all 0.3s ease; opacity: 0; visibility: hidden; transform: translateY(10px); z-index: 5; } .emoji-picker.visible { opacity: 1; visibility: visible; transform: translateY(0); } .emoji { font-size: 18px; cursor: pointer; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: 8px; transition: all 0.2s ease; } .emoji:hover { background-color: #f5f8ff; } .satisfaction-survey { padding: 15px; background-color: white; border-radius: 12px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); margin-bottom: 15px; animation: fadeIn 0.5s ease; display: none; } .satisfaction-survey.visible { display: block; } .satisfaction-title { font-size: 14px; font-weight: 600; margin-bottom: 10px; color: #333; } .rating-options { display: flex; justify-content: space-between; margin-bottom: 12px; } .rating-option { width: 40px; height: 40px; border-radius: 50%; background-color: #f5f8ff; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.2s ease; } .rating-option:hover { background-color: #e7edff; transform: translateY(-2px); } .rating-option.selected { background-color: #6e8efb; color: white; } .completion-message { font-size: 13px; color: #6e8efb; text-align: center; padding: 5px; display: none; } .completion-message.visible { display: block; animation: fadeIn 0.5s ease; } /* Responsive styles */ @media (max-width: 480px) { .chat-container { width: 100%; height: 100%; max-width: 100%; border-radius: 0; } .chat-button { bottom: 20px; right: 20px; width: 50px; height: 50px; } } /* Chat window transitions */ .chat-window { position: fixed; bottom: 100px; right: 30px; width: 360px; transform: translateY(20px); opacity: 0; visibility: hidden; transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); z-index: 999; } .chat-window.open { transform: translateY(0); opacity: 1; visibility: visible; } @media (max-width: 480px) { .chat-window { width: calc(100% - 40px); right: 20px; bottom: 80px; } } /* Special bubble effects */ .chat-bubble::after { content: ""; position: absolute; width: 12px; height: 12px; border-radius: 2px; z-index: 0; } .chat-bubble.agent::after { left: -3px; bottom: 8px; background-color: white; transform: rotate(45deg); } .chat-bubble.user::after { right: -3px; bottom: 8px; background-color: #a777e3; transform: rotate(45deg); } /* Animations */ @keyframes fadeInUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .fade-in-up { animation: fadeInUp 0.3s ease forwards; } /* Accessibility focus styles */ button:focus, a:focus, input:focus { outline: 2px solid #6e8efb; outline-offset: 2px; } /* Remove outline for mouse users */ button:focus:not(:focus-visible), a:focus:not(:focus-visible), input:focus:not(:focus-visible) { outline: none; } </style> </head> <body> <!-- Chat button --> <div class="chat-button" aria-label="Chat with support"> <span class="notification-badge">1</span> <svg class="open-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M20 4H4C2.9 4 2.01 4.9 2.01 6L2 18C2 19.1 2.9 20 4 20H20C21.1 20 22 19.1 22 18V6C22 4.9 21.1 4 20 4ZM20 18H4V8L12 13L20 8V18ZM12 11L4 6H20L12 11Z" fill="currentColor"/> </svg> <svg class="close-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z" fill="currentColor"/> </svg> </div> <!-- Chat window --> <div class="chat-window"> <div class="chat-container"> <div class="chat-header"> <div class="chat-header-left"> <div class="chat-avatar"> <img class="avatar-img" src="https://randomuser.me/api/portraits/women/55.jpg" alt="Support Agent"> <div class="status-indicator"></div> </div> <div class="header-info"> <h3>Swift Support</h3> <p>Typically replies in 2 minutes</p> </div> </div> <div class="action-buttons"> <button class="action-button minimize-btn" aria-label="Minimize chat"> <svg width="14" height="2" viewBox="0 0 14 2" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M1 1H13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> <button class="action-button close-btn" aria-label="Close chat"> <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> </div> </div> <div class="chat-body"> <!-- Support agent info --> <div class="support-agent-info"> <img class="agent-info-avatar" src="https://randomuser.me/api/portraits/women/55.jpg" alt="Support Agent"> <div class="agent-info-details"> <h4>Emma Taylor</h4> <p>Customer Service Specialist</p> </div> </div> <!-- Chat messages --> <div class="chat-bubble agent"> <div class="chat-content"> Hi there! π How can I help you today with your order, account, or product query? </div> <div class="timestamp">10:32 AM</div> <div class="quick-replies"> <button class="quick-reply">Track my order</button> <button class="quick-reply">Return policy</button> <button class="quick-reply">Payment issue</button> <button class="quick-reply">Speak to agent</button> </div> </div> <!-- More messages will be added dynamically --> </div> <div class="chat-footer"> <div class="input-container"> <input type="text" class="chat-input" placeholder="Type your message..." aria-label="Type your message"> <div class="extra-options"> <div class="extra-option emoji-btn" aria-label="Add emoji"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M10 18.333C14.6024 18.333 18.3333 14.6021 18.3333 9.99967C18.3333 5.39727 14.6024 1.66634 10 1.66634C5.39763 1.66634 1.66667 5.39727 1.66667 9.99967C1.66667 14.6021 5.39763 18.333 10 18.333Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M6.66667 11.6663C6.66667 11.6663 7.91667 13.333 10 13.333C12.0833 13.333 13.3333 11.6663 13.3333 11.6663" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M7.5 7.5H7.51" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M12.5 7.5H12.51" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <div class="extra-option attach-btn" aria-label="Attach file"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M17.0833 8.74967L9.66667 16.1663C8.95942 16.8736 8.02595 17.2703 7.05 17.2703C6.07405 17.2703 5.14058 16.8736 4.43333 16.1663C3.72609 15.4591 3.32939 14.5256 3.32939 13.5497C3.32939 12.5737 3.72609 11.6403 4.43333 10.933L11.85 3.51634C12.3186 3.04774 12.9532 2.78589 13.6167 2.78589C14.2801 2.78589 14.9147 3.04774 15.3833 3.51634C15.8519 3.98493 16.1138 4.61954 16.1138 5.28301C16.1138 5.94647 15.8519 6.58108 15.3833 7.04967L7.96667 14.4663C7.73237 14.7006 7.4149 14.8316 7.08333 14.8316C6.75177 14.8316 6.4343 14.7006 6.2 14.4663C5.9657 14.232 5.83478 13.9146 5.83478 13.583C5.83478 13.2514 5.9657 12.934 6.2 12.6997L13.1 5.83301" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> </div> <!-- Emoji picker --> <div class="emoji-picker"> <div class="emoji">π</div> <div class="emoji">π</div> <div class="emoji">π</div> <div class="emoji">π</div> <div class="emoji">β€οΈ</div> <div class="emoji">π</div> <div class="emoji">π€</div> <div class="emoji">π’</div> <div class="emoji">π</div> <div class="emoji">π</div> </div> </div> <button class="send-button" aria-label="Send message"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M16.5 1.5L8.25 9.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M16.5 1.5L11.25 16.5L8.25 9.75L1.5 6.75L16.5 1.5Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // DOM Elements const chatWindow = document.querySelector('.chat-window'); const chatButton = document.querySelector('.chat-button'); const closeBtn = document.querySelector('.close-btn'); const minimizeBtn = document.querySelector('.minimize-btn'); const chatContainer = document.querySelector('.chat-container'); const chatBody = document.querySelector('.chat-body'); const chatInput = document.querySelector('.chat-input'); const sendButton = document.querySelector('.send-button'); const quickReplies = document.querySelectorAll('.quick-reply'); const notificationBadge = document.querySelector('.notification-badge'); const emojiBtn = document.querySelector('.emoji-btn'); const emojiPicker = document.querySelector('.emoji-picker'); const emojis = document.querySelectorAll('.emoji'); const supportAgentInfo = document.querySelector('.support-agent-info'); // Show notification badge with 1 message setTimeout(() => { notificationBadge.classList.add('active'); }, 3000); // Variables to track state let isChatOpen = false; let isTyping = false; let agentIsTyping = false; let typingTimeout; // Predefined responses const agentResponses = { "track my order": "To track your order, I'll need your order number or the email address you used for your purchase. Could you provide that for me?", "return policy": "Our return policy allows you to return items within 30 days of delivery for a full refund. You can initiate a return from your order history page or I can guide you through the process. Would you like step-by-step instructions?", "payment issue": "I'm sorry you're experiencing payment issues. Could you tell me what specific problem you're encountering? Is it a declined card, double charge, or something else?", "speak to agent": "I'd be happy to connect you with a specialist. To help us direct you to the right team, could you briefly describe what you need assistance with?" }; // Predefined user responses based on agent messages const userResponseOptions = { "track my order": ["Here's my order number: ORD-29475", "I can't find my order number", "I used guest checkout"], "return policy": ["Yes, guide me through the steps", "Is return shipping free?", "Can I exchange instead of return?"], "payment issue": ["My card was declined", "I was charged twice", "Payment shows pending for days"], "speak to agent": ["Product technical support", "Billing question", "Website navigation help"] }; // Toggle chat window visibility function toggleChat() { isChatOpen = !isChatOpen; chatWindow.classList.toggle('open', isChatOpen); chatButton.classList.toggle('opened', isChatOpen); if (isChatOpen) { notificationBadge.classList.remove('active'); chatInput.focus(); // Show agent info after opening setTimeout(() => { supportAgentInfo.classList.add('visible'); }, 800); } } // Close chat function closeChat() { isChatOpen = false; chatWindow.classList.remove('open'); chatButton.classList.remove('opened'); } // Minimize chat function minimizeChat() { chatContainer.classList.toggle('minimized'); } // Scroll to bottom of chat function scrollToBottom() { chatBody.scrollTop = chatBody.scrollHeight; } // Show typing indicator function showTypingIndicator() { if (agentIsTyping) return; agentIsTyping = true; const typingIndicator = document.createElement('div'); typingIndicator.className = 'typing-indicator'; typingIndicator.innerHTML = ` <div class="typing-dot"></div> <div class="typing-dot"></div> <div class="typing-dot"></div> `; chatBody.appendChild(typingIndicator); scrollToBottom(); return typingIndicator; } // Add a message to chat function addMessage(message, isUser = false, delay = 0, withQuickReplies = null) { return new Promise(resolve => { setTimeout(() => { const bubble = document.createElement('div'); bubble.className = `chat-bubble ${isUser ? 'user' : 'agent'}`; // Get current time in format like "10:42 AM" const now = new Date(); const hours = now.getHours(); const minutes = now.getMinutes().toString().padStart(2, '0'); const ampm = hours >= 12 ? 'PM' : 'AM'; const formattedHours = hours % 12 || 12; const timeString = `${formattedHours}:${minutes} ${ampm}`; bubble.innerHTML = ` <div class="chat-content">${message}</div> <div class="timestamp">${timeString}</div> `; if (withQuickReplies && Array.isArray(withQuickReplies) && withQuickReplies.length > 0) { const quickRepliesContainer = document.createElement('div'); quickRepliesContainer.className = 'quick-replies'; withQuickReplies.forEach(reply => { const button = document.createElement('button'); button.className = 'quick-reply'; button.textContent = reply; button.addEventListener('click', () => handleQuickReplyClick(reply)); quickRepliesContainer.appendChild(button); }); bubble.appendChild(quickRepliesContainer); } chatBody.appendChild(bubble); scrollToBottom(); resolve(); }, delay); }); } // Handle sending a message function sendMessage() { const message = chatInput.value.trim(); if (!message) return; // Add user message to chat addMessage(message, true); chatInput.value = ''; updateSendButton(); // Show typing indicator const typingIndicator = showTypingIndicator(); // Simulate agent response after delay setTimeout(() => { // Remove typing indicator if (typingIndicator) { typingIndicator.remove(); agentIsTyping = false; } // Generate agent response based on message let response = "Thanks for your message! I've noted that down and will follow up shortly."; let quickReplies = null; // Check if message contains any keywords const lowerMsg = message.toLowerCase(); if (lowerMsg.includes('order') || lowerMsg.includes('track') || lowerMsg.includes('shipping')) { response = "To track your order, I'll need your order number. You can find this in your confirmation email. Could you share that with me?"; quickReplies = ["Here's my order #", "Can't find my order #", "Order hasn't shipped yet"]; } else if (lowerMsg.includes('return') || lowerMsg.includes('refund')) { response = "I can help with your return. Our policy allows returns within 30 days of delivery. Have you already initiated a return in your account?"; quickReplies = ["How do I start a return?", "Return window expired", "Check refund status"]; } else if (lowerMsg.includes('broken') || lowerMsg.includes('damaged') || lowerMsg.includes('not working')) { response = "I'm sorry to hear that your item arrived damaged or isn't working properly. We'll make this right. Could you briefly describe the issue you're experiencing?"; quickReplies = ["Item arrived damaged", "Product malfunctioning", "Missing parts"]; } else if (lowerMsg.includes('hi') || lowerMsg.includes('hello') || lowerMsg.includes('hey')) { response = "Hello! Thanks for reaching out. How can I assist you today with your order or account?"; quickReplies = ["Track my order", "Return policy", "Account help"]; } // Add agent response addMessage(response, false, 0, quickReplies); }, 1500); } // Handle quick reply click function handleQuickReplyClick(replyText) { // First add the clicked reply as a user message addMessage(replyText, true); // Show typing indicator const typingIndicator = showTypingIndicator(); // Find the appropriate response let responseText = "I'll look into that for you right away."; let quickReplies = null; // Try to match the reply with predefined responses const lowerReply = replyText.toLowerCase(); Object.keys(agentResponses).forEach(key => { if (lowerReply.includes(key)) { responseText = agentResponses[key]; quickReplies = userResponseOptions[key]; } }); // Special cases based on specific replies if (lowerReply.includes("order number") || lowerReply.includes("order #")) { responseText = "Thanks for providing your order number. I can see that your package is currently in transit and scheduled for delivery on Friday by 8pm. Would you like me to send you the tracking link?"; quickReplies
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>NeonChat - Gaming Interface</title> <style> :root { --primary: #0fe3ff; --secondary: #f845ff; --dark: #0d0e19; --darker: #07080f; --text: #e9eaff; --text-dim: #9395bd; --success: #42ff87; --danger: #ff4266; --warning: #ffb342; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Rajdhani', 'Orbitron', sans-serif; } body { background-color: var(--darker); color: var(--text); height: 100vh; display: flex; justify-content: center; align-items: center; overflow: hidden; font-family: 'Rajdhani', sans-serif; } .container { width: 700px; height: 700px; position: relative; background-color: rgba(13, 14, 25, 0.85); border-radius: 12px; border: 1px solid rgba(14, 227, 255, 0.15); box-shadow: 0 0 30px rgba(14, 227, 255, 0.1), 0 0 60px rgba(248, 69, 255, 0.05); backdrop-filter: blur(10px); display: flex; flex-direction: column; overflow: hidden; } .glitch-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(45deg, rgba(14, 227, 255, 0.03) 0%, rgba(248, 69, 255, 0.03) 100%); pointer-events: none; z-index: 1; } .chat-header { padding: 15px 20px; background-color: var(--darker); border-bottom: 1px solid rgba(14, 227, 255, 0.15); display: flex; justify-content: space-between; align-items: center; position: relative; z-index: 2; } .chat-title { display: flex; align-items: center; gap: 15px; } .chat-title h2 { background: linear-gradient(90deg, var(--primary), var(--secondary)); -webkit-background-clip: text; background-clip: text; color: transparent; font-size: 1.25rem; letter-spacing: 1px; font-weight: 600; text-transform: uppercase; } .online-status { display: flex; align-items: center; gap: 6px; font-size: 0.8rem; color: var(--success); } .status-indicator { width: 8px; height: 8px; background-color: var(--success); border-radius: 50%; position: relative; } .status-indicator::before { content: ''; position: absolute; top: -2px; left: -2px; width: 12px; height: 12px; background-color: var(--success); border-radius: 50%; opacity: 0.4; animation: pulse 2s infinite; } .header-actions { display: flex; gap: 15px; } .header-btn { background: none; border: none; color: var(--text-dim); cursor: pointer; transition: color 0.2s, transform 0.2s; font-size: 1.2rem; position: relative; } .header-btn:hover { color: var(--primary); transform: scale(1.1); } .chat-body { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 12px; position: relative; z-index: 2; scrollbar-width: thin; scrollbar-color: var(--secondary) var(--darker); } .chat-body::-webkit-scrollbar { width: 5px; } .chat-body::-webkit-scrollbar-thumb { background-color: var(--primary); border-radius: 10px; } .chat-body::-webkit-scrollbar-track { background-color: var(--darker); } .message { max-width: 80%; padding: 10px 15px; border-radius: 12px; position: relative; animation: fadeIn 0.3s ease-out forwards; transition: transform 0.2s; margin-bottom: 5px; } .message:hover { transform: translateY(-2px); } .message.incoming { align-self: flex-start; background: linear-gradient(135deg, rgba(14, 227, 255, 0.15), rgba(14, 227, 255, 0.05)); border-top-left-radius: 0; border-left: 2px solid var(--primary); } .message.outgoing { align-self: flex-end; background: linear-gradient(135deg, rgba(248, 69, 255, 0.15), rgba(248, 69, 255, 0.05)); border-bottom-right-radius: 0; border-right: 2px solid var(--secondary); } .message.system { align-self: center; background: rgba(255, 255, 255, 0.05); font-style: italic; font-size: 0.9rem; color: var(--text-dim); padding: 5px 15px; max-width: 90%; text-align: center; } .message-content { font-size: 0.95rem; line-height: 1.4; word-break: break-word; } .message-meta { display: flex; justify-content: space-between; margin-top: 5px; font-size: 0.7rem; color: var(--text-dim); } .username { font-weight: 600; margin-bottom: 3px; } .message.incoming .username { color: var(--primary); } .message.outgoing .username { color: var(--secondary); } .timestamp { font-size: 0.7rem; opacity: 0.7; } .chat-footer { padding: 15px 20px; background-color: var(--darker); border-top: 1px solid rgba(14, 227, 255, 0.15); position: relative; z-index: 2; } .message-form { display: flex; gap: 10px; } .message-input-container { flex: 1; position: relative; } .message-input { width: 100%; padding: 12px 15px; padding-right: 40px; background-color: rgba(255, 255, 255, 0.05); border: 1px solid rgba(14, 227, 255, 0.15); border-radius: 8px; color: var(--text); font-size: 0.95rem; transition: all 0.3s; outline: none; } .message-input:focus { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(14, 227, 255, 0.2); } .message-input::placeholder { color: var(--text-dim); } .emoji-btn { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; color: var(--text-dim); cursor: pointer; transition: color 0.2s; font-size: 1.1rem; } .emoji-btn:hover { color: var(--primary); } .send-btn { background: linear-gradient(135deg, var(--primary), var(--secondary)); border: none; border-radius: 8px; width: 45px; color: var(--dark); cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; transition: all 0.3s; position: relative; overflow: hidden; } .send-btn::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, var(--primary), var(--secondary)); opacity: 0; transition: opacity 0.3s; } .send-btn:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(14, 227, 255, 0.3); } .send-btn:active { transform: translateY(0); } .notification { position: absolute; top: 20px; left: 50%; transform: translateX(-50%) translateY(-100px); background: rgba(14, 227, 255, 0.9); color: var(--darker); padding: 8px 15px; border-radius: 6px; font-size: 0.9rem; z-index: 10; box-shadow: 0 5px 20px rgba(14, 227, 255, 0.4); opacity: 0; transition: transform 0.3s, opacity 0.3s; text-align: center; font-weight: 500; } .notification.active { transform: translateX(-50%) translateY(0); opacity: 1; } .typing-indicator { display: none; align-items: center; gap: 10px; padding: 8px 15px; font-size: 0.9rem; color: var(--text-dim); align-self: flex-start; margin-top: -5px; } .typing-indicator.active { display: flex; } .typing-dots { display: flex; gap: 3px; } .typing-dot { width: 6px; height: 6px; background-color: var(--primary); border-radius: 50%; opacity: 0.6; } .typing-dot:nth-child(1) { animation: typingDot 1s infinite 0.1s; } .typing-dot:nth-child(2) { animation: typingDot 1s infinite 0.2s; } .typing-dot:nth-child(3) { animation: typingDot 1s infinite 0.3s; } .ping-effect { position: absolute; width: 15px; height: 15px; border-radius: 50%; background-color: var(--primary); opacity: 0.7; z-index: 5; pointer-events: none; animation: pingFade 0.6s ease-out forwards; } .guild-indicator { display: flex; align-items: center; gap: 5px; font-size: 0.8rem; margin-top: 3px; } .guild-tag { padding: 2px 6px; border-radius: 3px; font-size: 0.7rem; font-weight: 600; text-transform: uppercase; background-color: rgba(66, 255, 135, 0.2); color: var(--success); } .incoming .guild-tag { background-color: rgba(14, 227, 255, 0.2); color: var(--primary); } .outgoing .guild-tag { background-color: rgba(248, 69, 255, 0.2); color: var(--secondary); } .player-level { font-size: 0.7rem; background: var(--text-dim); color: var(--darker); padding: 1px 5px; border-radius: 3px; margin-left: 5px; } .chat-mode-toggle { display: flex; gap: 10px; padding: 5px; margin-bottom: 15px; background-color: rgba(255, 255, 255, 0.05); border-radius: 8px; font-size: 0.8rem; width: fit-content; align-self: center; } .chat-mode-btn { padding: 5px 10px; border-radius: 5px; cursor: pointer; transition: all 0.2s; text-transform: uppercase; font-weight: 600; letter-spacing: 0.5px; } .chat-mode-btn.active { background: linear-gradient(90deg, var(--primary), var(--secondary)); color: var(--darker); } .message-reaction { display: flex; align-items: center; gap: 3px; background-color: rgba(255, 255, 255, 0.1); padding: 2px 5px; border-radius: 10px; font-size: 0.8rem; cursor: pointer; transition: all 0.2s; margin-top: 3px; width: fit-content; } .message-reaction:hover { background-color: rgba(14, 227, 255, 0.2); } .reaction-count { font-size: 0.75rem; } .quick-emotes { display: flex; gap: 5px; margin-top: 8px; } .quick-emote { font-size: 1.1rem; cursor: pointer; transition: transform 0.2s; opacity: 0.7; } .quick-emote:hover { transform: scale(1.2); opacity: 1; } /* Cyberpunk glitch effect on notification */ .notification::before { content: attr(data-text); position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: rgba(14, 227, 255, 0.9); color: var(--darker); clip: rect(0, 0, 0, 0); animation: glitch 2s infinite linear alternate-reverse; } /* Animation keyframes */ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes pulse { 0% { transform: scale(1); opacity: 0.4; } 50% { transform: scale(1.5); opacity: 0.2; } 100% { transform: scale(1); opacity: 0.4; } } @keyframes typingDot { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); opacity: 1; } } @keyframes pingFade { 0% { transform: scale(1); opacity: 0.7; } 100% { transform: scale(3); opacity: 0; } } @keyframes glitch { 0% { clip: rect(5px, 9999px, 75px, 0); opacity: 0.4; } 5% { clip: rect(33px, 9999px, 99px, 0); opacity: 0.3; } 10% { clip: rect(56px, 9999px, 22px, 0); opacity: 0.6; } 15% { clip: rect(0, 0, 0, 0); opacity: 0; } 100% { clip: rect(0, 0, 0, 0); opacity: 0; } } @media (max-width: 700px) { .container { width: 100%; height: 100%; border-radius: 0; } .message { max-width: 90%; } } </style> </head> <body> <div class="container"> <div class="glitch-overlay"></div> <div class="chat-header"> <div class="chat-title"> <h2>Raid Chat</h2> <div class="online-status"> <span class="status-indicator"></span> <span>24 raiders online</span> </div> </div> <div class="header-actions"> <button class="header-btn" aria-label="Toggle mute"> <i class="fas fa-volume-up"></i> </button> <button class="header-btn" aria-label="Settings"> <i class="fas fa-cog"></i> </button> <button class="header-btn" aria-label="Minimize"> <i class="fas fa-minus"></i> </button> </div> </div> <div class="chat-body" id="chat-body"> <div class="chat-mode-toggle"> <div class="chat-mode-btn active" data-mode="raid">Raid</div> <div class="chat-mode-btn" data-mode="team">Team</div> <div class="chat-mode-btn" data-mode="global">Global</div> </div> <div class="message system"> <div class="message-content">Welcome to Cybervault Raid #247 - 5 minutes until dungeon lockdown</div> </div> <div class="message incoming"> <div class="username">NightSlayer<span class="player-level">LVL 78</span></div> <div class="guild-indicator"> <div class="guild-tag">Phantom</div> </div> <div class="message-content">I'll take point on the east entrance. Two sentries with pulse rifles spotted.</div> <div class="message-meta"> <span class="timestamp">2:14 PM</span> </div> <div class="message-reaction"> <span>π</span> <span class="reaction-count">3</span> </div> </div> <div class="message outgoing"> <div class="username">You<span class="player-level">LVL 62</span></div> <div class="guild-indicator"> <div class="guild-tag">Neon</div> </div> <div class="message-content">Copy that. I've got the thermal grenades ready for the security mainframe. Need 30 seconds for cooldown.</div> <div class="message-meta"> <span class="timestamp">2:15 PM</span> </div> </div> <div class="message incoming"> <div class="username">CyberWitch<span class="player-level">LVL 81</span></div> <div class="guild-indicator"> <div class="guild-tag">Phantom</div> </div> <div class="message-content">Hold position! Detected stealth drones in the perimeter. I'm hacking into their signal now.</div> <div class="message-meta"> <span class="timestamp">2:16 PM</span> </div> </div> <div class="message system"> <div class="message-content">β¦ CyberWitch is using Neural Hack ability (24s remaining) β¦</div> </div> <div class="message incoming"> <div class="username">VoidWalker<span class="player-level">LVL 75</span></div> <div class="guild-indicator"> <div class="guild-tag">Neon</div> </div> <div class="message-content">I've marked a supply cache on your HUDs. MedKits and ammo packs inside. Should help with the boss encounter.</div> <div class="message-meta"> <span class="timestamp">2:17 PM</span> </div> </div> <div class="message outgoing"> <div class="username">You<span class="player-level">LVL 62</span></div> <div class="guild-indicator"> <div class="guild-tag">Neon</div> </div> <div class="message-content">On it. My shield capacity is at 68%. Anyone got spare power cells?</div> <div class="message-meta"> <span class="timestamp">2:18 PM</span> </div> </div> <div class="message incoming"> <div class="username">NightSlayer<span class="player-level">LVL 78</span></div> <div class="guild-indicator"> <div class="guild-tag">Phantom</div> </div> <div class="message-content">I've got 3 cells to spare. Ping your location when ready for transfer.</div> <div class="message-meta"> <span class="timestamp">2:19 PM</span> </div> </div> <div class="message system"> <div class="message-content">β¦ Raid boss "Neuromancer" has been detected on scanner β¦</div> </div> <div class="typing-indicator" id="typing-indicator"> <span>CyberWitch is typing</span> <div class="typing-dots"> <div class="typing-dot"></div> <div class="typing-dot"></div> <div class="typing-dot"></div> </div> </div> </div> <div class="chat-footer"> <form class="message-form" id="message-form"> <div class="message-input-container"> <input type="text" class="message-input" id="message-input" placeholder="Enter message... (Press Enter to send)" autocomplete="off"> <button type="button" class="emoji-btn" aria-label="Add emoji"> <i class="far fa-smile"></i> </button> </div> <button type="submit" class="send-btn" aria-label="Send message"> <i class="fas fa-paper-plane"></i> </button> </form> <div class="quick-emotes"> <div class="quick-emote" data-emote="π">π</div> <div class="quick-emote" data-emote="βοΈ">βοΈ</div> <div class="quick-emote" data-emote="π‘οΈ">π‘οΈ</div> <div class="quick-emote" data-emote="π₯">π₯</div> <div class="quick-emote" data-emote="β€οΈ">β€οΈ</div> </div> </div> <div class="notification" id="notification" data-text=""></div> </div> <script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script> <script> document.addEventListener('DOMContentLoaded', function() { const chatBody = document.getElementById('chat-body'); const messageForm = document.getElementById('message-form'); const messageInput = document.getElementById('message-input'); const notification = document.getElementById('notification'); const typingIndicator = document.getElementById('typing-indicator'); const quickEmotes = document.querySelectorAll('.quick-emote'); const chatModeButtons = document.querySelectorAll('.chat-mode-btn'); // Scroll to bottom of chat function scrollToBottom() { chatBody.scrollTop = chatBody.scrollHeight; } scrollToBottom(); // Show notification function showNotification(message, duration = 3000) { notification.textContent = message; notification.dataset.text = message; notification.classList.add('active'); setTimeout(() => { notification.classList.remove('active'); }, duration); } // Add message to chat function addMessage(content, isOutgoing = true) { const messageElement = document.createElement('div'); messageElement.classList.add('message', isOutgoing ? 'outgoing' : 'incoming'); const username = document.createElement('div'); username.classList.add('username'); username.innerHTML = isOutgoing ? 'You<span class="player-level">LVL 62</span>' : 'NightSlayer<span class="player-level">LVL 78</span>'; const guildIndicator = document.createElement('div'); guildIndicator.classList.add('guild-indicator'); const guildTag = document.createElement('div'); guildTag.classList.add('guild-tag'); guildTag.textContent = isOutgoing ? 'Neon' : 'Phantom'; guildIndicator.appendChild(guildTag); const messageContent = document.createElement('div'); messageContent.classList.add('message-content'); messageContent.textContent = content; const messageMeta = document.createElement('div'); messageMeta.classList.add('message-meta'); const timestamp = document.createElement('span'); timestamp.classList.add('timestamp'); const now = new Date(); timestamp.textContent = `${now.getHours()}:${now.getMinutes().toString().padStart(2, '0')} ${now.getHours() >= 12 ? 'PM' : 'AM'}`; messageMeta.appendChild(timestamp); messageElement.appendChild(username); messageElement.appendChild(guildIndicator); messageElement.appendChild(messageContent); messageElement.appendChild(messageMeta); // Remove typing indicator if it exists if (typingIndicator.classList.contains('active')) { typingIndicator.classList.remove('active'); } chatBody.appendChild(messageElement); scrollToBottom(); // Add ping effect at the message position const pingEffect = document.createElement('div'); pingEffect.classList.add('ping-effect'); pingEffect.style.left = isOutgoing ? '80%' : '20%'; pingEffect.style.top = `${chatBody.scrollHeight - 50}px`; chatBody.appendChild(pingEffect); setTimeout(() => { chatBody.removeChild(pingEffect); }, 600); return messageElement; } // Form submission messageForm.addEventListener('submit', function(e) { e.preventDefault(); const message = messageInput.value.trim(); if (message) { addMessage(message); messageInput.value = ''; // Simulate response after random delay setTimeout(() => { // Show typing indicator typingIndicator.classList.add('active'); setTimeout(() => { // Random responses based on context const responses = [ "Roger that. Moving to your position now.", "Watch your six! Enemy reinforcements detected on scanner.", "I've got your back. Let me know when you're ready to breach.", "Marking additional hostiles on your HUD. Proceed with caution.", "Need backup? I can deploy my drone for recon." ]; const randomResponse = responses[Math.floor(Math.random() * responses.length)]; addMessage(randomResponse, false); }, 2000); }, 1000 + Math.random() * 2000); // Show random game events occasionally if (Math.random() > 0.7) { setTimeout(() => { const events = [ "β¦ Security level increased: Additional patrols detected β¦", "β¦ Loot cache revealed in the eastern sector β¦", "β¦ Environmental hazard: Toxic gas detected β¦", "β¦ System alert: 2 minutes until lockdown β¦", "β¦ Objective updated: Neutralize security mainframe β¦" ]; const randomEvent = events[Math.floor(Math.random() * events.length)]; const systemMessage = document.createElement('div'); systemMessage.classList.add('message', 'system'); const systemContent = document.createElement('div'); systemContent.classList.add('message-content'); systemContent.textContent = randomEvent; systemMessage.appendChild(systemContent); chatBody.appendChild(systemMessage); scrollToBottom(); showNotification("New mission update received", 2500); }, 3000); } } }); // Quick emotes functionality quickEmotes.forEach(emote => { emote.addEventListener('click', () => { const emoteText = emote.getAttribute('data-emote'); messageInput.value += emoteText; messageInput.focus(); }); }); // Chat mode toggle chatModeButtons.forEach(button => { button.addEventListener('click', () => { chatModeButtons.forEach(btn => btn.classList.remove('active')); button.classList.add('active'); const mode = button.getAttribute('data-mode'); showNotification(`Switched to ${mode.toUpperCase()} chat`, 1500); }); }); // Add click effect to messages chatBody.addEventListener('click', (e) => { if (e.target.closest('.message')) { const message = e.target.closest('.message'); // Create a ping effect at click position const pingEffect = document.createElement('div'); pingEffect.classList.add('ping-effect'); pingEffect.style.left = `${e.clientX - chatBody.getBoundingClientRect().left}px`; pingEffect.style.top = `${e.clientY - chatBody.getBoundingClientRect().top}px`; chatBody.appendChild(pingEffect); setTimeout(() => { chatBody.removeChild(pingEffect); }, 600); } }); // Simulate random incoming messages function simulateIncomingMessage() { const delay = 15000 + Math.random() * 20000; // Random delay between 15-35 seconds setTimeout(() => { if (Math.random() > 0.4) { // 60% chance of showing typing indicator typingIndicator.classList.add('active'); setTimeout(() => { const messages = [ "Scanning complete. Three hostiles eliminated.", "My cloak is almost depleted. Need to recharge at the next energy node.", "Boss has a shield regeneration cycle. Target the power nodes first.", "Found a secret passage behind the eastern wall. Could be a shortcut.", "Watch out for laser tripwires. They'll trigger the alarm system." ]; const usernames = ["CyberWitch", "VoidWalker", "NightSlayer", "PhantomByte", "QuantumRogue"]; const randomUsername = usernames[Math.floor(Math.random() * usernames.length)]; const randomMessage = messages[Math.floor(Math.random() * messages.length)]; const messageElement = document.createElement('div'); messageElement.classList.add('message', 'incoming'); const username = document.createElement('div'); username.classList.add('username'); const level = 70 + Math.floor(Math.random() * 20); username.innerHTML = `${randomUsername}<span class="player-level">LVL ${level}</span>`; const guildIndicator = document.createElement('div'); guildIndicator.classList.add('guild-indicator'); const guildTag = document.createElement('div'); guildTag.classList.add('guild-tag'); guildTag.textContent = Math.random() > 0.5 ? 'Phantom' : 'Neon'; guildIndicator.appendChild(guildTag); const messageContent = document.createElement('div'); messageContent.classList.add('message-content'); messageContent.textContent = randomMessage; const messageMeta = document.createElement('div'); messageMeta.classList.add('message-meta'); const timestamp = document.createElement('span'); timestamp.classList.add('timestamp'); const now = new Date(); timestamp.textContent = `${now.getHours()}:${now.getMinutes().toString().padStart(2, '0')} ${now.getHours() >= 12 ? 'PM' : 'AM'}`; messageMeta.appendChild(timestamp); messageElement.appendChild(username); messageElement.appendChild(guildIndicator); messageElement.appendChild(messageContent); messageElement.appendChild(messageMeta); typingIndicator.classList.remove('active'); chatBody.appendChild(messageElement); scrollToBottom(); // Play notification sound if (document.visibilityState !== 'visible') { showNotification(`New message from ${randomUsername}`, 2000); } }, 1500 + Math.random() * 1000); } simulateIncomingMessage(); // Schedule next message }, delay); } // Start the simulation simulateIncomingMessage(); // Initial notification setTimeout(() => { showNotification("Connected to Raid Chat server", 2500); }, 1000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CorporateSync Chat</title> <style> :root { --primary: #2D5BFF; --primary-light: #E9EEFF; --secondary: #6C7A89; --light: #F5F7FA; --dark: #2C3E50; --success: #27AE60; --warning: #F39C12; --danger: #E74C3C; --border-radius: 10px; --shadow: 0 4px 12px rgba(0, 0, 0, 0.08); --transition: all 0.3s ease; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } body { background-color: var(--light); color: var(--dark); display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; } .app-container { width: 100%; max-width: 700px; height: 700px; background-color: white; border-radius: var(--border-radius); box-shadow: var(--shadow); display: flex; overflow: hidden; position: relative; } .sidebar { width: 280px; background-color: #FFFFFF; border-right: 1px solid #E1E4E8; display: flex; flex-direction: column; transition: var(--transition); position: relative; z-index: 2; } .sidebar-header { padding: 20px; border-bottom: 1px solid #E1E4E8; display: flex; justify-content: space-between; align-items: center; } .logo { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 16px; color: var(--primary); } .logo-icon { width: 28px; height: 28px; background-color: var(--primary); border-radius: 6px; display: flex; align-items: center; justify-content: center; color: white; } .search-container { padding: 15px; position: relative; } .search-input { width: 100%; padding: 10px 15px 10px 35px; border-radius: 20px; border: none; background-color: var(--light); font-size: 14px; transition: var(--transition); } .search-input:focus { outline: none; box-shadow: 0 0 0 2px var(--primary-light); } .search-icon { position: absolute; left: 25px; top: 50%; transform: translateY(-50%); color: var(--secondary); font-size: 14px; } .tabs { display: flex; border-bottom: 1px solid #E1E4E8; padding: 0 15px; } .tab { padding: 10px 15px; font-size: 14px; font-weight: 500; color: var(--secondary); cursor: pointer; position: relative; transition: var(--transition); user-select: none; } .tab.active { color: var(--primary); } .tab.active:after { content: ''; position: absolute; bottom: -1px; left: 0; width: 100%; height: 2px; background-color: var(--primary); } .tab-badge { background-color: var(--primary); color: white; font-size: 10px; font-weight: 600; padding: 2px 6px; border-radius: 10px; margin-left: 5px; } .contact-list { flex: 1; overflow-y: auto; padding: 10px 0; } .contact-list::-webkit-scrollbar { width: 5px; } .contact-list::-webkit-scrollbar-thumb { background-color: rgba(108, 122, 137, 0.2); border-radius: 10px; } .contact-list::-webkit-scrollbar-thumb:hover { background-color: rgba(108, 122, 137, 0.4); } .contact-item { padding: 10px 15px; display: flex; align-items: center; gap: 12px; cursor: pointer; transition: var(--transition); border-left: 3px solid transparent; position: relative; } .contact-item:hover { background-color: var(--primary-light); } .contact-item.active { background-color: var(--primary-light); border-left-color: var(--primary); } .avatar { width: 40px; height: 40px; border-radius: 50%; background-color: var(--light); display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 16px; color: var(--dark); position: relative; } .avatar.group { background-color: var(--primary-light); color: var(--primary); } .avatar img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; } .status-indicator { width: 10px; height: 10px; border-radius: 50%; background-color: var(--success); border: 2px solid white; position: absolute; bottom: 0; right: 0; } .status-indicator.away { background-color: var(--warning); } .status-indicator.offline { background-color: var(--secondary); } .contact-info { flex: 1; min-width: 0; } .contact-name { font-weight: 500; font-size: 14px; color: var(--dark); margin-bottom: 2px; display: flex; align-items: center; justify-content: space-between; } .contact-preview { font-size: 12px; color: var(--secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; gap: 4px; } .message-status { font-size: 14px; color: var(--secondary); margin-left: 5px; } .message-time { font-size: 11px; color: var(--secondary); } .unread-badge { background-color: var(--primary); color: white; font-size: 11px; font-weight: 600; width: 18px; height: 18px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-left: auto; } .sidebar-footer { padding: 15px; border-top: 1px solid #E1E4E8; display: flex; align-items: center; gap: 10px; } .user-avatar { width: 36px; height: 36px; border-radius: 50%; background-color: var(--primary-light); color: var(--primary); display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 14px; } .user-info { flex: 1; min-width: 0; } .user-name { font-weight: 500; font-size: 13px; color: var(--dark); } .user-role { font-size: 11px; color: var(--secondary); } .user-controls { display: flex; gap: 10px; } .icon-button { width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--secondary); transition: var(--transition); } .icon-button:hover { background-color: var(--light); color: var(--primary); } .chat-area { flex: 1; display: flex; flex-direction: column; background-color: white; position: relative; z-index: 1; } .chat-header { padding: 15px 20px; border-bottom: 1px solid #E1E4E8; display: flex; align-items: center; gap: 15px; } .menu-toggle { display: none; font-size: 18px; cursor: pointer; width: 32px; height: 32px; border-radius: 50%; align-items: center; justify-content: center; } .menu-toggle:hover { background-color: var(--light); } .chat-title { flex: 1; } .chat-name { font-weight: 600; font-size: 16px; color: var(--dark); margin-bottom: 2px; display: flex; align-items: center; gap: 5px; } .chat-participants { font-size: 12px; color: var(--secondary); } .chat-actions { display: flex; gap: 10px; } .messages-container { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 15px; } .messages-container::-webkit-scrollbar { width: 5px; } .messages-container::-webkit-scrollbar-thumb { background-color: rgba(108, 122, 137, 0.2); border-radius: 10px; } .messages-container::-webkit-scrollbar-thumb:hover { background-color: rgba(108, 122, 137, 0.4); } .date-divider { text-align: center; font-size: 12px; color: var(--secondary); margin: 10px 0; position: relative; } .date-divider:before, .date-divider:after { content: ''; position: absolute; top: 50%; width: calc(50% - 70px); height: 1px; background-color: #E1E4E8; } .date-divider:before { left: 0; } .date-divider:after { right: 0; } .message { display: flex; gap: 10px; max-width: 80%; animation: fadeIn 0.3s ease; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .message.outgoing { align-self: flex-end; flex-direction: row-reverse; } .message-avatar { width: 32px; height: 32px; border-radius: 50%; background-color: var(--light); display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 12px; color: var(--dark); flex-shrink: 0; } .message-avatar img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; } .message-content { display: flex; flex-direction: column; gap: 2px; } .message-bubble { padding: 10px 15px; border-radius: 18px; font-size: 14px; max-width: 100%; word-wrap: break-word; position: relative; } .message.incoming .message-bubble { background-color: var(--light); color: var(--dark); border-top-left-radius: 4px; } .message.outgoing .message-bubble { background-color: var(--primary); color: white; border-top-right-radius: 4px; } .message-sender { font-size: 12px; font-weight: 500; color: var(--secondary); margin-bottom: 2px; } .message-meta { display: flex; align-items: center; gap: 5px; font-size: 11px; color: var(--secondary); margin-left: auto; margin-top: 2px; } .message.outgoing .message-meta { color: #e0e0e0; } .typing-indicator { display: flex; align-items: center; gap: 4px; padding: 5px 12px; background-color: var(--light); border-radius: 18px; font-size: 12px; width: fit-content; color: var(--secondary); margin-top: 5px; } .typing-dot { width: 5px; height: 5px; border-radius: 50%; background-color: var(--secondary); animation: typingAnimation 1.5s infinite ease-in-out; } .typing-dot:nth-child(1) { animation-delay: 0s; } .typing-dot:nth-child(2) { animation-delay: 0.3s; } .typing-dot:nth-child(3) { animation-delay: 0.6s; } @keyframes typingAnimation { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } } .message-box { padding: 15px 20px; border-top: 1px solid #E1E4E8; display: flex; align-items: center; gap: 10px; } .message-input-container { flex: 1; position: relative; } .message-input { width: 100%; padding: 12px 15px; border-radius: 20px; border: 1px solid #E1E4E8; font-size: 14px; transition: var(--transition); resize: none; height: 45px; max-height: 120px; overflow-y: auto; } .message-input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 2px var(--primary-light); } .attachment-button { width: 38px; height: 38px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--secondary); transition: var(--transition); background-color: var(--light); } .attachment-button:hover { background-color: var(--primary-light); color: var(--primary); } .send-button { width: 38px; height: 38px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; background-color: var(--primary); color: white; transition: var(--transition); border: none; } .send-button:hover { background-color: #1a46e0; transform: scale(1.05); } .send-button:disabled { background-color: var(--secondary); cursor: not-allowed; opacity: 0.7; } .emoji-button { position: absolute; right: 15px; top: 50%; transform: translateY(-50%); color: var(--secondary); cursor: pointer; transition: var(--transition); } .emoji-button:hover { color: var(--primary); } .emoji-picker { position: absolute; bottom: 50px; right: 0; background-color: white; border-radius: 10px; box-shadow: var(--shadow); width: 250px; height: 250px; overflow-y: auto; display: none; padding: 10px; z-index: 10; grid-template-columns: repeat(6, 1fr); gap: 8px; } .emoji { font-size: 20px; cursor: pointer; text-align: center; padding: 5px; border-radius: 5px; transition: var(--transition); } .emoji:hover { background-color: var(--light); } .create-thread-modal { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 100; opacity: 0; visibility: hidden; transition: var(--transition); } .create-thread-modal.active { opacity: 1; visibility: visible; } .modal-content { background-color: white; border-radius: var(--border-radius); width: 90%; max-width: 500px; padding: 20px; animation: modalSlideIn 0.3s ease; } @keyframes modalSlideIn { from { transform: translateY(-20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .modal-title { font-size: 18px; font-weight: 600; color: var(--dark); } .close-modal { cursor: pointer; color: var(--secondary); font-size: 20px; transition: var(--transition); } .close-modal:hover { color: var(--danger); } .modal-form { display: flex; flex-direction: column; gap: 15px; } .form-group { display: flex; flex-direction: column; gap: 5px; } .form-label { font-size: 14px; font-weight: 500; color: var(--dark); } .form-input { padding: 10px; border-radius: 6px; border: 1px solid #E1E4E8; font-size: 14px; transition: var(--transition); } .form-input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 2px var(--primary-light); } .participant-chips { display: flex; flex-wrap: wrap; gap: 8px; padding: 5px 0; } .participant-chip { display: flex; align-items: center; gap: 5px; padding: 5px 10px; background-color: var(--primary-light); border-radius: 15px; font-size: 12px; color: var(--primary); } .remove-participant { cursor: pointer; color: var(--primary); font-size: 14px; transition: var(--transition); } .remove-participant:hover { color: var(--danger); } .modal-buttons { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; } .modal-button { padding: 8px 15px; border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; transition: var(--transition); } .cancel-button { background-color: var(--light); color: var(--secondary); border: none; } .cancel-button:hover { background-color: #e5e5e5; } .create-button { background-color: var(--primary); color: white; border: none; } .create-button:hover { background-color: #1a46e0; } .empty-state { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 20px; text-align: center; color: var(--secondary); } .empty-icon { font-size: 50px; margin-bottom: 15px; color: #d0d0d0; } .empty-text { font-size: 16px; font-weight: 500; margin-bottom: 10px; color: var(--dark); } .empty-subtext { font-size: 14px; color: var(--secondary); max-width: 300px; margin: 0 auto; } .empty-button { margin-top: 20px; padding: 8px 15px; background-color: var(--primary); color: white; border: none; border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; transition: var(--transition); } .empty-button:hover { background-color: #1a46e0; transform: translateY(-2px); } /* Tooltip styles */ [data-tooltip] { position: relative; } [data-tooltip]:hover:after { content: attr(data-tooltip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background-color: var(--dark); color: white; font-size: 12px; padding: 5px 8px; border-radius: 4px; white-space: nowrap; z-index: 10; margin-bottom: 5px; } [data-tooltip]:hover:before { content: ''; position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); border: 5px solid transparent; border-top-color: var(--dark); margin-bottom: -5px; z-index: 10; } /* Animation for notification */ @keyframes pulse { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.1); opacity: 0.7; } 100% { transform: scale(1); opacity: 1; } } .notification-pulse { animation: pulse 1.5s infinite; } /* Responsive styles */ @media screen and (max-width: 768px) { .sidebar { position: absolute; left: -280px; height: 100%; z-index: 10; } .sidebar.active { left: 0; } .menu-toggle { display: flex; } .message { max-width: 90%; } } </style> </head> <body> <div class="app-container"> <!-- Sidebar --> <div class="sidebar" id="sidebar"> <div class="sidebar-header"> <div class="logo"> <div class="logo-icon"> <i class="fas fa-comments"></i> </div> <span>CorporateSync</span> </div> <div class="icon-button" id="create-thread" data-tooltip="Create new thread"> <i class="fas fa-plus"></i> </div> </div> <div class="search-container"> <i class="fas fa-search search-icon"></i> <input type="text" class="search-input" placeholder="Search conversations..."> </div> <div class="tabs"> <div class="tab active">Recent</div> <div class="tab">Teams <span class="tab-badge">3</span></div> <div class="tab">Channels</div> </div> <div class="contact-list" id="contact-list"> <div class="contact-item active" data-id="1"> <div class="avatar group"> <i class="fas fa-users"></i> </div> <div class="contact-info"> <div class="contact-name"> <span>Product Team</span> <span class="message-time">10:42 AM</span> </div> <div class="contact-preview"> <span>Sarah: Let's finalize the UX for the dashboard by EOD</span> </div> </div> <div class="unread-badge">4</div> </div> <div class="contact-item" data-id="2"> <div class="avatar"> <img src="https://randomuser.me/api/portraits/men/32.jpg" alt="Michael Chen"> <div class="status-indicator"></div> </div> <div class="contact-info"> <div class="contact-name"> <span>Michael Chen</span> <span class="message-time">9:30 AM</span> </div> <div class="contact-preview"> <span>I've pushed the updated code to the repository</span> <i class="fas fa-check-double message-status"></i> </div> </div> </div> <div class="contact-item" data-id="3"> <div class="avatar group"> <i class="fas fa-users"></i> </div> <div class="contact-info"> <div class="contact-name"> <span>Q4 Marketing Campaign</span> <span class="message-time">Yesterday</span> </div> <div class="contact-preview"> <span>Emma: Here's the latest social media analytics report</span> </div> </div> <div class="unread-badge">2</div> </div> <div class="contact-item" data-id="4"> <div class="avatar"> <img src="https://randomuser.me/api/portraits/women/42.jpg" alt="Alicia Wong"> <div class="status-indicator away"></div> </div> <div class="contact-info"> <div class="contact-name"> <span>Alicia Wong</span> <span class="message-time">Yesterday</span> </div> <div class="contact-preview"> <span>Can we schedule a call to discuss the client feedback?</span> <i class="fas fa-check-double message-status"></i> </div> </div> </div> <div class="contact-item" data-id="5"> <div class="avatar"> <img src="https://randomuser.me/api/portraits/men/55.jpg" alt="David Johnson"> <div class="status-indicator offline"></div> </div> <div class="contact-info"> <div class="contact-name"> <span>David Johnson</span> <span class="message-time">Monday</span> </div> <div class="contact-preview"> <span>I'll review the sales report and get back to you</span> <i class="fas fa-check-double message-status"></i> </div> </div> </div> <div class="contact-item" data-id="6"> <div class="avatar group"> <i class="fas fa-users"></i> </div> <div class="contact-info"> <div class="contact-name"> <span>IT Support</span> <span class="message-time">Monday</span> </div> <div class="contact-preview"> <span>James: Network maintenance scheduled for tonight</span> </div> </div> </div> <div class="contact-item" data-id="7"> <div class="avatar"> <img src="https://randomuser.me/api/portraits/women/22.jpg" alt="Sophie Martin"> <div class="status-indicator"></div> </div> <div class="contact-info"> <div class="contact-name"> <span>Sophie Martin</span> <span class="message-time">Sunday</span> </div> <div class="contact-preview"> <span>The investor presentation looks great! Nice work.</span> <i class="fas fa-check message-status"></i> </div> </div> </div> </div> <div class="sidebar-footer"> <div class="user-avatar"> JD </div> <div class="user-info"> <div class="user-name">John Doe</div> <div class="user-role">Product Manager</div> </div> <div class="user-controls"> <div class="icon-button" data-tooltip="Settings"> <i class="fas fa-cog"></i> </div> <div class="icon-button" data-tooltip="Sign out"> <i class="fas fa-sign-out-alt"></i> </div> </div> </div> </div> <!-- Chat Area --> <div class="chat-area"> <div class="chat-header"> <div class="menu-toggle" id="menu-toggle"> <i class="fas fa-bars"></i> </div> <div class="avatar group"> <i class="fas fa-users"></i> </div> <div class="chat-title"> <div class="chat-name"> Product Team <i class="fas fa-thumbtack" style="font-size: 12px; color: var(--primary);"></i> </div> <div class="chat-participants">8 participants β’ Created by Alex Thompson</div> </div> <div class="chat-actions"> <div class="icon-button" data-tooltip="Search in conversation"> <i class="fas fa-search"></i> </div> <div class="icon-button" data-tooltip="Voice call"> <i class="fas fa-phone"></i> </div> <div class="icon-button" data-tooltip="Video call"> <i class="fas fa-video"></i> </div> <div class="icon-button" data-tooltip="More options"> <i class="fas fa-ellipsis-v"></i> </div> </div> </div> <div class="messages-container" id="messages-container"> <div class="date-divider">Today, July 12, 2023</div> <div class="message incoming"> <div class="message-avatar"> <img src="https://randomuser.me/api/portraits/women/65.jpg" alt="Sarah Peterson"> </div> <div class="message-content"> <div class="message-sender">Sarah Peterson</div> <div class="message-bubble"> Good morning team! We need to finalize the dashboard UX designs today. The client is expecting to see the prototype tomorrow. </div> <div class="message-meta">9:30 AM</div> </div> </div> <div class="message incoming"> <div class="message-avatar"> <img src="https://randomuser.me/api/portraits/men/32.jpg" alt="Michael Chen"> </div> <div class="message-content"> <div class="message-sender">Michael Chen</div> <div class="message-bubble"> I've already completed the user flow diagrams and wireframes. @Alex, could you review them before I share with the team? </div> <div class="message-meta">9:45 AM</div> </div> </div> <div class="message outgoing"> <div class="message-avatar"> JD </div> <div class="message-content"> <div class="message-bubble"> Sure, Michael. Please send them over. I'd like to check how they align with the requirements document from last week's meeting. </div> <div class="message-meta">10:02 AM <i class="fas fa-check-double"></i></div> </div> </div> <div class="message incoming"> <div class="message-avatar"> <img src="https://randomuser.me/api/portraits/women/42.jpg" alt="Alicia Wong"> </div> <div class="message-content"> <div class="message-sender">Alicia Wong</div> <div class="message-bubble"> I've finished the branding assets for the dashboard. Here's the link to the design system I created in Figma: <a href="#" style="color: inherit; text-decoration: underline;">https://figma.com/file/dashboard-design-system</a> </div> <div class="message-meta">10:15 AM</div> </div> </div> <div class="message outgoing"> <div class="message-avatar"> JD </div> <div class="message-content"> <div class="message-bubble"> Thanks Alicia, the branding looks consistent with our guidelines. Can everyone join a quick sync at 2 PM to finalize the designs? </div> <div class="message-meta">10:20 AM <i class="fas fa-check"></i></div> </div> </div> <div class="message incoming"> <div class="message-avatar"> <img src="https://randomuser.me/api/portraits/women/65.jpg" alt="Sarah Peterson"> </div> <div class="message-content"> <div class="message-sender">Sarah Peterson</div> <div class="message-bubble"> Let's finalize the UX for the dashboard by EOD. We need to submit it for QA testing first thing tomorrow. </div> <div class="message-meta">10:42 AM</div> </div> </div> <div class="message incoming"> <div class="message-content"> <div class="typing-indicator"> <div class="typing-dot"></div> <div class="typing-dot"></div> <div class="typing-dot"></div> </div> </div> </div> </div> <div class="message-box"> <div class="
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>E-Commerce Live Chat</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f9f4ef; font-size: 14px; } .chat-container { width: 100%; max-width: 680px; height: 680px; background-color: #fff; border-radius: 16px; box-shadow: 0 10px 30px rgba(202, 145, 95, 0.15); display: flex; flex-direction: column; overflow: hidden; position: relative; } .chat-header { padding: 20px; background: linear-gradient(135deg, #f9b572, #e07a5f); color: white; display: flex; align-items: center; justify-content: space-between; border-radius: 16px 16px 0 0; } .header-info { display: flex; align-items: center; } .avatar { width: 40px; height: 40px; border-radius: 50%; background-color: #fff; display: flex; align-items: center; justify-content: center; margin-right: 12px; overflow: hidden; } .avatar img { width: 100%; height: 100%; object-fit: cover; } .agent-name { font-weight: 600; margin-bottom: 3px; } .agent-status { font-size: 12px; opacity: 0.8; display: flex; align-items: center; } .status-dot { width: 8px; height: 8px; background-color: #4ade80; border-radius: 50%; display: inline-block; margin-right: 5px; animation: pulse 2s infinite; } @keyframes pulse { 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(74, 222, 128, 0.7); } 70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(74, 222, 128, 0); } 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(74, 222, 128, 0); } } .header-actions { display: flex; gap: 15px; } .header-actions button { background: transparent; border: none; color: white; cursor: pointer; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: background-color 0.3s; } .header-actions button:hover { background-color: rgba(255, 255, 255, 0.2); } .header-actions i { font-size: 16px; } .chat-body { flex: 1; padding: 20px; overflow-y: auto; display: flex; flex-direction: column; gap: 15px; background-color: #fcfaf7; } .message { max-width: 80%; padding: 12px 16px; border-radius: 18px; position: relative; animation: fadeIn 0.3s ease-out; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .message.agent { align-self: flex-start; background-color: #fff; color: #333; border-bottom-left-radius: 4px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); } .message.user { align-self: flex-end; background-color: #e07a5f; color: white; border-bottom-right-radius: 4px; box-shadow: 0 2px 10px rgba(224, 122, 95, 0.2); } .time { font-size: 10px; opacity: 0.7; margin-top: 5px; text-align: right; } .message-status { display: inline-block; margin-left: 5px; font-size: 12px; } .product-preview { margin-top: 10px; border-radius: 10px; overflow: hidden; border: 1px solid rgba(0, 0, 0, 0.1); background-color: white; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05); transform: scale(1); transition: transform 0.3s; } .product-preview:hover { transform: scale(1.02); } .product-img { width: 100%; height: 150px; object-fit: cover; background-color: #f8f8f8; } .product-info { padding: 12px; } .product-name { font-weight: 600; margin-bottom: 5px; color: #333; } .product-price { color: #e07a5f; font-weight: 600; margin-bottom: 10px; } .product-actions { display: flex; gap: 8px; } .action-button { flex: 1; padding: 8px; border: none; border-radius: 6px; font-weight: 500; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; justify-content: center; font-size: 13px; } .view-button { background-color: #f9f4ef; color: #333; } .view-button:hover { background-color: #f0e9e0; } .add-button { background-color: #e07a5f; color: white; } .add-button:hover { background-color: #d16e53; } .add-button i { margin-right: 4px; } .typing-indicator { display: flex; align-items: center; padding: 10px 16px; background-color: #fff; border-radius: 18px; align-self: flex-start; margin-top: 5px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); max-width: 100px; } .typing-indicator span { width: 8px; height: 8px; background-color: #e07a5f; border-radius: 50%; display: inline-block; margin: 0 2px; opacity: 0.4; } .typing-indicator span:nth-child(1) { animation: typing 1.5s infinite 0s; } .typing-indicator span:nth-child(2) { animation: typing 1.5s infinite 0.3s; } .typing-indicator span:nth-child(3) { animation: typing 1.5s infinite 0.6s; } @keyframes typing { 0% { transform: translateY(0); opacity: 0.4; } 25% { transform: translateY(-5px); opacity: 1; } 50% { transform: translateY(0); opacity: 0.4; } 100% { transform: translateY(0); opacity: 0.4; } } .chat-footer { padding: 15px 20px; background-color: #fff; border-top: 1px solid rgba(0, 0, 0, 0.05); display: flex; align-items: center; gap: 10px; position: relative; } .input-container { flex: 1; position: relative; } .input-field { width: 100%; padding: 12px 45px 12px 15px; border-radius: 25px; border: 1px solid rgba(0, 0, 0, 0.1); outline: none; background-color: #f9f4ef; transition: border-color 0.3s, box-shadow 0.3s; } .input-field:focus { border-color: #e07a5f; box-shadow: 0 0 0 3px rgba(224, 122, 95, 0.1); } .quick-actions { position: absolute; right: 15px; top: 50%; transform: translateY(-50%); display: flex; gap: 8px; } .quick-action { background: transparent; border: none; color: #777; cursor: pointer; font-size: 16px; width: 24px; height: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: color 0.3s, background-color 0.3s; } .quick-action:hover { color: #e07a5f; background-color: rgba(224, 122, 95, 0.1); } .send-button { background-color: #e07a5f; border: none; color: white; width: 45px; height: 45px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: transform 0.3s, background-color 0.3s; box-shadow: 0 3px 10px rgba(224, 122, 95, 0.3); } .send-button:hover { transform: scale(1.05); background-color: #d16e53; } .send-button i { font-size: 18px; } .quick-replies { padding: 10px 20px; display: flex; gap: 10px; overflow-x: auto; background-color: #fff; border-top: 1px solid rgba(0, 0, 0, 0.05); scrollbar-width: none; -ms-overflow-style: none; } .quick-replies::-webkit-scrollbar { display: none; } .quick-reply { padding: 8px 16px; border-radius: 20px; border: 1px solid rgba(224, 122, 95, 0.3); background-color: #fff; color: #e07a5f; white-space: nowrap; cursor: pointer; transition: all 0.3s; font-size: 13px; } .quick-reply:hover { background-color: #e07a5f; color: white; border-color: #e07a5f; } .notification { position: absolute; top: 15px; left: 50%; transform: translateX(-50%); background-color: rgba(0, 0, 0, 0.7); color: white; padding: 8px 16px; border-radius: 20px; font-size: 12px; z-index: 100; opacity: 0; transition: opacity 0.3s; pointer-events: none; } .notification.show { opacity: 1; animation: fadeInOut 3s forwards; } @keyframes fadeInOut { 0% { opacity: 0; transform: translate(-50%, 10px); } 10% { opacity: 1; transform: translate(-50%, 0); } 90% { opacity: 1; transform: translate(-50%, 0); } 100% { opacity: 0; transform: translate(-50%, -10px); } } @media (max-width: 700px) { .chat-container { height: 100vh; border-radius: 0; max-width: 100%; } .chat-header { border-radius: 0; } .message { max-width: 90%; } } </style> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> </head> <body> <div class="chat-container"> <div class="notification" id="notification">Product added to cart!</div> <div class="chat-header"> <div class="header-info"> <div class="avatar"> <img src="https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=100&q=80" alt="Support Agent"> </div> <div> <div class="agent-name">Sarah Miller</div> <div class="agent-status"> <span class="status-dot"></span> Online | Fashion Expert </div> </div> </div> <div class="header-actions"> <button><i class="fas fa-phone"></i></button> <button><i class="fas fa-video"></i></button> <button><i class="fas fa-ellipsis-v"></i></button> </div> </div> <div class="chat-body" id="chat-body"> <div class="message agent"> <div>Hi there! I'm Sarah from Elevated Style. How can I help you today?</div> <div class="time">10:03 AM</div> </div> <div class="message user"> <div>I'm looking for summer dresses that would be good for a beach vacation. Do you have any recommendations?</div> <div class="time">10:05 AM <span class="message-status"><i class="fas fa-check-double"></i></span></div> </div> <div class="message agent"> <div>Absolutely! We just got our new summer collection in. I'd recommend our Seaside Breeze maxi dress - it's lightweight, breathable, and perfect for beach days or evening walks along the shore.</div> <div class="time">10:07 AM</div> </div> <div class="message agent"> <div>Here's a preview of the dress:</div> <div class="product-preview"> <img src="https://images.unsplash.com/photo-1623609163859-ca93d401e455?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=400&q=80" alt="Seaside Breeze Maxi Dress" class="product-img"> <div class="product-info"> <div class="product-name">Seaside Breeze Maxi Dress</div> <div class="product-price">$79.95</div> <div class="product-actions"> <button class="action-button view-button">View Details</button> <button class="action-button add-button" id="add-to-cart"><i class="fas fa-shopping-cart"></i> Add to Cart</button> </div> </div> </div> <div class="time">10:08 AM</div> </div> <div class="message user"> <div>That looks perfect! What colors does it come in?</div> <div class="time">10:10 AM <span class="message-status"><i class="fas fa-check-double"></i></span></div> </div> <div class="typing-indicator" id="typing-indicator"> <span></span> <span></span> <span></span> </div> </div> <div class="quick-replies"> <button class="quick-reply">Do you offer free shipping?</button> <button class="quick-reply">What's your return policy?</button> <button class="quick-reply">Is this available in size M?</button> <button class="quick-reply">Any discount codes?</button> </div> <div class="chat-footer"> <div class="input-container"> <input type="text" class="input-field" id="message-input" placeholder="Type a message..."> <div class="quick-actions"> <button class="quick-action"><i class="far fa-smile"></i></button> <button class="quick-action"><i class="fas fa-paperclip"></i></button> </div> </div> <button class="send-button" id="send-button"> <i class="fas fa-paper-plane"></i> </button> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const chatBody = document.getElementById('chat-body'); const messageInput = document.getElementById('message-input'); const sendButton = document.getElementById('send-button'); const typingIndicator = document.getElementById('typing-indicator'); const addToCartButton = document.getElementById('add-to-cart'); const notification = document.getElementById('notification'); const quickReplies = document.querySelectorAll('.quick-reply'); // Initially hide typing indicator typingIndicator.style.display = 'none'; // Function to add messages function addMessage(content, isUser = false) { const messageDiv = document.createElement('div'); messageDiv.className = `message ${isUser ? 'user' : 'agent'}`; const contentDiv = document.createElement('div'); contentDiv.textContent = content; const timeDiv = document.createElement('div'); timeDiv.className = 'time'; const now = new Date(); let hours = now.getHours(); const minutes = now.getMinutes().toString().padStart(2, '0'); const ampm = hours >= 12 ? 'PM' : 'AM'; hours = hours % 12; hours = hours ? hours : 12; // Convert 0 to 12 timeDiv.innerHTML = `${hours}:${minutes} ${ampm}`; if (isUser) { const statusSpan = document.createElement('span'); statusSpan.className = 'message-status'; statusSpan.innerHTML = '<i class="fas fa-check"></i>'; // Simulate message being delivered after 1 second setTimeout(() => { statusSpan.innerHTML = '<i class="fas fa-check-double"></i>'; }, 1000); timeDiv.appendChild(statusSpan); } messageDiv.appendChild(contentDiv); messageDiv.appendChild(timeDiv); chatBody.appendChild(messageDiv); chatBody.scrollTop = chatBody.scrollHeight; return messageDiv; } // Add agent's response after typing indicator function addAgentResponse(content, delay = 2000) { // Show typing indicator typingIndicator.style.display = 'flex'; chatBody.scrollTop = chatBody.scrollHeight; setTimeout(() => { // Hide typing indicator and add message typingIndicator.style.display = 'none'; addMessage(content, false); }, delay); } // Send message on button click sendButton.addEventListener('click', () => { sendMessage(); }); // Also send message on Enter key messageInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { sendMessage(); } }); // Send message function function sendMessage() { const message = messageInput.value.trim(); if (message) { addMessage(message, true); messageInput.value = ''; // Simulate agent typing and responding if (message.toLowerCase().includes('color')) { addAgentResponse("It comes in four gorgeous colors: Ocean Blue (shown in the image), Sunset Coral, Sand Beige, and Mint Green. All of them are perfect for summer! Would you like to see the other colors?"); } else { addAgentResponse("Thanks for your message! I'll help you with that right away."); } } } // Add to cart functionality addToCartButton.addEventListener('click', () => { // Show notification notification.classList.add('show'); // Change button text temporarily addToCartButton.innerHTML = '<i class="fas fa-check"></i> Added'; addToCartButton.style.backgroundColor = '#4ade80'; // Reset button after 2 seconds setTimeout(() => { addToCartButton.innerHTML = '<i class="fas fa-shopping-cart"></i> Add to Cart'; addToCartButton.style.backgroundColor = ''; notification.classList.remove('show'); // Add agent response addAgentResponse("Great choice! I've added the Seaside Breeze Maxi Dress to your cart. Would you like to see some accessories that would pair well with it?"); }, 2000); }); // Quick replies functionality quickReplies.forEach(reply => { reply.addEventListener('click', () => { addMessage(reply.textContent, true); // Different responses based on quick reply if (reply.textContent.includes('free shipping')) { addAgentResponse("Yes! We offer free standard shipping on all orders over $50. Express shipping is available for an additional $9.95."); } else if (reply.textContent.includes('return policy')) { addAgentResponse("We have a 30-day return policy. Unworn items with tags attached can be returned for a full refund. We also offer free return shipping!"); } else if (reply.textContent.includes('size M')) { addAgentResponse("Yes, the Seaside Breeze Maxi Dress is currently available in size M in all colors. Would you like me to add it to your cart?"); } else if (reply.textContent.includes('discount')) { addAgentResponse("I can offer you a special 15% discount code for today: SUMMER15. I'll apply it to your cart automatically if you decide to make a purchase!"); } }); }); // Create ripple effect on buttons const buttons = document.querySelectorAll('.action-button, .send-button'); buttons.forEach(button => { button.addEventListener('click', function(e) { const rect = button.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; const ripple = document.createElement('span'); ripple.style.position = 'absolute'; ripple.style.width = '1px'; ripple.style.height = '1px'; ripple.style.borderRadius = '50%'; ripple.style.transform = 'scale(0)'; ripple.style.backgroundColor = 'rgba(255, 255, 255, 0.7)'; ripple.style.left = x + 'px'; ripple.style.top = y + 'px'; ripple.style.animation = 'ripple 0.6s linear'; ripple.style.pointerEvents = 'none'; button.appendChild(ripple); setTimeout(() => { ripple.remove(); }, 600); }); }); // Show the latest Seaside Breeze Maxi Dress response after 3 seconds setTimeout(() => { addAgentResponse("It comes in four gorgeous colors: Ocean Blue (shown in the image), Sunset Coral, Sand Beige, and Mint Green. All of them are perfect for summer! Would you like to see the other colors?"); }, 3000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>KnowledgeHub - Academic Group Chat</title> <style> :root { --primary: #5468FF; --primary-light: #8590FF; --primary-dark: #3A4DB2; --student: #E9EFFF; --teacher: #EBFAEF; --teacher-accent: #4CAF50; --text-dark: #1A2138; --text-light: #5F6A8A; --background: #F9FAFC; --panel: #FFFFFF; --border: #E1E5EE; --shadow: 0 4px 12px rgba(84, 104, 255, 0.10); --hover-shadow: 0 6px 16px rgba(84, 104, 255, 0.18); --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; } body { background-color: var(--background); color: var(--text-dark); width: 100%; height: 100vh; display: flex; align-items: center; justify-content: center; overflow: hidden; } .chat-container { width: 700px; height: 700px; display: flex; flex-direction: column; border-radius: 16px; background-color: var(--panel); box-shadow: var(--shadow); overflow: hidden; position: relative; } .header { padding: 16px 24px; background-color: var(--panel); border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); position: relative; z-index: 10; } .header-left { display: flex; align-items: center; gap: 12px; } .course-info { display: flex; flex-direction: column; } .course-title { font-weight: 600; font-size: 16px; color: var(--text-dark); } .course-participants { font-size: 12px; color: var(--text-light); } .header-actions { display: flex; gap: 12px; } .icon-button { width: 36px; height: 36px; border-radius: 50%; border: none; display: flex; align-items: center; justify-content: center; background-color: var(--background); color: var(--text-light); cursor: pointer; transition: var(--transition); } .icon-button:hover { background-color: var(--primary-light); color: white; transform: translateY(-2px); box-shadow: var(--hover-shadow); } .icon-button svg { width: 18px; height: 18px; } .tabs { display: flex; padding: 0 20px; background-color: var(--panel); border-bottom: 1px solid var(--border); position: relative; z-index: 5; } .tab { padding: 12px 16px; font-size: 14px; font-weight: 500; color: var(--text-light); cursor: pointer; border-bottom: 2px solid transparent; transition: var(--transition); position: relative; } .tab.active { color: var(--primary); border-bottom: 2px solid var(--primary); } .tab:hover:not(.active) { color: var(--text-dark); } .badge { position: absolute; top: 8px; right: 8px; background-color: var(--primary); color: white; font-size: 10px; font-weight: 500; padding: 1px 6px; border-radius: 10px; } .chat-content { flex: 1; overflow-y: auto; padding: 24px; display: flex; flex-direction: column; gap: 16px; scroll-behavior: smooth; } .chat-content::-webkit-scrollbar { width: 6px; } .chat-content::-webkit-scrollbar-track { background: transparent; } .chat-content::-webkit-scrollbar-thumb { background-color: var(--border); border-radius: 6px; } .message { display: flex; flex-direction: column; max-width: 80%; animation: fadeIn 0.3s ease-out; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .message.student { align-self: flex-end; } .message.teacher { align-self: flex-start; } .message-header { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; } .avatar { width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 12px; color: white; flex-shrink: 0; } .student .avatar { background-color: var(--primary); } .teacher .avatar { background-color: var(--teacher-accent); } .sender-name { font-size: 13px; font-weight: 600; } .student .sender-name { color: var(--primary-dark); } .teacher .sender-name { color: var(--teacher-accent); } .timestamp { font-size: 11px; color: var(--text-light); margin-left: auto; } .message-bubble { padding: 12px 16px; border-radius: 16px; font-size: 14px; line-height: 1.5; position: relative; transition: var(--transition); } .student .message-bubble { background-color: var(--student); border-top-right-radius: 4px; } .teacher .message-bubble { background-color: var(--teacher); border-top-left-radius: 4px; } .message-bubble:hover { transform: translateY(-2px); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); } .message-actions { display: flex; gap: 8px; margin-top: 6px; justify-content: flex-end; opacity: 0; transition: var(--transition); } .message:hover .message-actions { opacity: 1; } .action-button { background: none; border: none; font-size: 12px; color: var(--text-light); cursor: pointer; padding: 2px 6px; border-radius: 4px; transition: var(--transition); } .action-button:hover { background-color: rgba(84, 104, 255, 0.1); color: var(--primary); } .embed-content { margin-top: 10px; border-radius: 8px; overflow: hidden; border: 1px solid var(--border); background-color: white; transition: var(--transition); } .embed-content:hover { box-shadow: var(--shadow); transform: translateY(-2px); } .embed-header { padding: 10px 12px; background-color: rgba(84, 104, 255, 0.05); display: flex; align-items: center; gap: 8px; border-bottom: 1px solid var(--border); } .embed-icon { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; color: var(--primary); } .embed-title { font-size: 12px; font-weight: 500; flex: 1; } .embed-body { padding: 12px; } .embed-image { width: 100%; border-radius: 6px; height: auto; object-fit: cover; } .embed-text { font-size: 13px; color: var(--text-light); margin-top: 8px; line-height: 1.4; } .embed-footer { padding: 8px 12px; border-top: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; } .embed-button { background-color: var(--primary-light); color: white; font-size: 12px; font-weight: 500; padding: 6px 12px; border-radius: 6px; border: none; cursor: pointer; transition: var(--transition); } .embed-button:hover { background-color: var(--primary); transform: translateY(-1px); box-shadow: 0 3px 8px rgba(84, 104, 255, 0.2); } .date-divider { display: flex; align-items: center; gap: 12px; margin: 16px 0; opacity: 0.7; } .divider-line { flex: 1; height: 1px; background-color: var(--border); } .divider-text { font-size: 12px; color: var(--text-light); white-space: nowrap; } .typing-indicator { display: flex; align-items: center; gap: 4px; font-size: 12px; color: var(--text-light); padding: 8px 12px; margin-bottom: 8px; } .typing-dot { width: 5px; height: 5px; background-color: var(--text-light); border-radius: 50%; animation: typingAnimation 1.4s infinite ease-in-out; } .typing-dot:nth-child(1) { animation-delay: 0s; } .typing-dot:nth-child(2) { animation-delay: 0.2s; } .typing-dot:nth-child(3) { animation-delay: 0.4s; } @keyframes typingAnimation { 0%, 100% { transform: translateY(0); opacity: 0.5; } 50% { transform: translateY(-4px); opacity: 1; } } .input-area { padding: 16px 24px 24px; background-color: var(--panel); border-top: 1px solid var(--border); z-index: 10; } .toolbar { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; } .tool-button { background: none; border: none; cursor: pointer; width: 32px; height: 32px; border-radius: 4px; display: flex; align-items: center; justify-content: center; color: var(--text-light); transition: var(--transition); } .tool-button:hover { background-color: rgba(84, 104, 255, 0.1); color: var(--primary); } .tool-button svg { width: 18px; height: 18px; } .input-container { display: flex; gap: 12px; align-items: center; } .message-input { flex: 1; padding: 14px 16px; border-radius: 10px; border: 1px solid var(--border); background-color: var(--background); font-size: 14px; resize: none; transition: var(--transition); height: 50px; outline: none; } .message-input:focus { border-color: var(--primary-light); box-shadow: 0 0 0 2px rgba(84, 104, 255, 0.1); } .send-button { background-color: var(--primary); color: white; border: none; width: 50px; height: 50px; border-radius: 12px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: var(--transition); } .send-button:hover { background-color: var(--primary-dark); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(84, 104, 255, 0.2); } .poll-container { padding: 12px; background-color: rgba(84, 104, 255, 0.05); border-radius: 8px; margin-top: 8px; } .poll-question { font-weight: 500; margin-bottom: 10px; font-size: 13px; } .poll-options { display: flex; flex-direction: column; gap: 8px; } .poll-option { background-color: white; border: 1px solid var(--border); padding: 8px 12px; border-radius: 6px; font-size: 13px; position: relative; cursor: pointer; transition: var(--transition); display: flex; justify-content: space-between; } .poll-option:hover { border-color: var(--primary-light); background-color: rgba(84, 104, 255, 0.03); } .poll-option.selected { border-color: var(--primary); background-color: rgba(84, 104, 255, 0.1); } .poll-option.selected::before { content: ''; position: absolute; left: 0; top: 0; height: 100%; width: 3px; background-color: var(--primary); border-top-left-radius: 6px; border-bottom-left-radius: 6px; } .poll-percent { font-size: 12px; font-weight: 500; color: var(--primary); } .poll-votes { margin-top: 10px; font-size: 12px; color: var(--text-light); text-align: right; } .resource-link { display: flex; align-items: center; gap: 8px; padding: 10px; background-color: var(--background); border-radius: 6px; cursor: pointer; transition: var(--transition); text-decoration: none; color: var(--text-dark); border: 1px solid var(--border); } .resource-link:hover { background-color: rgba(84, 104, 255, 0.05); border-color: var(--primary-light); transform: translateY(-2px); box-shadow: var(--shadow); } .resource-icon { width: 36px; height: 36px; background-color: rgba(84, 104, 255, 0.1); border-radius: 6px; display: flex; align-items: center; justify-content: center; color: var(--primary); } .resource-info { flex: 1; } .resource-title { font-size: 13px; font-weight: 500; } .resource-desc { font-size: 11px; color: var(--text-light); } /* Responsive Styles */ @media (max-width: 700px) { .chat-container { width: 100%; height: 100%; border-radius: 0; } .message { max-width: 90%; } .header-actions { gap: 8px; } .icon-button { width: 32px; height: 32px; } .tabs { padding: 0 10px; } .tab { padding: 12px 10px; font-size: 13px; } } /* Animation for new messages */ @keyframes popIn { 0% { transform: scale(0.8); opacity: 0; } 50% { transform: scale(1.05); } 100% { transform: scale(1); opacity: 1; } } .pop-in { animation: popIn 0.3s forwards; } /* Resource expansion animation */ .resource-expanded { max-height: 0; overflow: hidden; transition: max-height 0.3s ease; } .resource-expanded.active { max-height: 200px; } /* Tooltip Styles */ .tooltip { position: relative; } .tooltip::after { content: attr(data-tooltip); position: absolute; bottom: 130%; left: 50%; transform: translateX(-50%); padding: 5px 10px; border-radius: 4px; background-color: rgba(26, 33, 56, 0.9); color: white; font-size: 11px; white-space: nowrap; opacity: 0; visibility: hidden; transition: all 0.2s ease; pointer-events: none; z-index: 100; } .tooltip::before { content: ''; position: absolute; bottom: 120%; left: 50%; transform: translateX(-50%); border-width: 4px; border-style: solid; border-color: rgba(26, 33, 56, 0.9) transparent transparent transparent; opacity: 0; visibility: hidden; transition: all 0.2s ease; pointer-events: none; z-index: 100; } .tooltip:hover::after, .tooltip:hover::before { opacity: 1; visibility: visible; } /* Reaction Styles */ .reactions { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; } .reaction { font-size: 12px; padding: 2px 6px 2px 4px; background-color: rgba(84, 104, 255, 0.06); border-radius: 12px; display: flex; align-items: center; gap: 3px; cursor: pointer; transition: var(--transition); } .reaction:hover { background-color: rgba(84, 104, 255, 0.15); } .reaction.active { background-color: rgba(84, 104, 255, 0.2); font-weight: 500; } </style> </head> <body> <div class="chat-container"> <div class="header"> <div class="header-left"> <div class="avatar" style="background-color: #5468FF;"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg> </div> <div class="course-info"> <div class="course-title">Advanced Environmental Science</div> <div class="course-participants">28 participants Β· Dr. Emily Chen</div> </div> </div> <div class="header-actions"> <button class="icon-button tooltip" data-tooltip="Search"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg> </button> <button class="icon-button tooltip" data-tooltip="Resource Library"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path></svg> </button> <button class="icon-button tooltip" data-tooltip="Settings"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><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"></path></svg> </button> </div> </div> <div class="tabs"> <div class="tab active">Discussion</div> <div class="tab">Assignments <span class="badge">2</span></div> <div class="tab">Resources</div> <div class="tab">Participants</div> </div> <div class="chat-content" id="chatContent"> <div class="date-divider"> <div class="divider-line"></div> <div class="divider-text">October 21, 2023</div> <div class="divider-line"></div> </div> <div class="message teacher"> <div class="message-header"> <div class="avatar">EC</div> <div class="sender-name">Dr. Emily Chen</div> <div class="timestamp">10:02 AM</div> </div> <div class="message-bubble"> Good morning everyone! Today we'll be discussing biodiversity hotspots and their significance in conservation efforts. Please share your thoughts on the reading from chapter 8. </div> <div class="message-actions"> <button class="action-button">Reply</button> <button class="action-button">Save</button> </div> <div class="reactions"> <div class="reaction">π 3</div> <div class="reaction">π 5</div> </div> </div> <div class="message student"> <div class="message-header"> <div class="avatar">JL</div> <div class="sender-name">Jamie Liang</div> <div class="timestamp">10:10 AM</div> </div> <div class="message-bubble"> I found the relationship between biodiversity and ecosystem resilience particularly fascinating. The reading mentioned that the Madagascar lowland forests have lost over 90% of their original habitat, yet they still harbor incredible endemic species diversity. </div> <div class="message-actions"> <button class="action-button">Reply</button> <button class="action-button">Save</button> </div> </div> <div class="message teacher"> <div class="message-header"> <div class="avatar">EC</div> <div class="sender-name">Dr. Emily Chen</div> <div class="timestamp">10:15 AM</div> </div> <div class="message-bubble"> Excellent point, Jamie! Madagascar is indeed one of the most important biodiversity hotspots globally. For everyone's reference, here's an interactive map of global biodiversity hotspots we'll be discussing today: </div> <div class="embed-content"> <div class="embed-header"> <div class="embed-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"></polygon><line x1="8" y1="2" x2="8" y2="18"></line><line x1="16" y1="6" x2="16" y2="22"></line></svg> </div> <div class="embed-title">Global Biodiversity Hotspots - Conservation International</div> </div> <div class="embed-body"> <img src="https://images.unsplash.com/photo-1633469924728-52a7d0d94e93?q=80&w=1000&auto=format&fit=crop" alt="Biodiversity Hotspots Map" class="embed-image"> <div class="embed-text"> Interactive map showing the 36 recognized biodiversity hotspots that collectively contain over 50% of the world's plant species and 42% of terrestrial vertebrates in just 2.3% of Earth's land surface. </div> </div> <div class="embed-footer"> <button class="embed-button" id="openResourceBtn">Open in Resource Library</button> </div> </div> <div class="message-actions"> <button class="action-button">Reply</button> <button class="action-button">Save</button> </div> <div class="reactions"> <div class="reaction">π 4</div> <div class="reaction">π‘ 7</div> </div> </div> <div class="message student"> <div class="message-header"> <div class="avatar">TK</div> <div class="sender-name">Tariq Khan</div> <div class="timestamp">10:22 AM</div> </div> <div class="message-bubble"> I'm curious about the criteria used to define a biodiversity hotspot. The reading mentions both endemism and threat level, but are there specific thresholds? </div> <div class="message-actions"> <button class="action-button">Reply</button> <button class="action-button">Save</button> </div> </div> <div class="message teacher"> <div class="message-header"> <div class="avatar">EC</div> <div class="sender-name">Dr. Emily Chen</div> <div class="timestamp">10:28 AM</div> </div> <div class="message-bubble"> Great question, Tariq! To be designated as a biodiversity hotspot, a region must meet two strict criteria: 1. It must contain at least 1,500 species of vascular plants as endemics (>0.5% of the world's total) 2. It must have lost at least 70% of its original vegetation Let's quickly check our understanding with a poll: </div> <div class="poll-container"> <div class="poll-question">Which of these is NOT one of the 36 recognized biodiversity hotspots?</div> <div class="poll-options"> <div class="poll-option" data-option="1">California Floristic Province</div> <div class="poll-option" data-option="2">Amazon Rainforest <span class="poll-percent">62%</span></div> <div class="poll-option" data-option="3">Cape Floristic Region</div> <div class="poll-option" data-option="4">Sundaland</div> </div> <div class="poll-votes">13 votes</div> </div> <div class="message-actions"> <button class="action-button">Reply</button> <button class="action-button">Save</button> </div> </div> <div class="date-divider"> <div class="divider-line"></div> <div class="divider-text">Today</div> <div class="divider-line"></div> </div> <div class="message student"> <div class="message-header"> <div class="avatar">MR</div> <div class="sender-name">Maya Rodriguez</div> <div class="timestamp">9:45 AM</div> </div> <div class="message-bubble"> For our group project on conservation strategies, I found this research paper that might be useful. It discusses novel approaches to protecting biodiversity in fragmented habitats. </div> <div class="resource-link"> <div class="resource-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg> </div> <div class="resource-info"> <div class="resource-title">Landscape connectivity and biodiversity conservation in fragmented ecosystems</div> <div class="resource-desc">Journal of Conservation Biology (2023) Β· PDF Β· 2.4MB</div> </div> </div> <div class="message-actions"> <button class="action-button">Reply</button> <button class="action-button">Save</button> </div> <div class="reactions"> <div class="reaction">π 5</div> <div class="reaction">π― 2</div> </div> </div> <div class="message teacher"> <div class="message-header"> <div class="avatar">EC</div> <div class="sender-name">Dr. Emily Chen</div> <div class="timestamp">10:02 AM</div> </div> <div class="message-bubble"> Thank you for sharing this resource, Maya! This will be very helpful for the upcoming project. I've added it to our class resource library. Just a reminder to everyone β your group presentations on conservation strategies for your assigned biodiversity hotspot are due next Friday. Please use the rubric in the Assignments tab as a guide. </div> <div class="message-actions"> <button class="action-button">Reply</button> <button class="action-button">Save</button> </div> </div> <div class="typing-indicator"> <div class="avatar" style="width: 20px; height: 20px; font-size: 10px;">JL</div> <span>Jamie Liang is typing</span> <div class="typing-dot"></div> <div class="typing-dot"></div> <div class="typing-dot"></div> </div> </div> <div class="input-area"> <div class="toolbar"> <button class="tool-button tooltip" data-tooltip="Attach File"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>SecureHealth Connect</title> <style> :root { --primary-color: #2a7fff; --secondary-color: #e6f0ff; --tertiary-color: #f0f7ff; --success-color: #00c48c; --text-color: #2c3e50; --light-text: #7c8999; --border-radius: 12px; --box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08); --transition: all 0.3s ease; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f9fafc; color: var(--text-color); display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 20px; } .app-container { width: 100%; max-width: 680px; height: 680px; background-color: white; border-radius: var(--border-radius); box-shadow: var(--box-shadow); overflow: hidden; position: relative; display: flex; flex-direction: column; } .chat-header { padding: 20px; background-color: white; box-shadow: 0 2px 15px rgba(0, 0, 0, 0.05); display: flex; align-items: center; position: relative; z-index: 2; } .provider-info { display: flex; align-items: center; flex-grow: 1; } .provider-avatar { width: 50px; height: 50px; border-radius: 50%; object-fit: cover; margin-right: 15px; border: 2px solid var(--secondary-color); } .provider-name { display: flex; flex-direction: column; } .provider-name h3 { font-weight: 600; margin-bottom: 2px; color: var(--text-color); } .provider-status { display: flex; align-items: center; color: var(--success-color); font-size: 0.9rem; } .status-dot { width: 8px; height: 8px; background-color: var(--success-color); border-radius: 50%; margin-right: 5px; position: relative; } .status-dot::after { content: ''; position: absolute; width: 100%; height: 100%; border-radius: 50%; background-color: var(--success-color); opacity: 0.5; animation: pulse 2s infinite; } .chat-actions { display: flex; align-items: center; } .action-button { width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-left: 10px; background-color: var(--secondary-color); color: var(--primary-color); cursor: pointer; transition: var(--transition); border: none; } .action-button:hover { background-color: var(--primary-color); color: white; transform: translateY(-2px); } .icon { width: 20px; height: 20px; fill: currentColor; } .secure-badge { display: flex; align-items: center; font-size: 0.8rem; color: var(--success-color); font-weight: 500; padding: 5px 10px; margin-right: 10px; border-radius: 12px; background-color: rgba(0, 196, 140, 0.1); } .secure-badge svg { margin-right: 5px; } .chat-content { flex-grow: 1; padding: 20px; overflow-y: auto; display: flex; flex-direction: column; background-color: var(--tertiary-color); position: relative; } .chat-bubble { max-width: 75%; padding: 15px; margin-bottom: 15px; border-radius: 18px; position: relative; line-height: 1.5; opacity: 0; transform: translateY(20px); animation: fadeIn 0.5s forwards; } .chat-bubble.sent { align-self: flex-end; background-color: var(--primary-color); color: white; border-bottom-right-radius: 4px; } .chat-bubble.received { align-self: flex-start; background-color: white; border-bottom-left-radius: 4px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); } .message-time { font-size: 0.7rem; opacity: 0.7; margin-top: 5px; text-align: right; } .message-status { display: flex; align-items: center; justify-content: flex-end; font-size: 0.7rem; color: rgba(255, 255, 255, 0.7); margin-top: 2px; } .encryption-animation { display: inline-block; width: 14px; height: 14px; margin-right: 4px; position: relative; } .encryption-dot { position: absolute; width: 3px; height: 3px; background-color: currentColor; border-radius: 50%; opacity: 0; } .chat-input-container { padding: 15px; background-color: white; box-shadow: 0 -2px 15px rgba(0, 0, 0, 0.05); position: relative; z-index: 2; } .input-privacy-notice { font-size: 0.75rem; color: var(--light-text); text-align: center; margin-bottom: 10px; display: flex; align-items: center; justify-content: center; } .input-privacy-notice svg { margin-right: 5px; } .chat-input-wrapper { display: flex; align-items: center; background-color: var(--tertiary-color); border-radius: 30px; padding: 5px; box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.03); } .attachment-button, .send-button { width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background-color: var(--secondary-color); color: var(--primary-color); cursor: pointer; transition: var(--transition); border: none; } .send-button { background-color: var(--primary-color); color: white; } .attachment-button:hover, .send-button:hover { transform: scale(1.05); } .chat-input { flex-grow: 1; background: none; border: none; padding: 10px 15px; outline: none; font-size: 0.95rem; color: var(--text-color); } .appointment-reminder { background-color: white; border-radius: var(--border-radius); padding: 15px; margin: 15px 0; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); border-left: 4px solid var(--primary-color); align-self: center; width: 90%; transition: var(--transition); animation: fadeIn 0.5s forwards; opacity: 0; transform: translateY(20px); } .appointment-reminder h4 { margin-bottom: 5px; color: var(--primary-color); } .appointment-reminder p { font-size: 0.9rem; color: var(--light-text); margin-bottom: 10px; } .reminder-buttons { display: flex; justify-content: flex-end; } .reminder-button { background: none; border: none; padding: 5px 10px; border-radius: 15px; font-size: 0.8rem; cursor: pointer; transition: var(--transition); font-weight: 500; } .reminder-button.confirm { background-color: var(--primary-color); color: white; margin-left: 10px; } .reminder-button.reschedule { color: var(--primary-color); } .reminder-button:hover { transform: translateY(-2px); } .encryption-indicator { display: flex; align-items: center; justify-content: center; font-size: 0.7rem; color: var(--light-text); margin-top: 5px; opacity: 0; animation: fadeIn 1s forwards; animation-delay: 0.5s; } .encryption-indicator svg { margin-right: 5px; animation: secureGlow 2s infinite alternate; } @keyframes pulse { 0% { transform: scale(1); opacity: 0.5; } 70% { transform: scale(1.5); opacity: 0; } 100% { transform: scale(1); opacity: 0; } } @keyframes fadeIn { to { opacity: 1; transform: translateY(0); } } @keyframes secureGlow { from { filter: drop-shadow(0 0 1px var(--success-color)); } to { filter: drop-shadow(0 0 3px var(--success-color)); } } .typing-indicator { align-self: flex-start; background-color: white; border-radius: 18px; padding: 15px; margin-bottom: 15px; display: none; animation: fadeIn 0.3s forwards; } .typing-dots { display: flex; } .typing-dot { width: 8px; height: 8px; border-radius: 50%; background-color: var(--light-text); margin-right: 4px; animation: typingAnimation 1.5s infinite ease-in-out; } .typing-dot:nth-child(2) { animation-delay: 0.2s; } .typing-dot:nth-child(3) { animation-delay: 0.4s; margin-right: 0; } @keyframes typingAnimation { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } } .privacy-tooltip { position: absolute; bottom: 80px; left: 50%; transform: translateX(-50%); background-color: var(--text-color); color: white; padding: 10px 15px; border-radius: 6px; font-size: 0.8rem; z-index: 10; width: max-content; max-width: 280px; opacity: 0; pointer-events: none; transition: opacity 0.3s ease; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2); } .privacy-tooltip::after { content: ''; position: absolute; bottom: -5px; left: 50%; transform: translateX(-50%); border-width: 5px 5px 0; border-style: solid; border-color: var(--text-color) transparent transparent; } .input-privacy-notice:hover + .privacy-tooltip { opacity: 1; } @media (max-width: 600px) { .chat-bubble { max-width: 85%; } .appointment-reminder { width: 95%; } .provider-status span { display: none; } } .encryption-animation .encryption-line { position: absolute; height: 1px; background-color: currentColor; width: 0; opacity: 0.7; animation: encryptLine 2s ease-in-out; } @keyframes encryptLine { 0% { width: 0; opacity: 0.7; } 50% { width: 100%; opacity: 0.7; } 100% { width: 100%; opacity: 0; } } .file-attachment { display: flex; align-items: center; background-color: rgba(255, 255, 255, 0.2); border-radius: 8px; padding: 8px; margin-top: 8px; } .file-attachment svg { margin-right: 8px; } .file-name { font-size: 0.85rem; flex-grow: 1; } .file-size { font-size: 0.75rem; opacity: 0.7; } .message-encryption-active { display: inline-flex; align-items: center; animation: encryptionFade 2s forwards; } @keyframes encryptionFade { 0% { opacity: 1; } 80% { opacity: 1; } 100% { opacity: 0.5; } } .wave-bg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0.05; pointer-events: none; background-image: url("data:image/svg+xml,%3Csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cpattern id='pattern' width='100' height='30' patternUnits='userSpaceOnUse'%3E%3Cpath d='M0 15 Q 10 5, 20 15 T 40 15 T 60 15 T 80 15 T 100 15' stroke='%232a7fff' fill='none' stroke-width='1'/%3E%3C/pattern%3E%3C/defs%3E%3Crect width='100%25' height='100%25' fill='url(%23pattern)'/%3E%3C/svg%3E"); } /* Animated pulse button */ .emergency-button { background-color: rgba(255, 59, 48, 0.1); color: #ff3b30; border: 1px solid rgba(255, 59, 48, 0.3); padding: 6px 15px; border-radius: 20px; font-size: 0.8rem; font-weight: 500; margin-right: 15px; cursor: pointer; transition: all 0.2s ease; position: relative; overflow: hidden; } .emergency-button:hover { background-color: rgba(255, 59, 48, 0.2); } .emergency-button::after { content: ''; position: absolute; width: 30px; height: 30px; background: rgba(255, 59, 48, 0.4); border-radius: 50%; left: 50%; top: 50%; transform: translate(-50%, -50%) scale(0); opacity: 0; animation: emergencyPulse 2s infinite; } @keyframes emergencyPulse { 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; } 100% { transform: translate(-50%, -50%) scale(3); opacity: 0; } } </style> </head> <body> <div class="app-container"> <div class="chat-header"> <div class="provider-info"> <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIHZpZXdCb3g9IjAgMCAxOTIgMTkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxjaXJjbGUgZmlsbD0iI2U2ZjBmZiIgY3g9Ijk2IiBjeT0iOTYiIHI9Ijk2Ii8+PHBhdGggZmlsbD0iIzJhN2ZmZiIgZD0iTTk2IDE0MmMtMTggMC0zMy04LTQyLTIyLTEtMS0xLTItMS0zIDMtOCAxMC0xNCAyMC0xOGwyMy0xMCAyMy0xMGMzLTEgNS0yIDYtNnYtNGMtNi01LTEwLTEzLTEwLTIzIDAtMTQgOS0yNSAyMC0yNSAxMiAwIDIxIDExIDIxIDI1IDAgOS00IDE3LTEwIDIzdjRjMSA0IDMgNSA2IDZsMjMgMTAgMjMgMTBjMTAgNCA5IDE1IDkgMTggMCAxLTEgMi0xIDNhNTcgNTcgMCAwMS00MiAyMkg5NnoiLz48L3N2Zz4=" alt="Dr. Sarah Chen" class="provider-avatar"> <div class="provider-name"> <h3>Dr. Sarah Chen</h3> <div class="provider-status"> <div class="status-dot"></div> <span>Available for Consultation</span> </div> </div> </div> <div class="chat-actions"> <button class="emergency-button"> Emergency Access </button> <div class="secure-badge"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none"> <path d="M12 1L3 5V11C3 16.55 6.84 21.74 12 23C17.16 21.74 21 16.55 21 11V5L12 1ZM12 11.99H19C18.47 16.11 15.72 19.78 12 20.93V12H5V6.3L12 3.19V11.99Z" fill="#00c48c"/> </svg> HIPAA Compliant </div> <button class="action-button"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4zM14 13h-3v3H9v-3H6v-2h3V8h2v3h3v2z"/> </svg> </button> <button class="action-button"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M12 15c1.66 0 2.99-1.34 2.99-3L15 6c0-1.66-1.34-3-3-3S9 4.34 9 6v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 15 6.7 12H5c0 3.42 2.72 6.23 6 6.72V22h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z"/> </svg> </button> </div> </div> <div class="chat-content" id="chatContent"> <div class="wave-bg"></div> <div class="chat-bubble received" style="animation-delay: 0.1s"> <div>Hello John, Dr. Chen here. How have you been feeling since our last appointment?</div> <div class="message-time">10:03 AM</div> </div> <div class="appointment-reminder"> <h4>Follow-up Appointment</h4> <p>Your next scheduled video consultation is tomorrow at 2:00 PM EST. Please ensure you have a stable internet connection and a private space for the call.</p> <div class="reminder-buttons"> <button class="reminder-button reschedule">Reschedule</button> <button class="reminder-button confirm">Confirm</button> </div> </div> <div class="chat-bubble sent" style="animation-delay: 0.3s"> <div>Hi Dr. Chen, the new medication seems to be helping with my blood pressure readings. They've been consistently lower this week.</div> <div class="message-time">10:05 AM</div> <div class="message-status"> <div class="encryption-animation"> <div class="encryption-line"></div> </div> <div class="message-encryption-active"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none"> <path d="M12 1L3 5V11C3 16.55 6.84 21.74 12 23C17.16 21.74 21 16.55 21 11V5L12 1ZM12 11.99H19C18.47 16.11 15.72 19.78 12 20.93V12H5V6.3L12 3.19V11.99Z" fill="currentColor"/> </svg> <span>End-to-end encrypted</span> </div> </div> </div> <div class="chat-bubble received" style="animation-delay: 0.5s"> <div>That's excellent news! Could you share some of your recent readings with me? Also, have you experienced any side effects like dizziness or fatigue?</div> <div class="message-time">10:07 AM</div> </div> <div class="chat-bubble sent" style="animation-delay: 0.7s"> <div>I've been monitoring my readings twice daily as you recommended. Here's my data from the past week:</div> <div class="file-attachment"> <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"> <path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/> </svg> <span class="file-name">BP_Readings_Week12.pdf</span> <span class="file-size">243KB</span> </div> <div class="message-time">10:09 AM</div> <div class="message-status"> <div class="encryption-animation"> <div class="encryption-line"></div> </div> <div class="message-encryption-active"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none"> <path d="M12 1L3 5V11C3 16.55 6.84 21.74 12 23C17.16 21.74 21 16.55 21 11V5L12 1ZM12 11.99H19C18.47 16.11 15.72 19.78 12 20.93V12H5V6.3L12 3.19V11.99Z" fill="currentColor"/> </svg> <span>End-to-end encrypted</span> </div> </div> </div> <div class="typing-indicator" id="typingIndicator"> <div class="typing-dots"> <div class="typing-dot"></div> <div class="typing-dot"></div> <div class="typing-dot"></div> </div> </div> </div> <div class="chat-input-container"> <div class="input-privacy-notice"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none"> <path d="M12 1L3 5V11C3 16.55 6.84 21.74 12 23C17.16 21.74 21 16.55 21 11V5L12 1ZM12 11.99H19C18.47 16.11 15.72 19.78 12 20.93V12H5V6.3L12 3.19V11.99Z" fill="#7c8999"/> </svg> Your conversation is protected by medical-grade encryption </div> <div class="privacy-tooltip"> All messages in this consultation are encrypted end-to-end and comply with HIPAA regulations. Only you and your healthcare provider can access this information. </div> <div class="chat-input-wrapper"> <button class="attachment-button"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5v10.5c0 .55-.45 1-1 1s-1-.45-1-1V6H10v9.5c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5V5c0-2.21-1.79-4-4-4S7 2.79 7 5v12.5c0 3.04 2.46 5.5 5.5 5.5s5.5-2.46 5.5-5.5V6h-1.5z"/> </svg> </button> <input type="text" class="chat-input" id="messageInput" placeholder="Type a secure message..."> <button class="send-button" id="sendButton"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/> </svg> </button> </div> <div class="encryption-indicator"> <svg width="10" height="10" viewBox="0 0 24 24" fill="none"> <path d="M12 1L3 5V11C3 16.55 6.84 21.74 12 23C17.16 21.74 21 16.55 21 11V5L12 1ZM12 11.99H19C18.47 16.11 15.72 19.78 12 20.93V12H5V6.3L12 3.19V11.99Z" fill="#00c48c"/> </svg> This conversation is protected by HIPAA-compliant encryption </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const chatContent = document.getElementById('chatContent'); const messageInput = document.getElementById('messageInput'); const sendButton = document.getElementById('sendButton'); const typingIndicator = document.getElementById('typingIndicator'); // Scroll to bottom of chat function scrollToBottom() { chatContent.scrollTop = chatContent.scrollHeight; } // Initialize scroll setTimeout(scrollToBottom, 100); // Function to create encryption animation function createEncryptionAnimation() { const encryptionAnimation = document.createElement('div'); encryptionAnimation.className = 'encryption-animation'; const encryptionLine = document.createElement('div'); encryptionLine.className = 'encryption-line'; encryptionAnimation.appendChild(encryptionLine); return encryptionAnimation; } // Function to add encrypted status to message function addEncryptionStatus(messageElement) { const messageStatus = document.createElement('div'); messageStatus.className = 'message-status'; messageStatus.appendChild(createEncryptionAnimation()); const encryptionText = document.createElement('div'); encryptionText.className = 'message-encryption-active'; const encryptionIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); encryptionIcon.setAttribute('width', '12'); encryptionIcon.setAttribute('height', '12'); encryptionIcon.setAttribute('viewBox', '0 0 24 24'); encryptionIcon.setAttribute('fill', 'none'); const encryptionPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); encryptionPath.setAttribute('d', 'M12 1L3 5V11C3 16.55 6.84 21.74 12 23C17.16 21.74 21 16.55 21 11V5L12 1ZM12 11.99H19C18.47 16.11 15.72 19.78 12 20.93V12H5V6.3L12 3.19V11.99Z'); encryptionPath.setAttribute('fill', 'currentColor'); encryptionIcon.appendChild(encryptionPath); encryptionText.appendChild(encryptionIcon); const statusText = document.createElement('span'); statusText.textContent = 'End-to-end encrypted'; encryptionText.appendChild(statusText); messageStatus.appendChild(encryptionText); messageElement.appendChild(messageStatus); } function sendMessage() { const message = messageInput.value.trim(); if (message === '') return; // Create message bubble const messageBubble = document.createElement('div'); messageBubble.className = 'chat-bubble sent'; const messageText = document.createElement('div'); messageText.textContent = message; messageBubble.appendChild(messageText); const timestamp = document.createElement('div'); timestamp.className = 'message-time'; const now = new Date(); timestamp.textContent = now.getHours() + ':' + (now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes()) + ' ' + (now.getHours() >= 12 ? 'PM' : 'AM'); messageBubble.appendChild(timestamp); // Add encryption status addEncryptionStatus(messageBubble); // Add message to chat chatContent.appendChild(messageBubble); messageInput.value = ''; scrollToBottom(); // Show typing indicator after sending message setTimeout(() => { typingIndicator.style.display = 'block'; scrollToBottom(); // Simulate response after typing setTimeout(() => { typingIndicator.style.display = 'none'; const responses = [ "Thank you for sharing your readings. The numbers look much better compared to last month. Continue monitoring and keep me updated if anything changes.", "I've reviewed your data and it shows good progress. Make sure you're still taking the medication at the same time each day for consistent results.", "Your blood pressure readings are heading in the right direction. Remember to maintain your low-sodium diet and regular exercise routine as well." ]; const responseText = responses[Math.floor(Math.random() * responses.length)]; const responseBubble = document.createElement('div'); responseBubble.className = 'chat-bubble received'; const responseTextElement = document.createElement('div'); responseTextElement.textContent = responseText; responseBubble.appendChild(responseTextElement); const responseTimestamp = document.createElement('div'); responseTimestamp.className = 'message-time'; const responseTime = new Date(); responseTimestamp.textContent = responseTime.getHours() + ':' + (responseTime.getMinutes() < 10 ? '0' + responseTime.getMinutes() : responseTime.getMinutes()) + ' ' + (responseTime.getHours() >= 12 ? 'PM' : 'AM'); responseBubble.appendChild(responseTimestamp); chatContent.appendChild(responseBubble); scrollToBottom(); }, 2000); }, 500); } // Send message on button click sendButton.addEventListener('click', sendMessage); // Send message on Enter key messageInput.addEventListener('keypress', function(e) { if (e.key === 'Enter') { sendMessage(); } }); // Focus input field on load setTimeout(() => { messageInput.focus(); }, 500); // Interaction with appointment reminder const confirmButton = document.querySelector('.reminder-button.confirm'); const rescheduleButton = document.querySelector('.reminder-button.reschedule'); const appointmentReminder = document.querySelector('.appointment-reminder'); confirmButton.addEventListener('click', function() { appointmentReminder.innerHTML = '<h4>Appointment Confirmed</h4><p>Your video consultation for tomorrow at 2:00 PM EST has been confirmed. You'll receive a reminder notification 15 minutes before the appointment.</p>'; }); rescheduleButton.addEventListener('click', function() { appointmentReminder.innerHTML = '<h4>Reschedule Appointment</h4><p>Please select a new date and time for your follow-up appointment:</p><div style="margin-top: 10px;"><select style="padding: 5px; border-radius: 5px; margin-right: 10px; border: 1px solid #e6e6e6;"><option>Wed, Jun 28</option><option>Thu, Jun 29</option><option>Fri, Jun 30</option></select><select style="padding: 5px; border-radius: 5px; border: 1px solid #e6e6e6;"><option>9:00 AM</option><option>11:30 AM</option><option>2:00 PM</option><option>4:30 PM</option></select></div><div class="reminder-buttons" style="margin-top: 10px;"><button class="reminder-button confirm">Confirm New Time</button></div>'; const newConfirmButton = appointmentReminder.querySelector('.reminder-button.confirm'); newConfirmButton.addEventListener('click', function() { appointmentReminder.innerHTML = '<h4>Appointment Rescheduled</h4><p>Your appointment has been rescheduled. You will receive a confirmation email with the new details shortly.</p>'; }); }); // Make emergency button functional const emergencyButton = document.querySelector('.emergency-button'); emergencyButton.addEventListener('click', function
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Project Management Chat</title> <style> :root { --primary: #3a7bd5; --primary-light: #4a88e2; --secondary: #f0f5ff; --success: #00c781; --warning: #ffaa15; --danger: #ff4040; --info: #7d4cdb; --dark: #2b2b2b; --light: #f8f9fa; --border: #e1e4e8; --shadow: 0 4px 6px rgba(0, 0, 0, 0.05); --shadow-hover: 0 10px 20px rgba(0, 0, 0, 0.08); --transition: all 0.3s ease; --radius: 10px; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f9fafc; display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; } .chat-container { width: 100%; max-width: 700px; height: 700px; background-color: white; border-radius: var(--radius); box-shadow: var(--shadow); display: grid; grid-template-rows: 70px 1fr 70px; overflow: hidden; position: relative; } .chat-header { display: flex; align-items: center; justify-content: space-between; padding: 0 20px; border-bottom: 1px solid var(--border); background-color: white; position: relative; z-index: 10; } .header-title { display: flex; align-items: center; gap: 10px; } .header-title h2 { font-size: 20px; color: var(--dark); } .project-status { display: flex; align-items: center; gap: 5px; font-size: 14px; color: var(--success); } .header-actions { display: flex; gap: 15px; } .action-btn { background: none; border: none; color: var(--dark); cursor: pointer; font-size: 20px; transition: var(--transition); padding: 5px; border-radius: 50%; } .action-btn:hover { background-color: var(--secondary); color: var(--primary); } .chat-messages { padding: 20px; overflow-y: auto; overflow-x: hidden; background-color: #f8fafd; display: flex; flex-direction: column; gap: 15px; } .message { display: flex; gap: 10px; position: relative; transition: var(--transition); max-width: 100%; } .message:hover { transform: translateY(-2px); } .avatar { width: 40px; height: 40px; border-radius: 50%; background-color: var(--primary); color: white; display: flex; align-items: center; justify-content: center; font-weight: bold; flex-shrink: 0; } .message-content { background-color: white; padding: 15px; border-radius: var(--radius); box-shadow: var(--shadow); position: relative; max-width: calc(100% - 50px); transition: var(--transition); } .message-content:hover { box-shadow: var(--shadow-hover); } .message.outgoing .message-content { background-color: var(--primary); color: white; } .message.high-priority .message-content { border-left: 4px solid var(--danger); } .message.medium-priority .message-content { border-left: 4px solid var(--warning); } .message.low-priority .message-content { border-left: 4px solid var(--success); } .message-header { display: flex; justify-content: space-between; margin-bottom: 5px; font-size: 14px; } .message-sender { font-weight: bold; color: var(--primary); } .message.outgoing .message-sender { color: white; } .message-time { color: #888; font-size: 12px; } .message.outgoing .message-time { color: rgba(255, 255, 255, 0.7); } .message-text { margin-bottom: 8px; word-break: break-word; } .message-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 10px; } .message-tag { background-color: var(--secondary); color: var(--primary); padding: 4px 8px; border-radius: 50px; font-size: 12px; cursor: pointer; transition: var(--transition); } .message.outgoing .message-tag { background-color: rgba(255, 255, 255, 0.2); color: white; } .message-tag:hover { background-color: var(--primary-light); color: white; } .message-attachment { display: flex; align-items: center; gap: 5px; background-color: var(--secondary); padding: 8px 10px; border-radius: 8px; margin-top: 8px; cursor: pointer; transition: var(--transition); width: fit-content; } .message.outgoing .message-attachment { background-color: rgba(255, 255, 255, 0.2); color: white; } .message-attachment:hover { background-color: var(--primary-light); color: white; } .thread-indicator { display: flex; align-items: center; gap: 5px; font-size: 12px; color: var(--primary); margin-top: 5px; cursor: pointer; } .thread-indicator i { font-size: 14px; } .message.outgoing .thread-indicator { color: rgba(255, 255, 255, 0.9); } .chat-input { padding: 15px 20px; border-top: 1px solid var(--border); display: flex; align-items: center; background-color: white; position: relative; z-index: 10; } .input-container { flex: 1; display: flex; align-items: center; background-color: var(--secondary); border-radius: 20px; padding: 0 15px; position: relative; } .input-container input { flex: 1; border: none; outline: none; height: 40px; background-color: transparent; padding: 0 10px; font-size: 15px; } .input-actions { display: flex; gap: 10px; } .input-btn { background: none; border: none; color: #888; cursor: pointer; transition: var(--transition); font-size: 18px; } .input-btn:hover { color: var(--primary); } .send-btn { background-color: var(--primary); color: white; width: 40px; height: 40px; border-radius: 50%; border: none; cursor: pointer; margin-left: 10px; transition: var(--transition); display: flex; align-items: center; justify-content: center; } .send-btn:hover { background-color: var(--primary-light); transform: scale(1.05); } .file-preview { position: absolute; bottom: 100%; left: 0; right: 0; background-color: white; padding: 10px 15px; border-top: 1px solid var(--border); display: none; transform-origin: bottom; } .file-preview.visible { display: block; animation: slideUp 0.3s forwards; } .file-preview-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .file-preview-content { display: flex; align-items: center; gap: 10px; background-color: var(--secondary); padding: 10px; border-radius: 8px; } .file-preview-icon { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; background-color: var(--primary); color: white; border-radius: 8px; font-size: 18px; } .file-preview-details { flex: 1; } .file-preview-name { font-weight: bold; } .file-preview-size { font-size: 12px; color: #888; } .file-preview-close { background: none; border: none; color: #888; cursor: pointer; font-size: 18px; } .file-preview-close:hover { color: var(--danger); } .emoji-panel { position: absolute; bottom: 100%; right: 0; width: 250px; height: 200px; background-color: white; border-radius: 10px; box-shadow: var(--shadow); padding: 10px; display: none; grid-template-columns: repeat(5, 1fr); gap: 10px; overflow-y: auto; transform-origin: bottom right; } .emoji-panel.visible { display: grid; animation: fadeIn 0.3s forwards; } .emoji { font-size: 22px; cursor: pointer; text-align: center; transition: var(--transition); } .emoji:hover { transform: scale(1.3); } .thread-view { position: absolute; top: 0; right: -100%; width: 100%; height: 100%; background-color: white; z-index: 100; display: grid; grid-template-rows: 70px 1fr 70px; transition: var(--transition); } .thread-view.visible { right: 0; } .thread-header { display: flex; align-items: center; justify-content: space-between; padding: 0 20px; border-bottom: 1px solid var(--border); } .thread-header-title { display: flex; align-items: center; gap: 10px; } .back-btn { background: none; border: none; cursor: pointer; font-size: 20px; color: var(--dark); } .back-btn:hover { color: var(--primary); } .thread-messages { padding: 20px; overflow-y: auto; background-color: #f8fafd; display: flex; flex-direction: column; gap: 15px; } .thread-parent { border-left: 3px solid var(--primary); padding-left: 15px; margin-bottom: 20px; } .thread-input { padding: 15px 20px; border-top: 1px solid var(--border); display: flex; align-items: center; } .day-divider { text-align: center; margin: 20px 0; display: flex; align-items: center; justify-content: center; color: #888; font-size: 14px; } .day-divider::before, .day-divider::after { content: ''; flex: 1; height: 1px; background-color: var(--border); margin: 0 10px; } .tag-suggestion { position: absolute; bottom: 100%; left: 20px; background-color: white; border-radius: 10px; box-shadow: var(--shadow); padding: 10px; display: none; width: 200px; transform-origin: bottom left; } .tag-suggestion.visible { display: block; animation: fadeIn 0.3s forwards; } .tag-item { padding: 8px 10px; cursor: pointer; border-radius: 5px; transition: var(--transition); } .tag-item:hover { background-color: var(--secondary); } .pulse { position: relative; } .pulse::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: inherit; border-radius: inherit; animation: pulse 2s ease-out infinite; z-index: -1; } @keyframes pulse { 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(58, 123, 213, 0.7); } 70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(58, 123, 213, 0); } 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(58, 123, 213, 0); } } @keyframes fadeIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } } @keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .typing-indicator { display: flex; align-items: center; gap: 5px; margin-top: 5px; opacity: 0; transition: opacity 0.3s ease; } .typing-indicator.visible { opacity: 1; } .typing-dot { width: 8px; height: 8px; background-color: var(--primary); border-radius: 50%; animation: typingDot 1.5s infinite ease-in-out; opacity: 0.7; } .typing-dot:nth-child(1) { animation-delay: 0s; } .typing-dot:nth-child(2) { animation-delay: 0.3s; } .typing-dot:nth-child(3) { animation-delay: 0.6s; } @keyframes typingDot { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-5px); } } /* Responsive */ @media (max-width: 600px) { .chat-container { border-radius: 0; height: 100vh; } .thread-view { top: 0; right: -100%; width: 100%; height: 100%; } } .empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; text-align: center; color: #888; padding: 20px; } .empty-icon { font-size: 50px; margin-bottom: 20px; color: var(--primary); } .empty-title { font-size: 20px; margin-bottom: 10px; color: var(--dark); } .empty-description { max-width: 300px; margin-bottom: 20px; } .get-started-btn { background-color: var(--primary); color: white; border: none; padding: 10px 20px; border-radius: 20px; cursor: pointer; transition: var(--transition); } .get-started-btn:hover { background-color: var(--primary-light); transform: translateY(-2px); } .status-bubble { width: 10px; height: 10px; border-radius: 50%; background-color: var(--success); display: inline-block; margin-right: 5px; } .reaction-btn { background: none; border: none; cursor: pointer; font-size: 14px; color: #888; padding: 3px 8px; border-radius: 30px; margin-right: 5px; transition: var(--transition); } .reaction-btn:hover { background-color: var(--secondary); color: var(--primary); } .reactions { display: flex; gap: 5px; margin-top: 5px; } .reaction { background-color: var(--secondary); color: var(--dark); padding: 2px 8px; border-radius: 30px; font-size: 12px; display: flex; align-items: center; gap: 3px; cursor: pointer; transition: var(--transition); } .reaction:hover { background-color: var(--primary-light); color: white; } .message-options { position: absolute; top: 5px; right: 5px; opacity: 0; transition: var(--transition); } .message:hover .message-options { opacity: 1; } .options-btn { background: none; border: none; cursor: pointer; font-size: 16px; color: #888; width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: var(--transition); } .options-btn:hover { background-color: var(--secondary); color: var(--primary); } </style> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> </head> <body> <div class="chat-container"> <!-- Chat Header --> <div class="chat-header"> <div class="header-title"> <h2>Website Redesign</h2> <div class="project-status"> <div class="status-bubble"></div> <span>In progress</span> </div> </div> <div class="header-actions"> <button class="action-btn" title="Search messages"> <i class="fas fa-search"></i> </button> <button class="action-btn" title="View members"> <i class="fas fa-users"></i> </button> <button class="action-btn" title="Settings"> <i class="fas fa-cog"></i> </button> </div> </div> <!-- Chat Messages --> <div class="chat-messages" id="chatMessages"> <div class="day-divider">Yesterday</div> <!-- Message 1 --> <div class="message"> <div class="avatar" style="background-color: #3a7bd5;">AS</div> <div class="message-content high-priority"> <div class="message-options"> <button class="options-btn"> <i class="fas fa-ellipsis-h"></i> </button> </div> <div class="message-header"> <span class="message-sender">Alex Smith</span> <span class="message-time">10:30 AM</span> </div> <div class="message-text"> We need to finalize the homepage mockup by EOD. The client has requested some changes to the navigation structure based on the usability testing. </div> <div class="message-attachment" onclick="previewFile()"> <i class="fas fa-file-pdf"></i> <span>usability_feedback.pdf (2.3 MB)</span> </div> <div class="message-tags"> <span class="message-tag">#design</span> <span class="message-tag">#urgent</span> </div> <div class="thread-indicator" onclick="openThread()"> <i class="fas fa-reply"></i> <span>5 replies</span> </div> <div class="reactions"> <div class="reaction"> <span>π</span> <span>3</span> </div> <div class="reaction"> <span>π₯</span> <span>2</span> </div> </div> </div> </div> <!-- Message 2 --> <div class="message"> <div class="avatar" style="background-color: #7d4cdb;">JL</div> <div class="message-content medium-priority"> <div class="message-options"> <button class="options-btn"> <i class="fas fa-ellipsis-h"></i> </button> </div> <div class="message-header"> <span class="message-sender">Jessica Lee</span> <span class="message-time">11:15 AM</span> </div> <div class="message-text"> I've started implementing the backend API for the user dashboard. Can someone review my approach to make sure it's consistent with the rest of the system? </div> <div class="message-attachment" onclick="previewFile()"> <i class="fas fa-file-code"></i> <span>api_specs.json (156 KB)</span> </div> <div class="message-tags"> <span class="message-tag">#backend</span> <span class="message-tag">#api</span> </div> <div class="thread-indicator" onclick="openThread()"> <i class="fas fa-reply"></i> <span>2 replies</span> </div> </div> </div> <div class="day-divider">Today</div> <!-- Message 3 --> <div class="message outgoing"> <div class="message-content"> <div class="message-options"> <button class="options-btn"> <i class="fas fa-ellipsis-h"></i> </button> </div> <div class="message-header"> <span class="message-sender">You</span> <span class="message-time">9:20 AM</span> </div> <div class="message-text"> I've finished the responsive layouts for the product pages. They're working well on all devices, but we might need to adjust some spacing on tablet view. </div> <div class="message-attachment" onclick="previewFile()"> <i class="fas fa-file-image"></i> <span>responsive_screens.zip (4.7 MB)</span> </div> <div class="message-tags"> <span class="message-tag">#frontend</span> <span class="message-tag">#responsive</span> </div> </div> <div class="avatar" style="background-color: #00c781;">ME</div> </div> <!-- Message 4 --> <div class="message"> <div class="avatar" style="background-color: #ff4040;">TJ</div> <div class="message-content low-priority"> <div class="message-options"> <button class="options-btn"> <i class="fas fa-ellipsis-h"></i> </button> </div> <div class="message-header"> <span class="message-sender">Tom Johnson</span> <span class="message-time">10:05 AM</span> </div> <div class="message-text"> I've scheduled a meeting with the content team for Thursday at 2 PM to review all website copy. Please update your calendars and prepare any questions. </div> <div class="message-tags"> <span class="message-tag">#meeting</span> <span class="message-tag">#content</span> </div> <div class="reactions"> <div class="reaction"> <span>π</span> <span>5</span> </div> </div> </div> </div> <div class="typing-indicator" id="typingIndicator"> <div class="avatar" style="background-color: #ffaa15; width: 30px; height: 30px; font-size: 12px;">KL</div> <div class="typing-dot"></div> <div class="typing-dot"></div> <div class="typing-dot"></div> </div> </div> <!-- Chat Input --> <div class="chat-input"> <div class="input-container"> <div class="input-actions"> <button class="input-btn" id="attachBtn" title="Attach file"> <i class="fas fa-paperclip"></i> </button> </div> <input type="text" id="messageInput" placeholder="Type a message, use # for tasks, @ for people..."> <div class="input-actions"> <button class="input-btn" id="emojiBtn" title="Add emoji"> <i class="far fa-smile"></i> </button> <button class="input-btn" title="Add task"> <i class="fas fa-tasks"></i> </button> </div> </div> <button class="send-btn pulse" id="sendBtn"> <i class="fas fa-paper-plane"></i> </button> <!-- Tag Suggestion Panel --> <div class="tag-suggestion" id="tagSuggestion"> <div class="tag-item" onclick="insertTag('design')">#design</div> <div class="tag-item" onclick="insertTag('frontend')">#frontend</div> <div class="tag-item" onclick="insertTag('backend')">#backend</div> <div class="tag-item" onclick="insertTag('meeting')">#meeting</div> <div class="tag-item" onclick="insertTag('urgent')">#urgent</div> </div> <!-- Emoji Panel --> <div class="emoji-panel" id="emojiPanel"> <div class="emoji" onclick="insertEmoji('π')">π</div> <div class="emoji" onclick="insertEmoji('π')">π</div> <div class="emoji" onclick="insertEmoji('β€οΈ')">β€οΈ</div> <div class="emoji" onclick="insertEmoji('π')">π</div> <div class="emoji" onclick="insertEmoji('π₯')">π₯</div> <div class="emoji" onclick="insertEmoji('π')">π</div> <div class="emoji" onclick="insertEmoji('π')">π</div> <div class="emoji" onclick="insertEmoji('π€')">π€</div> <div class="emoji" onclick="insertEmoji('π')">π</div> <div class="emoji" onclick="insertEmoji('β ')">β </div> <div class="emoji" onclick="insertEmoji('β οΈ')">β οΈ</div> <div class="emoji" onclick="insertEmoji('β°')">β°</div> <div class="emoji" onclick="insertEmoji('π‘')">π‘</div> <div class="emoji" onclick="insertEmoji('π')">π</div> <div class="emoji" onclick="insertEmoji('π')">π</div> <div class="emoji" onclick="insertEmoji('π')">π</div> <div class="emoji" onclick="insertEmoji('π οΈ')">π οΈ</div> <div class="emoji" onclick="insertEmoji('π')">π</div> <div class="emoji" onclick="insertEmoji('π')">π</div> <div class="emoji" onclick="insertEmoji('π')">π</div> </div> <!-- File Upload Preview --> <div class="file-preview" id="filePreview"> <div class="file-preview-header"> <span>File to upload</span> <button class="file-preview-close" onclick="closeFilePreview()"> <i class="fas fa-times"></i> </button> </div> <div class="file-preview-content"> <div class="file-preview-icon"> <i class="fas fa-file"></i> </div> <div class="file-preview-details"> <div class="file-preview-name">document.pdf</div> <div class="file-preview-size">3.2 MB</div> </div> </div> </div> </div> <!-- Thread View --> <div class="thread-view" id="threadView"> <div class="thread-header"> <div class="thread-header-title"> <button class="back-btn" onclick="closeThread()"> <i class="fas fa-arrow-left"></i> </button> <h3>Thread</h3> </div> <div class="header-actions"> <button class="action-btn"> <i class="fas fa-ellipsis-v"></i> </button> </div> </div> <div class="thread-messages"> <div class="thread-parent"> <div class="message"> <div class="avatar" style="background-color: #3a7bd5;">AS</div> <div class="message-content high-priority"> <div class="message-header"> <span class="message-sender">Alex Smith</span> <span class="message-time">10:30 AM</span> </div> <div class="message-text"> We need to finalize the homepage mockup by EOD. The client has requested some changes to the navigation structure based on the usability testing. </div> <div class="message-attachment" onclick="previewFile()"> <i class="fas fa-file-pdf"></i> <span>usability_feedback.pdf (2.3 MB)</span> </div> <div class="message-tags"> <span class="message-tag">#design</span> <span class="message-tag">#urgent</span> </div> <div class="reactions"> <div class="reaction"> <span>π</span> <span>3</span> </div> <div class="reaction"> <span>π₯</span> <span>2</span> </div> </div> </div> </div> </div> <!-- Thread replies --> <div class="message"> <div class="avatar" style="background-color: #00c781;">ME</div> <div class="message-content"> <div class="message-header"> <span class="message-sender">You</span> <span class="message-time">10:45 AM</span> </div> <div class="message-text"> I've reviewed the feedback. The main issue seems to be the dropdown menus not being intuitive enough for mobile users. </div> </div> </div> <div class="message"> <div class="avatar" style="background-color: #ffaa15;">KL</div> <div class="message-content"> <div class="message-header"> <span class="message-sender">Karen Lopez</span> <span class="message-time">11:02 AM</span> </div> <div class="message-text"> I can update the mobile nav to use a hamburger menu with slide-out panel. Would that address the concern? </div> <div class="message-attachment" onclick="previewFile()"> <i class="fas fa-file-image"></i> <span>mobile_nav.sketch (1.8 MB)</span> </div> </div> </div> <div class="message"> <div class="avatar" style="background-color: #3a7bd5;">AS</div> <div class="message-content"> <div class="message-header"> <span class="message-sender">Alex Smith</span> <span class="message-time">11:15 AM</span> </div> <div class="message-text"> That looks good! Let's also make sure that the most common actions are accessible without going into submenus. </div> </div> </div> <div class="message"> <div class="avatar" style="background-color: #ff4040;">TJ</div> <div class="message-content"> <div class="message-header"> <span class="message-sender">Tom Johnson</span> <span class="message-time">11:30 AM</span> </div> <div class="message-text"> Should we also consider adding a search icon in the top navigation for quick access? The usability testing showed users struggled to find the search function. </div> <div class="message-tags"> <span class="message-tag">#ux</span> </div> </div> </div> </div> <div class="thread-input"> <div class="input-container"> <div class="input-actions"> <button class="input-btn"> <i class="fas fa-paperclip"></i> </button> </div> <input type="text" placeholder="Reply to thread..."> <div class="input-actions"> <button class="input-btn"> <i class="far fa-smile"></i> </button> <button class="input-btn"> <i class="fas fa-at"></i> </button> </div> </div> <button class="send-btn"> <i class="fas fa-paper-plane"></i> </button> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Elements const messageInput = document.getElementById('messageInput'); const sendBtn = document.getElementById('sendBtn'); const chatMessages = document.getElementById('chatMessages'); const emojiBtn = document.getElementById('emojiBtn'); const emojiPanel = document.getElementById('emojiPanel'); const attachBtn = document.getElementById('attachBtn'); const filePreview = document.getElementById('filePreview');
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> :root { --primary: #6c5ce7; --secondary: #fd79a8; --accent: #00b894; --dark: #2d3436; --light: #f5f6fa; --gradient: linear-gradient(135deg, var(--primary), var(--secondary)); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: var(--dark); color: var(--light); display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; } .chat-container { width: 100%; max-width: 650px; height: 650px; border-radius: 16px; background-color: rgba(45, 52, 54, 0.9); backdrop-filter: blur(10px); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); display: flex; flex-direction: column; overflow: hidden; position: relative; } .chat-header { background: var(--gradient); padding: 15px 20px; display: flex; align-items: center; justify-content: space-between; position: relative; overflow: hidden; } .chat-header h2 { font-size: 1.5rem; font-weight: 600; color: var(--light); z-index: 1; display: flex; align-items: center; } .live-indicator { display: flex; align-items: center; margin-left: 15px; background-color: rgba(255, 255, 255, 0.2); padding: 3px 10px; border-radius: 12px; font-size: 0.8rem; } .live-dot { width: 10px; height: 10px; background-color: #ff0000; border-radius: 50%; margin-right: 5px; animation: pulse 1.5s infinite; } .viewer-count { display: flex; align-items: center; gap: 5px; background-color: rgba(0, 0, 0, 0.2); padding: 5px 10px; border-radius: 20px; font-size: 0.9rem; } .bubble-background { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0.6; z-index: 0; overflow: hidden; } .bubble { position: absolute; bottom: -20px; background-color: rgba(255, 255, 255, 0.2); border-radius: 50%; animation: float 10s infinite ease-in-out; } .ticker-container { flex: 1; overflow-y: auto; padding: 15px; display: flex; flex-direction: column-reverse; position: relative; } .ticker-container::-webkit-scrollbar { width: 6px; } .ticker-container::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.05); } .ticker-container::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.2); border-radius: 3px; } .ticker-container::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.3); } .message { margin-bottom: 12px; display: flex; align-items: flex-start; transform: translateX(-100%); opacity: 0; animation: slideIn 0.5s forwards; } .message-avatar { width: 36px; height: 36px; border-radius: 50%; background-size: cover; background-position: center; margin-right: 10px; flex-shrink: 0; border: 2px solid transparent; transition: transform 0.3s ease; } .message:hover .message-avatar { transform: scale(1.1); } .message-content { background-color: rgba(255, 255, 255, 0.1); padding: 10px 15px; border-radius: 18px; max-width: 80%; position: relative; transition: all 0.3s ease; } .message:hover .message-content { background-color: rgba(255, 255, 255, 0.15); transform: translateY(-2px); } .message-header { display: flex; justify-content: space-between; margin-bottom: 5px; align-items: center; } .message-name { font-weight: 600; font-size: 0.9rem; } .message-time { font-size: 0.7rem; color: rgba(255, 255, 255, 0.5); } .message-text { font-size: 0.95rem; line-height: 1.4; word-break: break-word; } .featured-message { border-left: 3px solid var(--accent); } .featured-message .message-content { background-color: rgba(0, 184, 148, 0.2); } .featured-message .message-name { color: var(--accent); } .featured-badge { background-color: var(--accent); color: white; font-size: 0.7rem; padding: 2px 6px; border-radius: 8px; margin-left: 5px; } .emoji-reaction { position: absolute; right: -10px; top: -10px; background-color: var(--secondary); color: white; width: 24px; height: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.8rem; animation: bounce 1s infinite; } .message-input-container { padding: 15px; background-color: rgba(255, 255, 255, 0.05); display: flex; align-items: center; gap: 10px; border-top: 1px solid rgba(255, 255, 255, 0.1); } .message-input { flex: 1; padding: 12px 15px; border-radius: 25px; border: none; background-color: rgba(255, 255, 255, 0.1); color: var(--light); font-size: 0.95rem; transition: all 0.3s ease; } .message-input:focus { outline: none; background-color: rgba(255, 255, 255, 0.15); box-shadow: 0 0 0 2px rgba(108, 92, 231, 0.3); } .message-input::placeholder { color: rgba(255, 255, 255, 0.5); } .send-button { width: 44px; height: 44px; border-radius: 50%; border: none; background: var(--gradient); color: white; font-size: 1.2rem; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; box-shadow: 0 4px 10px rgba(108, 92, 231, 0.3); } .send-button:hover { transform: translateY(-2px); box-shadow: 0 6px 15px rgba(108, 92, 231, 0.4); } .emoji-button, .reaction-button { width: 38px; height: 38px; border-radius: 50%; border: none; background-color: rgba(255, 255, 255, 0.1); color: var(--light); font-size: 1.1rem; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; } .emoji-button:hover, .reaction-button:hover { background-color: rgba(255, 255, 255, 0.2); } .streaming-info { display: flex; align-items: center; padding: 10px 15px; background-color: rgba(255, 255, 255, 0.05); border-radius: 8px; margin-bottom: 15px; gap: 10px; } .streaming-topic { flex: 1; font-size: 0.9rem; } .topic-highlight { color: var(--secondary); font-weight: 600; } .interaction-stats { display: flex; gap: 15px; } .stat-item { display: flex; align-items: center; gap: 5px; font-size: 0.8rem; color: rgba(255, 255, 255, 0.7); } .flying-heart { position: absolute; font-size: 1.5rem; animation: flyHearts 3s forwards; z-index: 10; opacity: 0; pointer-events: none; } .message-reaction { display: flex; gap: 5px; margin-top: 5px; flex-wrap: wrap; } .reaction-pill { background-color: rgba(255, 255, 255, 0.1); border-radius: 12px; padding: 2px 8px; font-size: 0.75rem; display: flex; align-items: center; gap: 3px; cursor: pointer; transition: all 0.2s ease; } .reaction-pill:hover { background-color: rgba(255, 255, 255, 0.2); } .reaction-count { font-size: 0.7rem; } .moderation-tools { display: none; position: absolute; right: 0; top: 0; background-color: rgba(45, 52, 54, 0.95); border-radius: 0 0 0 8px; padding: 5px; z-index: 5; } .message:hover .moderation-tools { display: flex; } .mod-button { width: 24px; height: 24px; background: none; border: none; color: rgba(255, 255, 255, 0.6); font-size: 0.8rem; cursor: pointer; transition: all 0.2s ease; } .mod-button:hover { color: var(--light); } .poll-container { background-color: rgba(108, 92, 231, 0.2); border-radius: 12px; padding: 15px; margin-bottom: 15px; border: 1px solid rgba(108, 92, 231, 0.3); } .poll-title { font-weight: 600; margin-bottom: 10px; font-size: 0.95rem; } .poll-options { display: flex; flex-direction: column; gap: 8px; } .poll-option { position: relative; background-color: rgba(255, 255, 255, 0.1); border-radius: 8px; padding: 8px 10px; cursor: pointer; transition: all 0.3s ease; overflow: hidden; } .poll-option:hover { background-color: rgba(255, 255, 255, 0.15); } .poll-progress { position: absolute; left: 0; top: 0; height: 100%; background-color: rgba(108, 92, 231, 0.3); z-index: 0; transition: width 1s ease-in-out; } .poll-option-text { display: flex; justify-content: space-between; position: relative; z-index: 1; } .poll-percent { font-size: 0.8rem; font-weight: 600; } .poll-voters { font-size: 0.75rem; color: rgba(255, 255, 255, 0.6); margin-top: 10px; text-align: right; } .confetti { position: absolute; width: 10px; height: 10px; background-color: var(--secondary); animation: confetti 4s ease-in-out forwards; z-index: 100; pointer-events: none; } @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } } @keyframes slideIn { 0% { transform: translateX(-50px); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } } @keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } } @keyframes float { 0%, 100% { transform: translateY(0) scale(1); } 50% { transform: translateY(-20px) scale(1.1); } } @keyframes flyHearts { 0% { transform: translate(0, 0); opacity: 1; } 100% { transform: translate(var(--x), -100px); opacity: 0; } } @keyframes confetti { 0% { transform: translateY(0) rotate(0); opacity: 1; } 100% { transform: translateY(400px) rotate(720deg); opacity: 0; } } /* Responsive styles */ @media (max-width: 600px) { .chat-container { width: 100%; height: 100vh; border-radius: 0; } .message-content { max-width: 75%; } .streaming-info { flex-direction: column; align-items: flex-start; } .interaction-stats { width: 100%; justify-content: space-between; } } </style> </head> <body> <div class="chat-container"> <div class="chat-header"> <h2>Stream Chat <span class="live-indicator"><span class="live-dot"></span> LIVE</span></h2> <div class="viewer-count"> <i class="fas fa-user"></i> 1,247 viewers </div> <div class="bubble-background"> <div class="bubble" style="width: 20px; height: 20px; left: 10%; animation-duration: 8s;"></div> <div class="bubble" style="width: 15px; height: 15px; left: 20%; animation-duration: 10s; animation-delay: 1s;"></div> <div class="bubble" style="width: 25px; height: 25px; left: 50%; animation-duration: 7s; animation-delay: 0.5s;"></div> <div class="bubble" style="width: 18px; height: 18px; left: 70%; animation-duration: 9s; animation-delay: 2s;"></div> <div class="bubble" style="width: 22px; height: 22px; left: 85%; animation-duration: 11s; animation-delay: 1.5s;"></div> </div> </div> <div class="ticker-container" id="tickerContainer"> <div class="streaming-info"> <div class="streaming-topic"> Now discussing: <span class="topic-highlight">New Product Launch Q&A</span> </div> <div class="interaction-stats"> <div class="stat-item"> <i class="fas fa-comment"></i> 428 </div> <div class="stat-item"> <i class="fas fa-heart"></i> 1.2k </div> </div> </div> <div class="poll-container"> <div class="poll-title">Poll: Which feature are you most excited about?</div> <div class="poll-options"> <div class="poll-option" data-option="1"> <div class="poll-progress" style="width: 45%"></div> <div class="poll-option-text"> <span>AI Assistant</span> <span class="poll-percent">45%</span> </div> </div> <div class="poll-option" data-option="2"> <div class="poll-progress" style="width: 28%"></div> <div class="poll-option-text"> <span>Dark Mode</span> <span class="poll-percent">28%</span> </div> </div> <div class="poll-option" data-option="3"> <div class="poll-progress" style="width: 27%"></div> <div class="poll-option-text"> <span>Voice Commands</span> <span class="poll-percent">27%</span> </div> </div> </div> <div class="poll-voters">312 votes β’ 1:24 remaining</div> </div> <!-- Messages will be added here via JavaScript --> </div> <div class="message-input-container"> <button class="emoji-button">π</button> <input type="text" class="message-input" placeholder="Join the conversation..." id="messageInput"> <button class="reaction-button">β€οΈ</button> <button class="send-button" id="sendButton"> <i class="fas fa-paper-plane"></i> </button> </div> </div> <script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script> <script> document.addEventListener('DOMContentLoaded', function() { const tickerContainer = document.getElementById('tickerContainer'); const messageInput = document.getElementById('messageInput'); const sendButton = document.getElementById('sendButton'); const reactionButton = document.querySelector('.reaction-button'); const pollOptions = document.querySelectorAll('.poll-option'); // Sample messages data const messages = [ { id: 1, name: "Sarah Martinez", avatar: "https://i.pravatar.cc/150?img=1", text: "When will the new update be available in Europe? So excited to try it!", time: "Just now", featured: false, reactions: [{emoji: "π", count: 5}, {emoji: "π", count: 2}] }, { id: 2, name: "Mike Johnson", avatar: "https://i.pravatar.cc/150?img=2", text: "Is there going to be backward compatibility with older versions?", time: "1 min ago", featured: false, reactions: [{emoji: "π€", count: 3}] }, { id: 3, name: "Diana Chen", avatar: "https://i.pravatar.cc/150?img=3", text: "The dark mode implementation looks amazing! I'm loving the contrast ratio you've chosen.", time: "2 mins ago", featured: true, reactions: [{emoji: "β€οΈ", count: 12}, {emoji: "π", count: 8}] }, { id: 4, name: "Alex Rodriguez", avatar: "https://i.pravatar.cc/150?img=4", text: "Can we get a quick demo of the voice command feature?", time: "3 mins ago", featured: false, reactions: [{emoji: "β ", count: 4}] }, { id: 5, name: "Taylor Swift", avatar: "https://i.pravatar.cc/150?img=5", text: "Just joined the stream. What did I miss about the pricing structure?", time: "5 mins ago", featured: false, reactions: [] } ]; // Render initial messages messages.forEach(message => { addMessageToTicker(message); }); // Send message functionality sendButton.addEventListener('click', function() { sendMessage(); }); messageInput.addEventListener('keypress', function(e) { if (e.key === 'Enter') { sendMessage(); } }); // Add heart reactions reactionButton.addEventListener('click', function() { sendHearts(); }); // Poll interaction pollOptions.forEach(option => { option.addEventListener('click', function() { const optionId = this.getAttribute('data-option'); voteOnPoll(optionId); }); }); // Functions function sendMessage() { const text = messageInput.value.trim(); if (text) { const newMessage = { id: messages.length + 1, name: "You", avatar: "https://i.pravatar.cc/150?img=8", text: text, time: "Just now", featured: false, reactions: [] }; addMessageToTicker(newMessage, true); messageInput.value = ''; // Simulate response after a random delay if (Math.random() > 0.5) { setTimeout(() => { const responses = [ "Thank you for your question! We'll address that shortly.", "Great point! Let me elaborate on that aspect of our product.", "Excellent question - that's something many users have asked about.", "Thanks for bringing that up! It's definitely on our roadmap." ]; const responseMsg = { id: messages.length + 2, name: "Host", avatar: "https://i.pravatar.cc/150?img=12", text: responses[Math.floor(Math.random() * responses.length)], time: "Just now", featured: true, reactions: [] }; addMessageToTicker(responseMsg); }, 2000 + Math.random() * 3000); } } } function addMessageToTicker(message, isNew = false) { const messageEl = document.createElement('div'); messageEl.className = `message ${message.featured ? 'featured-message' : ''}`; if (isNew) { messageEl.style.animation = 'none'; setTimeout(() => { messageEl.style.animation = 'slideIn 0.5s forwards'; }, 10); } let reactionsHtml = ''; if (message.reactions && message.reactions.length > 0) { reactionsHtml = '<div class="message-reaction">'; message.reactions.forEach(reaction => { reactionsHtml += `<div class="reaction-pill"><span>${reaction.emoji}</span><span class="reaction-count">${reaction.count}</span></div>`; }); reactionsHtml += '</div>'; } const featuredBadge = message.featured ? '<span class="featured-badge">HOST</span>' : ''; const emojiReaction = Math.random() > 0.8 && !isNew ? `<div class="emoji-reaction">β</div>` : ''; messageEl.innerHTML = ` <div class="message-avatar" style="background-image: url('${message.avatar}')"></div> <div class="message-content"> ${emojiReaction} <div class="message-header"> <div class="message-name">${message.name} ${featuredBadge}</div> <div class="message-time">${message.time}</div> </div> <div class="message-text">${message.text}</div> ${reactionsHtml} <div class="moderation-tools"> <button class="mod-button feature-btn" title="Feature"><i class="fas fa-star"></i></button> <button class="mod-button hide-btn" title="Hide"><i class="fas fa-eye-slash"></i></button> </div> </div> `; // Add hover effects for reaction pills setTimeout(() => { const reactionPills = messageEl.querySelectorAll('.reaction-pill'); reactionPills.forEach(pill => { pill.addEventListener('click', function() { const currentCount = parseInt(this.querySelector('.reaction-count').textContent); this.querySelector('.reaction-count').textContent = currentCount + 1; // Animated effect this.style.transform = 'scale(1.2)'; setTimeout(() => { this.style.transform = 'scale(1)'; }, 200); }); }); // Moderation buttons const featureBtn = messageEl.querySelector('.feature-btn'); const hideBtn = messageEl.querySelector('.hide-btn'); if (featureBtn) { featureBtn.addEventListener('click', function() { messageEl.classList.toggle('featured-message'); const messageContent = messageEl.querySelector('.message-content'); if (messageEl.classList.contains('featured-message')) { messageContent.style.backgroundColor = 'rgba(0, 184, 148, 0.2)'; // Add featured badge if not already there const msgHeader = messageEl.querySelector('.message-name'); if (!msgHeader.querySelector('.featured-badge')) { msgHeader.innerHTML += '<span class="featured-badge">FEATURED</span>'; } } else { messageContent.style.backgroundColor = ''; // Remove featured badge const badge = messageEl.querySelector('.featured-badge'); if (badge) badge.remove(); } }); } if (hideBtn) { hideBtn.addEventListener('click', function() { messageEl.style.animation = 'slideIn 0.5s reverse forwards'; setTimeout(() => { messageEl.remove(); }, 500); }); } }, 100); // Add to the ticker container if (isNew) { tickerContainer.prepend(messageEl); } else { tickerContainer.appendChild(messageEl); } // Add confetti effect for featured messages if (message.featured && !isNew) { createConfetti(5); } } function voteOnPoll(optionId) { // Simulate voting const options = document.querySelectorAll('.poll-option'); const voters = document.querySelector('.poll-voters'); let currentVotes = parseInt(voters.textContent.split(' ')[0]); currentVotes++; voters.textContent = `${currentVotes} votes β’ 1:24 remaining`; // Calculate new percentages const newPercentages = [45, 28, 27]; // Starting percentages // Adjust the selected option newPercentages[optionId-1] += 1; // Calculate sum and normalize const sum = newPercentages.reduce((a, b) => a + b, 0); const normalizedPercentages = newPercentages.map(p => Math.round(p/sum*100)); // Update UI options.forEach((option, index) => { const progressBar = option.querySelector('.poll-progress'); const percentText = option.querySelector('.poll-percent'); progressBar.style.width = `${normalizedPercentages[index]}%`; percentText.textContent = `${normalizedPercentages[index]}%`; // Highlight selected option if (index === (optionId-1)) { option.style.borderLeft = '3px solid var(--accent)'; createConfetti(3); } }); } function sendHearts() { for (let i = 0; i < 5; i++) { setTimeout(() => { const heart = document.createElement('div'); heart.className = 'flying-heart'; heart.innerHTML = 'β€οΈ'; heart.style.left = `${Math.random() * 100}%`; heart.style.setProperty('--x', `${(Math.random() * 200) - 100}px`); document.body.appendChild(heart); setTimeout(() => { heart.remove(); }, 3000); }, i * 150); } } function createConfetti(count) { for (let i = 0; i < count; i++) { const confetti = document.createElement('div'); confetti.className = 'confetti'; confetti.style.left = `${Math.random() * 100}%`; confetti.style.backgroundColor = `hsl(${Math.random() * 360}, 80%, 60%)`; confetti.style.animationDelay = `${Math.random() * 2}s`; document.body.appendChild(confetti); setTimeout(() => { confetti.remove(); }, 4000); } } // Demo: Auto-add messages every few seconds setInterval(() => { if (Math.random() > 0.7) { const randomMessages = [ "Will there be a mobile app version too?", "The interface looks so clean! Great job team!", "Can we get a breakdown of the subscription tiers again?", "Does the AI feature work offline?", "This is exactly what I've been waiting for!", "Will there be educational discounts available?", "How does this compare to your competitors?", "The dark mode looks amazing! When can we access the beta?" ]; const randomNames = ["James B.", "Priya K.", "Marcus T.", "Elena R.", "Jamal W.", "Sophie L."]; const randomMessage = { id: Math.floor(Math.random() * 1000) + 10, name: randomNames[Math.floor(Math.random() * randomNames.length)], avatar: `https://i.pravatar.cc/150?img=${Math.floor(Math.random() * 70)}`, text: randomMessages[Math.floor(Math.random() * randomMessages.length)], time: "Just now", featured: Math.random() > 0.9, reactions: [] }; addMessageToTicker(randomMessage); } }, 5000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Marketplace Negotiation Chat</title> <style> :root { --primary: #5c6bc0; --primary-light: #8e99f3; --primary-dark: #26418f; --secondary: #ff7043; --secondary-light: #ffa270; --secondary-dark: #c63f17; --neutral-lightest: #f5f7fa; --neutral-light: #e0e5ec; --neutral: #b0bec5; --neutral-dark: #546e7a; --neutral-darkest: #263238; --success: #66bb6a; --warning: #ffca28; --danger: #ef5350; --white: #ffffff; --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.05); --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.1); --shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.15); --radius-sm: 4px; --radius-md: 8px; --radius-lg: 16px; --transition: all 0.3s ease; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } body { background-color: var(--neutral-lightest); display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; } .marketplace-chat { width: 100%; max-width: 700px; height: 700px; background-color: var(--white); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); display: flex; flex-direction: column; overflow: hidden; position: relative; } .chat-header { display: flex; align-items: center; justify-content: space-between; padding: 15px 20px; background-color: var(--white); border-bottom: 1px solid var(--neutral-light); z-index: 10; } .chat-header-left { display: flex; align-items: center; gap: 12px; } .chat-header-title { font-size: 18px; font-weight: 600; color: var(--neutral-darkest); } .chat-header-subtitle { font-size: 14px; color: var(--neutral-dark); } .product-info { display: flex; align-items: center; padding: 15px 20px; background-color: var(--neutral-lightest); border-bottom: 1px solid var(--neutral-light); } .product-image { width: 60px; height: 60px; border-radius: var(--radius-sm); object-fit: cover; margin-right: 15px; border: 1px solid var(--neutral-light); } .product-details { flex: 1; } .product-name { font-size: 16px; font-weight: 600; color: var(--neutral-darkest); margin-bottom: 4px; } .product-price { font-size: 20px; font-weight: 700; color: var(--primary-dark); } .product-status { font-size: 13px; color: var(--neutral-dark); display: flex; align-items: center; gap: 5px; } .status-indicator { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background-color: var(--success); } .chat-body { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 15px; scroll-behavior: smooth; } .chat-message { display: flex; flex-direction: column; max-width: 80%; } .chat-message.sent { align-self: flex-end; } .chat-message.received { align-self: flex-start; } .message-content { padding: 12px 16px; border-radius: 18px; font-size: 15px; line-height: 1.4; position: relative; transition: var(--transition); } .chat-message.sent .message-content { background-color: var(--primary); color: var(--white); border-bottom-right-radius: 4px; } .chat-message.received .message-content { background-color: var(--neutral-light); color: var(--neutral-darkest); border-bottom-left-radius: 4px; } .message-timestamp { font-size: 11px; color: var(--neutral-dark); margin-top: 4px; align-self: flex-end; } .chat-message.sent .message-timestamp { margin-right: 8px; } .chat-message.received .message-timestamp { margin-left: 8px; align-self: flex-start; } .message-status { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; margin-left: 5px; } .message-status i { font-size: 14px; } .negotiation-offer { background-color: var(--neutral-lightest); border: 1px solid var(--neutral-light); border-radius: var(--radius-md); padding: 12px; margin-top: 8px; width: 100%; } .negotiation-offer-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .negotiation-offer-title { font-size: 14px; font-weight: 600; color: var(--neutral-darkest); } .negotiation-price { font-size: 18px; font-weight: 700; color: var(--secondary); } .negotiation-actions { display: flex; gap: 8px; margin-top: 10px; } .reply-options { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; } .reply-option { background-color: var(--neutral-lightest); border: 1px solid var(--neutral-light); border-radius: 16px; padding: 8px 16px; font-size: 14px; color: var(--neutral-darkest); cursor: pointer; transition: var(--transition); } .reply-option:hover { background-color: var(--neutral-light); transform: translateY(-2px); } .system-message { align-self: center; background-color: var(--neutral-lightest); border-radius: var(--radius-md); padding: 8px 16px; font-size: 13px; color: var(--neutral-dark); max-width: 80%; text-align: center; margin: 8px 0; } .btn { padding: 8px 16px; border-radius: var(--radius-md); font-size: 14px; font-weight: 600; cursor: pointer; transition: var(--transition); border: none; display: inline-flex; align-items: center; justify-content: center; gap: 6px; } .btn-primary { background-color: var(--primary); color: var(--white); } .btn-primary:hover { background-color: var(--primary-dark); transform: translateY(-2px); } .btn-secondary { background-color: var(--white); color: var(--primary); border: 1px solid var(--primary); } .btn-secondary:hover { background-color: var(--neutral-lightest); transform: translateY(-2px); } .btn-success { background-color: var(--success); color: var(--white); } .btn-success:hover { background-color: #419645; transform: translateY(-2px); } .btn-danger { background-color: var(--danger); color: var(--white); } .btn-danger:hover { background-color: #c62828; transform: translateY(-2px); } .btn-icon { width: 36px; height: 36px; border-radius: 50%; padding: 0; display: flex; align-items: center; justify-content: center; } .chat-footer { padding: 15px 20px; background-color: var(--white); border-top: 1px solid var(--neutral-light); display: flex; gap: 10px; align-items: center; position: relative; } .chat-input-wrapper { flex: 1; position: relative; } .chat-input { width: 100%; border: 1px solid var(--neutral-light); border-radius: 24px; padding: 12px 20px; font-size: 15px; color: var(--neutral-darkest); outline: none; transition: var(--transition); } .chat-input:focus { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(92, 107, 192, 0.2); } .quick-actions { display: flex; gap: 10px; } .chat-input-placeholder { color: var(--neutral-dark); } .negotiation-tools { display: flex; padding: 10px 0; gap: 10px; overflow-x: auto; margin-bottom: 10px; } .negotiation-tool { background-color: var(--neutral-lightest); border: 1px solid var(--neutral-light); border-radius: var(--radius-md); padding: 8px 12px; font-size: 13px; display: flex; align-items: center; gap: 6px; cursor: pointer; transition: var(--transition); white-space: nowrap; } .negotiation-tool:hover { background-color: var(--neutral-light); transform: translateY(-2px); } .negotiation-tool i { font-size: 16px; color: var(--primary); } .avatar { width: 40px; height: 40px; border-radius: 50%; background-color: var(--neutral-light); display: flex; align-items: center; justify-content: center; font-weight: 600; color: var(--primary-dark); text-transform: uppercase; } .status-badge { display: inline-flex; align-items: center; padding: 4px 8px; border-radius: 12px; font-size: 12px; font-weight: 600; } .status-badge-negotiating { background-color: var(--warning); color: var(--neutral-darkest); } .typing-indicator { display: flex; align-items: center; gap: 4px; padding: 8px 16px; background-color: var(--neutral-light); border-radius: 18px; color: var(--neutral-darkest); font-size: 14px; max-width: fit-content; margin-top: 8px; opacity: 0; transform: translateY(10px); transition: var(--transition); align-self: flex-start; } .typing-indicator.visible { opacity: 1; transform: translateY(0); } .typing-animation { display: flex; align-items: center; gap: 3px; } .typing-dot { width: 6px; height: 6px; border-radius: 50%; background-color: var(--neutral-dark); animation: typingAnimation 1.4s infinite ease-in-out; } .typing-dot:nth-child(1) { animation-delay: 0s; } .typing-dot:nth-child(2) { animation-delay: 0.2s; } .typing-dot:nth-child(3) { animation-delay: 0.4s; } @keyframes typingAnimation { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-5px); } } .message-content.with-offer { margin-bottom: 0; } .price-input-wrapper { display: flex; align-items: center; background-color: var(--white); border: 1px solid var(--neutral-light); border-radius: var(--radius-md); padding: 2px; margin-top: 5px; } .price-input-wrapper span { padding: 0 10px; color: var(--neutral-dark); font-weight: 600; } .price-input { border: none; padding: 8px 10px; width: 100%; outline: none; font-size: 15px; color: var(--neutral-darkest); } .make-offer-btn { background-color: var(--secondary); color: var(--white); border: none; padding: 8px 16px; border-radius: var(--radius-md); font-weight: 600; cursor: pointer; transition: var(--transition); } .make-offer-btn:hover { background-color: var(--secondary-dark); } .price-adjustment { display: flex; align-items: center; margin-top: 5px; margin-bottom: 5px; } .price-adjust-btn { background-color: var(--neutral-light); border: none; width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--transition); } .price-adjust-btn:hover { background-color: var(--neutral); } .counter-offer-input { display: flex; align-items: center; gap: 10px; margin-top: 8px; } .counter-offer-input .price-input-wrapper { flex: 1; margin-top: 0; } .chat-message.received .message-content.offer-message { background-color: rgba(255, 202, 40, 0.2); border: 1px solid var(--warning); } .chat-message.sent .message-content.offer-message { background-color: rgba(92, 107, 192, 0.9); } .offer-highlight { font-weight: 700; color: var(--secondary-dark); } .chat-message.received .offer-highlight { color: var(--secondary-dark); } .chat-message.sent .offer-highlight { color: var(--white); } @media (max-width: 700px) { .marketplace-chat { height: 100vh; border-radius: 0; } .negotiation-actions { flex-wrap: wrap; } .chat-message { max-width: 90%; } } .pulse-animation { animation: pulse 2s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(255, 112, 67, 0.6); } 70% { box-shadow: 0 0 0 8px rgba(255, 112, 67, 0); } 100% { box-shadow: 0 0 0 0 rgba(255, 112, 67, 0); } } .slide-in { animation: slideIn 0.3s forwards; } @keyframes slideIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .shake-animation { animation: shake 0.5s ease-in-out; } @keyframes shake { 0%, 100% { transform: translateX(0); } 20%, 60% { transform: translateX(-5px); } 40%, 80% { transform: translateX(5px); } } .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; font-size: 24px; line-height: 1; letter-spacing: normal; text-transform: none; display: inline-block; white-space: nowrap; word-wrap: normal; direction: ltr; -webkit-font-feature-settings: 'liga'; -webkit-font-smoothing: antialiased; } </style> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> </head> <body> <div class="marketplace-chat"> <div class="chat-header"> <div class="chat-header-left"> <div class="avatar">JS</div> <div> <div class="chat-header-title">Jack Smith</div> <div class="chat-header-subtitle">Active now</div> </div> </div> <div class="status-badge status-badge-negotiating"> <i class="material-icons" style="font-size: 14px; margin-right: 4px;">sync</i> Negotiating </div> </div> <div class="product-info"> <img src="https://images.unsplash.com/photo-1541807084-5c52b6b3adef?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80" alt="Vintage Camera" class="product-image"> <div class="product-details"> <div class="product-name">Vintage Leica M6 35mm Film Camera</div> <div class="product-price">$1,200.00</div> <div class="product-status"> <span class="status-indicator"></span> Available for immediate shipping </div> </div> </div> <div class="chat-body" id="chat-body"> <div class="chat-message received slide-in"> <div class="message-content"> Hi there! I'm really interested in your vintage Leica M6. It's exactly what I've been looking for. </div> <span class="message-timestamp">Yesterday, 4:23 PM</span> </div> <div class="chat-message sent slide-in"> <div class="message-content"> Hello! Thanks for your interest. It's in excellent condition with the original box and papers. Only used a handful of times. </div> <span class="message-timestamp">Yesterday, 4:25 PM</span> </div> <div class="chat-message received slide-in"> <div class="message-content offer-message"> I'd like to make an offer of <span class="offer-highlight">$950</span> for the camera. I can pay immediately and arrange pickup this weekend. </div> <span class="message-timestamp">Yesterday, 4:28 PM</span> </div> <div class="system-message slide-in"> <i class="material-icons" style="font-size: 14px; vertical-align: middle; margin-right: 4px;">info</i> Seller has 24 hours to respond to your offer </div> <div class="chat-message sent slide-in"> <div class="message-content"> I appreciate your offer, but that's a bit too low for this model. The M6 is highly sought after, and this one is in mint condition with all accessories. </div> <span class="message-timestamp">Yesterday, 5:02 PM</span> </div> <div class="chat-message sent slide-in"> <div class="message-content offer-message"> I can come down to <span class="offer-highlight">$1,100</span> which is already $100 off my asking price. </div> <span class="message-timestamp">Yesterday, 5:03 PM</span> </div> <div class="chat-message received slide-in"> <div class="message-content"> Thanks for considering. I understand the value of a Leica M6 in good condition. </div> <span class="message-timestamp">Yesterday, 5:15 PM</span> </div> <div class="chat-message received slide-in"> <div class="message-content offer-message"> How about we meet in the middle at <span class="offer-highlight">$1,025</span>? I can pay immediately with secure payment. </div> <span class="message-timestamp">Yesterday, 5:16 PM</span> </div> <div class="chat-message sent slide-in"> <div class="message-content"> I've had several inquiries about the camera, but I appreciate your interest and prompt responses. </div> <span class="message-timestamp">Today, 9:30 AM</span> </div> <div class="chat-message sent slide-in"> <div class="message-content offer-message"> Let's do <span class="offer-highlight">$1,050</span> and I'll include an extra roll of film and expedited shipping. That's my final offer. </div> <span class="message-timestamp">Today, 9:31 AM</span> </div> <div class="typing-indicator" id="typing-indicator"> <div class="typing-animation"> <div class="typing-dot"></div> <div class="typing-dot"></div> <div class="typing-dot"></div> </div> </div> </div> <div class="negotiation-tools"> <div class="negotiation-tool" id="make-offer-tool"> <i class="material-icons">local_offer</i> Make an offer </div> <div class="negotiation-tool"> <i class="material-icons">check_circle</i> Accept offer </div> <div class="negotiation-tool"> <i class="material-icons">refresh</i> Counter offer </div> <div class="negotiation-tool"> <i class="material-icons">schedule</i> Request time </div> <div class="negotiation-tool"> <i class="material-icons">help</i> Ask question </div> </div> <div class="chat-footer"> <div class="chat-input-wrapper"> <input type="text" class="chat-input" id="chat-input" placeholder="Type a message or use quick actions..."> </div> <button class="btn btn-primary btn-icon" id="send-btn"> <i class="material-icons">send</i> </button> </div> <div id="offer-form" style="display: none; position: absolute; bottom: 80px; left: 20px; right: 20px; background: white; padding: 16px; border-radius: 12px; box-shadow: var(--shadow-lg); z-index: 100; border: 1px solid var(--neutral-light);"> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;"> <h3 style="font-size: 16px; color: var(--neutral-darkest);">Make an Offer</h3> <button id="close-offer-form" style="background: none; border: none; cursor: pointer;"> <i class="material-icons">close</i> </button> </div> <div class="price-input-wrapper"> <span>$</span> <input type="number" class="price-input" id="price-input" placeholder="Enter your offer" value="1050"> </div> <div class="price-adjustment"> <button class="price-adjust-btn" id="decrease-price"> <i class="material-icons">remove</i> </button> <div style="flex: 1; height: 2px; background-color: var(--neutral-light); margin: 0 10px;"></div> <button class="price-adjust-btn" id="increase-price"> <i class="material-icons">add</i> </button> </div> <div style="margin-top: 16px; display: flex; justify-content: space-between; gap: 10px;"> <button class="btn btn-secondary" id="cancel-offer">Cancel</button> <button class="btn btn-success pulse-animation" id="submit-offer">Send Offer</button> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const chatBody = document.getElementById('chat-body'); const chatInput = document.getElementById('chat-input'); const sendBtn = document.getElementById('send-btn'); const makeOfferTool = document.getElementById('make-offer-tool'); const offerForm = document.getElementById('offer-form'); const closeOfferForm = document.getElementById('close-offer-form'); const priceInput = document.getElementById('price-input'); const decreasePrice = document.getElementById('decrease-price'); const increasePrice = document.getElementById('increase-price'); const submitOffer = document.getElementById('submit-offer'); const cancelOffer = document.getElementById('cancel-offer'); const typingIndicator = document.getElementById('typing-indicator'); // Auto-scroll to bottom of chat chatBody.scrollTop = chatBody.scrollHeight; // Show typing indicator after page load setTimeout(() => { typingIndicator.classList.add('visible'); // After "typing", show the response setTimeout(() => { typingIndicator.classList.remove('visible'); const newMessage = document.createElement('div'); newMessage.className = 'chat-message received slide-in'; newMessage.innerHTML = ` <div class="message-content"> You've got a deal! $1,050 with the extra film and expedited shipping sounds fair. Let me know the payment details and I'll complete the transaction right away. </div> <span class="message-timestamp">Just now</span> `; chatBody.appendChild(newMessage); chatBody.scrollTop = chatBody.scrollHeight; // Add reply options setTimeout(() => { const replyOptions = document.createElement('div'); replyOptions.className = 'reply-options slide-in'; replyOptions.innerHTML = ` <div class="reply-option">Send payment instructions</div> <div class="reply-option">Confirm delivery timeline</div> <div class="reply-option">Arrange pickup details</div> `; chatBody.appendChild(replyOptions); chatBody.scrollTop = chatBody.scrollHeight; // Make reply options clickable const options = replyOptions.querySelectorAll('.reply-option'); options.forEach(option => { option.addEventListener('click', function() { const optionText = this.textContent; // Remove reply options replyOptions.remove(); // Add new message based on selection const responseMessage = document.createElement('div'); responseMessage.className = 'chat-message sent slide-in'; let messageContent = ''; if (optionText === 'Send payment instructions') { messageContent = `Great! Here are the payment details. I've set up a secure payment request through the marketplace. You should receive a notification shortly. Once payment is confirmed, I'll ship the camera with tracking.`; } else if (optionText === 'Confirm delivery timeline') { messageContent = `Perfect! Once payment is confirmed, I'll ship the camera via expedited shipping within 24 hours. You should receive it within 2-3 business days with full tracking information.`; } else { messageContent = `Sounds good! If you prefer pickup, we can arrange a meeting at a safe public location. Would the downtown marketplace on Saturday around noon work for you?`; } responseMessage.innerHTML = ` <div class="message-content"> ${messageContent} </div> <span class="message-timestamp">Just now</span> `; chatBody.appendChild(responseMessage); chatBody.scrollTop = chatBody.scrollHeight; }); }); }, 1000); }, 2500); }, 1500); // Send message function function sendMessage() { const message = chatInput.value.trim(); if (message === '') return; const newMessage = document.createElement('div'); newMessage.className = 'chat-message sent slide-in'; newMessage.innerHTML = ` <div class="message-content"> ${message} </div> <span class="message-timestamp">Just now</span> `; chatBody.appendChild(newMessage); chatInput.value = ''; chatBody.scrollTop = chatBody.scrollHeight; // Simulate response setTimeout(() => { typingIndicator.classList.add('visible'); chatBody.scrollTop = chatBody.scrollHeight; setTimeout(() => { typingIndicator.classList.remove('visible'); const responseMessage = document.createElement('div'); responseMessage.className = 'chat-message received slide-in'; // Generate a contextual response based on the message let responseText = ''; const lowerMessage = message.toLowerCase(); if (lowerMessage.includes('payment') || lowerMessage.includes('pay')) { responseText = 'I'll complete the payment as soon as I receive the request. I have my payment method ready to go!'; } else if (lowerMessage.includes('ship') || lowerMessage.includes('delivery') || lowerMessage.includes('send')) { responseText = 'That shipping timeline works great for me. I'm excited to receive the camera soon!'; } else if (lowerMessage.includes('meet') || lowerMessage.includes('pickup')) { responseText = 'Saturday at noon works perfectly. Let's meet at the main entrance of the downtown marketplace. I'll be wearing a blue jacket.'; } else { responseText = 'Thanks for the information. Looking forward to completing this transaction!'; } responseMessage.innerHTML = ` <div class="message-content"> ${responseText} </div> <span class="message-timestamp">Just now</span> `; chatBody.appendChild(responseMessage); chatBody.scrollTop = chatBody.scrollHeight; }, 2000); }, 1000); } // Event Listeners sendBtn.addEventListener('click', sendMessage); chatInput.addEventListener('keypress', function(e) { if (e.key === 'Enter') { sendMessage(); } }); // Make offer tool functionality makeOfferTool.addEventListener('click', function() { offerForm.style.display = 'block'; offerForm.classList.add('slide-in'); }); closeOfferForm.addEventListener('click', function() { offerForm.style.display = 'none'; }); cancelOffer.addEventListener('click', function() { offerForm.style.display = 'none'; }); // Price adjustment buttons decreasePrice.addEventListener('click', function() { let currentValue = parseInt(priceInput.value) || 1050; currentValue = Math.max(currentValue - 25, 0); priceInput.value = currentValue; priceInput.classList.add('shake-animation'); setTimeout(() => { priceInput.classList.remove('shake-animation'); }, 500); }); increasePrice.addEventListener('click', function() { let currentValue = parseInt(priceInput.value) || 1050; currentValue += 25; priceInput.value = currentValue; priceInput.classList.add('shake-animation'); setTimeout(() => { priceInput.classList.remove('shake-animation'); }, 500); }); // Submit offer submitOffer.addEventListener('click', function() { const offerAmount = priceInput.value.trim(); if (!offerAmount) return; offerForm.style.display = 'none'; const newMessage = document.createElement('div'); newMessage.className = 'chat-message sent slide-in'; newMessage.innerHTML = ` <div class="message-content offer-message"> I'd like to make a counter-offer of <span class="offer-highlight">$${offerAmount}</span> for the Leica M6. What do you think? </div> <span class="message-timestamp">Just now</span> `; chatBody.appendChild(newMessage); chatBody.scrollTop = chatBody.scrollHeight; // Simulate response setTimeout(() => { typingIndicator.classList.add('visible'); chatBody.scrollTop = chatBody.scrollHeight; setTimeout(() => { typingIndicator.classList.remove('visible'); // Response logic based on offer amount const originalPrice = 1200; const offerValue = parseInt(offerAmount); let responseText = ''; if (offerValue >= 1100) { responseText = `That's a fair offer! I can accept $${offerAmount} for the camera. Would you like to proceed with the purchase?`; } else if (offerValue >= 1000) { responseText = `I appreciate your offer of $${offerAmount}, but I'm really looking to get at least $1,050 for this camera given its excellent condition.`; } else { responseText = `Thank you for your offer of $${offerAmount}, but that's significantly below what I can accept. This model in such good condition normally sells for around $1,200.`; } const responseMessage = document.createElement('div'); responseMessage.className = 'chat-message received slide-in'; responseMessage.innerHTML = ` <div class="message-content"> ${responseText} </div> <span class="message-timestamp">Just now</span> `; chatBody.appendChild(responseMessage); chatBody.scrollTop = chatBody.scrollHeight; }, 2000); }, 1000); }); // Make reply options clickable document.addEventListener('click', function(e) { if (e.target.classList.contains('reply-option')) { const replyOptions = e.target.closest('.reply-options'); if (replyOptions) { const optionText = e.target.textContent; chatInput.value = optionText; chatInput.focus(); } } }); // Prevent form submission document.querySelectorAll('form').forEach(form => { form.addEventListener('submit', function(e) { e.preventDefault(); return false; }); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>NetworkNexus Chat</title> <style> :root { --primary: #4f46e5; --primary-light: #6366f1; --primary-dark: #4338ca; --secondary: #0ea5e9; --accent: #f59e0b; --dark: #111827; --light: #f9fafb; --gray: #9ca3af; --gray-light: #e5e7eb; --gray-dark: #4b5563; --danger: #ef4444; --success: #10b981; --border-radius: 12px; --box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); --transition: all 0.3s ease; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } body { background-color: var(--light); height: 700px; width: 700px; max-width: 100%; display: flex; flex-direction: column; overflow: hidden; } .chat-container { display: flex; height: 100%; width: 100%; background-color: #ffffff; border-radius: var(--border-radius); box-shadow: var(--box-shadow); overflow: hidden; } .sidebar { width: 250px; background-color: var(--light); border-right: 1px solid var(--gray-light); display: flex; flex-direction: column; transition: var(--transition); position: relative; z-index: 10; } .sidebar-collapsed { width: 70px; } .sidebar-header { padding: 20px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--gray-light); background-color: white; position: sticky; top: 0; z-index: 5; } .sidebar-header h2 { font-size: 1.2rem; color: var(--dark); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .toggle-sidebar { background: none; border: none; color: var(--gray-dark); cursor: pointer; font-size: 1.2rem; transition: var(--transition); } .toggle-sidebar:hover { color: var(--primary); } .search-box { padding: 15px; position: sticky; top: 64px; background-color: white; z-index: 4; } .search-input { width: 100%; padding: 10px 15px; border-radius: 20px; border: 1px solid var(--gray-light); outline: none; font-size: 0.9rem; background-color: var(--gray-light); transition: var(--transition); } .search-input:focus { border-color: var(--primary-light); box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2); } .participants-list { overflow-y: auto; flex: 1; padding: 10px; } .participant { display: flex; align-items: center; padding: 10px; border-radius: var(--border-radius); margin-bottom: 8px; cursor: pointer; transition: var(--transition); position: relative; } .participant:hover { background-color: var(--gray-light); } .participant.active { background-color: rgba(79, 70, 229, 0.1); } .participant-avatar { width: 40px; height: 40px; border-radius: 50%; margin-right: 12px; object-fit: cover; border: 2px solid white; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } .participant-info { flex: 1; overflow: hidden; } .participant-name { font-weight: 600; font-size: 0.95rem; color: var(--dark); margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .participant-role { font-size: 0.8rem; color: var(--gray-dark); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .participant-status { width: 10px; height: 10px; border-radius: 50%; margin-left: 5px; } .status-online { background-color: var(--success); } .status-offline { background-color: var(--gray); } .status-busy { background-color: var(--danger); } .chat-area { flex: 1; display: flex; flex-direction: column; background-color: #ffffff; } .chat-header { padding: 15px 20px; border-bottom: 1px solid var(--gray-light); display: flex; align-items: center; justify-content: space-between; background-color: white; position: sticky; top: 0; z-index: 3; } .chat-title { display: flex; align-items: center; } .chat-title h2 { font-size: 1.1rem; color: var(--dark); margin-right: 10px; } .chat-subtitle { font-size: 0.85rem; color: var(--gray-dark); } .chat-actions { display: flex; gap: 10px; } .action-btn { background: none; border: none; color: var(--gray-dark); cursor: pointer; font-size: 1.1rem; padding: 5px; border-radius: 50%; transition: var(--transition); display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; } .action-btn:hover { background-color: var(--gray-light); color: var(--primary); } .messages-container { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 15px; } .message { display: flex; gap: 12px; max-width: 80%; animation: fadeIn 0.3s ease; } .message.outgoing { align-self: flex-end; flex-direction: row-reverse; } .message-avatar { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; } .message-content { display: flex; flex-direction: column; } .message-bubble { padding: 12px 16px; border-radius: 18px; font-size: 0.95rem; position: relative; max-width: 100%; word-wrap: break-word; } .message.incoming .message-bubble { background-color: var(--gray-light); color: var(--dark); border-bottom-left-radius: 5px; } .message.outgoing .message-bubble { background-color: var(--primary); color: white; border-bottom-right-radius: 5px; } .message-info { display: flex; align-items: center; margin-top: 4px; font-size: 0.75rem; color: var(--gray-dark); } .message.outgoing .message-info { justify-content: flex-end; } .message-time { margin-right: 8px; } .message-status { display: flex; align-items: center; } .network-prompt { background-color: rgba(15, 118, 110, 0.08); border-radius: var(--border-radius); border-left: 3px solid var(--success); padding: 15px; margin: 15px 0; font-size: 0.9rem; color: var(--dark); animation: fadeIn 0.5s ease; } .network-prompt-title { font-weight: 600; margin-bottom: 8px; color: var(--success); } .network-prompt-actions { display: flex; gap: 10px; margin-top: 10px; } .network-prompt-btn { padding: 8px 15px; border-radius: 20px; font-size: 0.8rem; font-weight: 500; cursor: pointer; transition: var(--transition); border: none; } .network-prompt-btn.primary { background-color: var(--success); color: white; } .network-prompt-btn.secondary { background-color: transparent; border: 1px solid var(--success); color: var(--success); } .network-prompt-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .profile-preview { position: absolute; background-color: white; border-radius: var(--border-radius); box-shadow: var(--box-shadow); width: 300px; z-index: 100; opacity: 0; pointer-events: none; transition: opacity 0.3s ease, transform 0.3s ease; transform: translateY(10px); overflow: hidden; } .profile-preview.show { opacity: 1; pointer-events: auto; transform: translateY(0); } .profile-header { background: linear-gradient(135deg, var(--primary), var(--secondary)); height: 80px; position: relative; } .profile-avatar-wrapper { position: absolute; bottom: -30px; left: 20px; } .profile-avatar { width: 70px; height: 70px; border-radius: 50%; border: 4px solid white; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); object-fit: cover; } .profile-body { padding: 40px 20px 20px; } .profile-name { font-size: 1.1rem; font-weight: 600; color: var(--dark); margin-bottom: 5px; } .profile-role { font-size: 0.85rem; color: var(--gray-dark); margin-bottom: 15px; } .profile-bio { font-size: 0.9rem; color: var(--gray-dark); margin-bottom: 15px; line-height: 1.5; } .profile-stats { display: flex; gap: 15px; margin-bottom: 15px; } .stat { display: flex; flex-direction: column; align-items: center; } .stat-value { font-weight: 600; color: var(--primary); font-size: 1rem; } .stat-label { font-size: 0.75rem; color: var(--gray-dark); } .profile-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 15px; } .profile-tag { background-color: var(--gray-light); padding: 5px 10px; border-radius: 15px; font-size: 0.75rem; color: var(--gray-dark); } .profile-actions { display: flex; gap: 10px; } .profile-btn { flex: 1; padding: 8px; border-radius: 6px; font-size: 0.85rem; font-weight: 500; cursor: pointer; transition: var(--transition); border: none; text-align: center; } .profile-btn.primary { background-color: var(--primary); color: white; } .profile-btn.secondary { background-color: var(--gray-light); color: var(--gray-dark); } .profile-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .chat-input-container { padding: 15px; border-top: 1px solid var(--gray-light); background-color: white; position: sticky; bottom: 0; } .chat-input-wrapper { display: flex; align-items: center; background-color: var(--gray-light); border-radius: 24px; padding: 5px; transition: var(--transition); } .chat-input-wrapper:focus-within { box-shadow: 0 0 0 2px var(--primary-light); } .chat-input-tools { display: flex; padding: 0 5px; } .tool-btn { background: none; border: none; color: var(--gray-dark); cursor: pointer; font-size: 1.1rem; padding: 8px; border-radius: 50%; transition: var(--transition); } .tool-btn:hover { color: var(--primary); background-color: rgba(79, 70, 229, 0.1); } .chat-input { flex: 1; border: none; outline: none; padding: 10px; background-color: transparent; font-size: 0.95rem; resize: none; max-height: 120px; min-height: 24px; } .send-btn { background-color: var(--primary); color: white; border: none; width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--transition); } .send-btn:hover { background-color: var(--primary-dark); transform: scale(1.05); } .send-btn:disabled { background-color: var(--gray); cursor: not-allowed; transform: scale(1); } /* Typing indicator */ .typing-indicator { display: flex; align-items: center; margin-top: 5px; font-size: 0.85rem; color: var(--gray-dark); animation: fadeIn 0.3s ease; } .typing-dots { display: flex; margin-left: 5px; } .typing-dot { width: 6px; height: 6px; border-radius: 50%; background-color: var(--gray-dark); margin-right: 3px; animation: typingDot 1.4s infinite ease-in-out; } .typing-dot:nth-child(1) { animation-delay: 0s; } .typing-dot:nth-child(2) { animation-delay: 0.2s; } .typing-dot:nth-child(3) { animation-delay: 0.4s; margin-right: 0; } /* Notification badge */ .notification-badge { background-color: var(--danger); color: white; border-radius: 50%; width: 18px; height: 18px; font-size: 0.7rem; display: flex; align-items: center; justify-content: center; position: absolute; top: 5px; right: 5px; } /* System message */ .system-message { text-align: center; padding: 8px 16px; background-color: rgba(79, 70, 229, 0.1); border-radius: 20px; font-size: 0.85rem; color: var(--primary); margin: 10px 0; max-width: 80%; align-self: center; animation: fadeIn 0.3s ease; } /* Animations */ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes typingDot { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-4px); } } /* Responsive design */ @media (max-width: 650px) { .sidebar { position: absolute; left: 0; top: 0; bottom: 0; transform: translateX(-100%); box-shadow: 5px 0 15px rgba(0, 0, 0, 0.1); } .sidebar.mobile-visible { transform: translateX(0); } .sidebar-collapsed { transform: translateX(-100%); } .messages-container { padding: 15px 10px; } .message { max-width: 90%; } .mobile-menu-btn { display: block !important; } } .mobile-menu-btn { display: none; background: none; border: none; color: var(--gray-dark); cursor: pointer; font-size: 1.2rem; margin-right: 10px; } /* Custom scrollbar */ ::-webkit-scrollbar { width: 6px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background-color: var(--gray); border-radius: 10px; } ::-webkit-scrollbar-thumb:hover { background-color: var(--gray-dark); } </style> </head> <body> <div class="chat-container"> <div class="sidebar"> <div class="sidebar-header"> <h2>NetworkNexus</h2> <button class="toggle-sidebar"> <i class="fas fa-chevron-left"></i> </button> </div> <div class="search-box"> <input type="text" class="search-input" placeholder="Search participants..."> </div> <div class="participants-list"> <div class="participant active" data-id="user1"> <img src="https://randomuser.me/api/portraits/women/44.jpg" alt="Sarah Chen" class="participant-avatar"> <div class="participant-info"> <div class="participant-name">Sarah Chen</div> <div class="participant-role">UX Designer @ Figma</div> </div> <div class="participant-status status-online"></div> </div> <div class="participant" data-id="user2"> <img src="https://randomuser.me/api/portraits/men/32.jpg" alt="Marcus Johnson" class="participant-avatar"> <div class="participant-info"> <div class="participant-name">Marcus Johnson</div> <div class="participant-role">Product Manager @ Slack</div> </div> <div class="participant-status status-online"></div> <div class="notification-badge">3</div> </div> <div class="participant" data-id="user3"> <img src="https://randomuser.me/api/portraits/women/68.jpg" alt="Priya Patel" class="participant-avatar"> <div class="participant-info"> <div class="participant-name">Priya Patel</div> <div class="participant-role">Frontend Dev @ Shopify</div> </div> <div class="participant-status status-busy"></div> </div> <div class="participant" data-id="user4"> <img src="https://randomuser.me/api/portraits/men/75.jpg" alt="David Kim" class="participant-avatar"> <div class="participant-info"> <div class="participant-name">David Kim</div> <div class="participant-role">VC @ Sequoia Capital</div> </div> <div class="participant-status status-offline"></div> </div> <div class="participant" data-id="user5"> <img src="https://randomuser.me/api/portraits/women/90.jpg" alt="Elena Rodriguez" class="participant-avatar"> <div class="participant-info"> <div class="participant-name">Elena Rodriguez</div> <div class="participant-role">CTO @ Webflow</div> </div> <div class="participant-status status-online"></div> </div> <div class="participant" data-id="user6"> <img src="https://randomuser.me/api/portraits/men/40.jpg" alt="Jordan Taylor" class="participant-avatar"> <div class="participant-info"> <div class="participant-name">Jordan Taylor</div> <div class="participant-role">Design Lead @ Airbnb</div> </div> <div class="participant-status status-online"></div> </div> </div> </div> <div class="chat-area"> <div class="chat-header"> <button class="mobile-menu-btn"> <i class="fas fa-bars"></i> </button> <div class="chat-title"> <h2>Sarah Chen</h2> <div class="chat-subtitle">UX Designer @ Figma</div> </div> <div class="chat-actions"> <button class="action-btn" id="video-call-btn"> <i class="fas fa-video"></i> </button> <button class="action-btn" id="phone-call-btn"> <i class="fas fa-phone"></i> </button> <button class="action-btn" id="info-btn"> <i class="fas fa-info-circle"></i> </button> </div> </div> <div class="messages-container"> <div class="system-message"> Chat started on June 15, 2023 β’ Virtual Design Summit </div> <div class="message incoming"> <img src="https://randomuser.me/api/portraits/women/44.jpg" alt="Sarah Chen" class="message-avatar"> <div class="message-content"> <div class="message-bubble"> Hi there! I noticed you're working on some interesting AI-powered design tools. I'm currently exploring similar concepts at Figma. Would love to exchange ideas! </div> <div class="message-info"> <span class="message-time">2:14 PM</span> </div> </div> </div> <div class="message outgoing"> <img src="https://randomuser.me/api/portraits/men/86.jpg" alt="You" class="message-avatar"> <div class="message-content"> <div class="message-bubble"> Hey Sarah! Absolutely, I'd love to chat about that. We've been experimenting with ML models to automate some tedious design tasks. What specific area are you focusing on at Figma? </div> <div class="message-info"> <span class="message-time">2:16 PM</span> <span class="message-status"> <i class="fas fa-check-double"></i> </span> </div> </div> </div> <div class="message incoming"> <img src="https://randomuser.me/api/portraits/women/44.jpg" alt="Sarah Chen" class="message-avatar"> <div class="message-content"> <div class="message-bubble"> I'm part of the team exploring AI-assisted design systems - particularly how we can use ML to help maintain consistency across large design systems while still allowing for creative exploration. The challenge is balancing automation with designer control. </div> <div class="message-info"> <span class="message-time">2:19 PM</span> </div> </div> </div> <div class="network-prompt"> <div class="network-prompt-title"> <i class="fas fa-lightbulb"></i> Networking Opportunity </div> <p>You and Sarah both share interests in AI-powered design tools. This could be a great opportunity to schedule a follow-up conversation on collaborative innovation.</p> <div class="network-prompt-actions"> <button class="network-prompt-btn primary">Schedule Meeting</button> <button class="network-prompt-btn secondary">Share Contact</button> </div> </div> <div class="message outgoing"> <img src="https://randomuser.me/api/portraits/men/86.jpg" alt="You" class="message-avatar"> <div class="message-content"> <div class="message-bubble"> That's fascinating! We're facing the exact same challenge. I'd love to dive deeper into how you're approaching this balance. Would you be open to scheduling a video call sometime next week to share some of our findings and possibly explore collaboration opportunities? </div> <div class="message-info"> <span class="message-time">2:23 PM</span> <span class="message-status"> <i class="fas fa-check-double"></i> </span> </div> </div> </div> <div class="typing-indicator"> <span>Sarah is typing</span> <div class="typing-dots"> <div class="typing-dot"></div> <div class="typing-dot"></div> <div class="typing-dot"></div> </div> </div> </div> <div class="chat-input-container"> <div class="chat-input-wrapper"> <div class="chat-input-tools"> <button class="tool-btn" id="emoji-btn"> <i class="far fa-smile"></i> </button> <button class="tool-btn" id="attach-btn"> <i class="fas fa-paperclip"></i> </button> </div> <textarea class="chat-input" placeholder="Type your message..."></textarea> <button class="send-btn" disabled> <i class="fas fa-paper-plane"></i> </button> </div> </div> </div> </div> <div class="profile-preview" id="profile-preview"> <div class="profile-header"> <div class="profile-avatar-wrapper"> <img src="https://randomuser.me/api/portraits/women/44.jpg" alt="Sarah Chen" class="profile-avatar"> </div> </div> <div class="profile-body"> <div class="profile-name">Sarah Chen</div> <div class="profile-role">UX Designer @ Figma</div> <div class="profile-bio"> Leading design systems initiatives at Figma. Previously at Google and Apple. Passionate about the intersection of AI and design. Based in San Francisco. </div> <div class="profile-stats"> <div class="stat"> <div class="stat-value">24</div> <div class="stat-label">Connections</div> </div> <div class="stat"> <div class="stat-value">8</div> <div class="stat-label">Sessions</div> </div> <div class="stat"> <div class="stat-value">3</div> <div class="stat-label">Shared Groups</div> </div> </div> <div class="profile-tags"> <div class="profile-tag">UX Design</div> <div class="profile-tag">AI</div> <div class="profile-tag">Design Systems</div> <div class="profile-tag">Product</div> <div class="profile-tag">Figma</div> </div> <div class="profile-actions"> <button class="profile-btn primary">Connect</button> <button class="profile-btn secondary">View Profile</button> </div> </div> </div> <script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script> <script> document.addEventListener('DOMContentLoaded', function() { // DOM elements const sidebar = document.querySelector('.sidebar'); const toggleSidebarBtn = document.querySelector('.toggle-sidebar'); const mobileMenuBtn = document.querySelector('.mobile-menu-btn'); const chatInput = document.querySelector('.chat-input'); const sendBtn = document.querySelector('.send-btn'); const messagesContainer = document.querySelector('.messages-container'); const participants = document.querySelectorAll('.participant'); const profilePreview = document.getElementById('profile-preview'); const typingIndicator = document.querySelector('.typing-indicator'); const networkPrompt = document.querySelector('.network-prompt'); const networkPromptBtns = document.querySelectorAll('.network-prompt-btn'); // Handle sidebar toggle toggleSidebarBtn.addEventListener('click', function() { sidebar.classList.toggle('sidebar-collapsed'); // Change icon direction const icon = this.querySelector('i'); if (sidebar.classList.contains('sidebar-collapsed')) { icon.classList.remove('fa-chevron-left'); icon.classList.add('fa-chevron-right'); } else { icon.classList.remove('fa-chevron-right'); icon.classList.add('fa-chevron-left'); } }); // Mobile menu mobileMenuBtn?.addEventListener('click', function() { sidebar.classList.toggle('mobile-visible'); }); // Enable/disable send button based on input chatInput.addEventListener('input', function() { if (this.value.trim() === '') { sendBtn.disabled = true; } else { sendBtn.disabled = false; } // Auto-resize the textarea this.style.height = 'auto'; this.style.height = (this.scrollHeight) + 'px'; }); // Scroll to bottom of messages function scrollToBottom() { messagesContainer.scrollTop = messagesContainer.scrollHeight; } scrollToBottom(); // Send message sendBtn.addEventListener('click', function() { if (chatInput.value.trim() === '') return; // Create new message element const messageElement = document.createElement('div'); messageElement.classList.add('message', 'outgoing'); const currentTime = new Date(); const hours = currentTime.getHours(); const minutes = currentTime.getMinutes(); const formattedTime = `${hours > 12 ? hours - 12 : hours}:${minutes < 10 ? '0' + minutes : minutes} ${hours >= 12 ? 'PM' : 'AM'}`; messageElement.innerHTML = ` <img src="https://randomuser.me/api/portraits/men/86.jpg" alt="You" class="message-avatar"> <div class="message-content"> <div class="message-bubble">${chatInput.value}</div> <div class="message-info"> <span class="message-time">${formattedTime}</span> <span class="message-status"> <i class="fas fa-check"></i> </span> </div> </div> `; // Insert before typing indicator if (typingIndicator.parentNode === messagesContainer) { messagesContainer.insertBefore(messageElement, typingIndicator); } else { messagesContainer.appendChild(messageElement); } // Clear and reset input field chatInput.value = ''; chatInput.style.height = 'auto'; sendBtn.disabled = true; // Scroll to bottom scrollToBottom(); // Simulate reply after delay setTimeout(() => { // Show typing indicator if not already visible if (!typingIndicator.parentNode === messagesContainer) { messagesContainer.appendChild(typingIndicator); scrollToBottom(); } setTimeout(() => { // Remove typing indicator if (typingIndicator.parentNode === messagesContainer) { messagesContainer.removeChild(typingIndicator); } // Add response message const responseElement = document.createElement('div'); responseElement.classList.add('message', 'incoming'); const responseTime = new Date(); responseTime.setMinutes(responseTime.getMinutes() + 1); const respHours = responseTime.getHours(); const respMinutes = responseTime.getMinutes(); const respFormattedTime = `${respHours > 12 ? respHours - 12 : respHours}:${respMinutes < 10 ? '0' + respMinutes : respMinutes} ${respHours >= 12 ? 'PM' : 'AM'}`; responseElement.innerHTML = ` <img src="https://randomuser.me/api/portraits/women/44.jpg" alt="Sarah Chen" class="message-avatar"> <div class="message-content"> <div class="message-bubble">Absolutely! I'd be happy to schedule a video call. How about Wednesday at 2 PM Pacific? I can share my screen and show you some of our prototypes.</div> <div class="message-info"> <span class="message-time">${respFormattedTime}</span> </div> </div> `; messagesContainer.appendChild(responseElement); scrollToBottom(); }, 2500); }, 1000); }); // Handle enter key to send message chatInput.addEventListener('keydown', function(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); if (!sendBtn.disabled) { sendBtn.click(); } } }); // Profile preview for participants participants.forEach(participant => { participant.addEventListener('mouseenter', function(e) { const rect = this.getBoundingClientRect(); const previewHeight = 350; // Approximate height of preview // Position the preview let top = rect.top; if (window.innerHeight - rect.top < previewHeight) { top = window.innerHeight - previewHeight - 10; } profilePreview.style.top = `${top}px`; profilePreview.style.left = `${rect.right + 10}px`; // Update content based on participant const name = this.querySelector('.participant-name').textContent; const role = this