diff options
Diffstat (limited to 'client/index.html')
-rw-r--r-- | client/index.html | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..941394f --- /dev/null +++ b/client/index.html @@ -0,0 +1,563 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>JCHAT - JMAP Chat Client</title> + <style> + * { + margin: 0; + padding: 0; + box-sizing: border-box; + } + + body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background-color: #f5f5f5; + height: 100vh; + display: flex; + flex-direction: column; + } + + .header { + background-color: #2c3e50; + color: white; + padding: 1rem 2rem; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + } + + .header h1 { + font-size: 1.5rem; + font-weight: 600; + } + + .connection-status { + padding: 0.5rem 1rem; + border-radius: 20px; + font-size: 0.9rem; + } + + .status-connected { + background-color: #27ae60; + } + + .status-disconnected { + background-color: #e74c3c; + } + + .status-connecting { + background-color: #f39c12; + } + + .main-container { + display: flex; + flex: 1; + overflow: hidden; + } + + .sidebar { + width: 300px; + background-color: white; + border-right: 1px solid #ddd; + display: flex; + flex-direction: column; + } + + .sidebar-header { + padding: 1rem; + background-color: #34495e; + color: white; + font-weight: 600; + } + + .user-info { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 1rem; + font-size: 0.9rem; + } + + .user-settings-btn { + background: none; + border: none; + cursor: pointer; + padding: 0.25rem; + border-radius: 4px; + font-size: 1rem; + color: white; + } + + .user-settings-btn:hover { + background: rgba(255,255,255,0.2); + } + + .new-conversation-btn { + width: 100%; + padding: 0.75rem; + background: #3498db; + color: white; + border: none; + border-radius: 8px; + cursor: pointer; + font-size: 0.9rem; + font-weight: 500; + transition: background-color 0.2s; + } + + .new-conversation-btn:hover { + background: #2980b9; + } + + /* Modal Styles */ + .modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0,0,0,0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + } + + .modal-content { + background: white; + padding: 2rem; + border-radius: 12px; + min-width: 400px; + max-width: 500px; + } + + .modal-content h3 { + margin-top: 0; + margin-bottom: 1.5rem; + color: #333; + } + + .modal-content label { + display: block; + margin-bottom: 1rem; + font-weight: 500; + color: #555; + } + + .modal-content input, + .modal-content textarea { + width: 100%; + padding: 0.75rem; + border: 1px solid #ddd; + border-radius: 6px; + margin-top: 0.25rem; + font-size: 0.9rem; + } + + .modal-content textarea { + resize: vertical; + min-height: 80px; + } + + .modal-buttons { + display: flex; + gap: 1rem; + justify-content: flex-end; + margin-top: 1.5rem; + } + + .modal-buttons button { + padding: 0.75rem 1.5rem; + border: none; + border-radius: 6px; + cursor: pointer; + font-size: 0.9rem; + font-weight: 500; + } + + .modal-buttons button:first-child { + background: #4f46e5; + color: white; + } + + .modal-buttons button:first-child:hover { + background: #3730a3; + } + + .modal-buttons button:last-child { + background: #f3f4f6; + color: #374151; + } + + .modal-buttons button:last-child:hover { + background: #e5e7eb; + } + + .conversation-list { + flex: 1; + overflow-y: auto; + } + + .conversation-item { + padding: 1rem; + border-bottom: 1px solid #eee; + cursor: pointer; + transition: background-color 0.2s; + } + + .conversation-item:hover { + background-color: #f8f9fa; + } + + .conversation-item.active { + background-color: #3498db; + color: white; + } + + .conversation-title { + font-weight: 600; + margin-bottom: 0.25rem; + } + + .conversation-preview { + font-size: 0.9rem; + color: #666; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .conversation-item.active .conversation-preview { + color: #ecf0f1; + } + + .conversation-meta { + font-size: 0.8rem; + color: #999; + margin-top: 0.25rem; + display: flex; + justify-content: space-between; + } + + .conversation-item.active .conversation-meta { + color: #bdc3c7; + } + + .chat-area { + flex: 1; + display: flex; + flex-direction: column; + background-color: white; + } + + .chat-header { + padding: 1rem 2rem; + background-color: white; + border-bottom: 1px solid #ddd; + font-weight: 600; + } + + .messages-container { + flex: 1; + overflow-y: auto; + padding: 1rem; + display: flex; + flex-direction: column; + gap: 1rem; + } + + .message { + display: flex; + gap: 0.75rem; + max-width: 70%; + } + + .message.own { + align-self: flex-end; + flex-direction: row-reverse; + } + + .message-avatar { + width: 40px; + height: 40px; + border-radius: 50%; + background-color: #3498db; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 600; + font-size: 0.9rem; + flex-shrink: 0; + } + + .message-content { + background-color: #f8f9fa; + padding: 0.75rem 1rem; + border-radius: 18px; + position: relative; + } + + .message.own .message-content { + background-color: #3498db; + color: white; + } + + .message-sender { + font-weight: 600; + font-size: 0.9rem; + margin-bottom: 0.25rem; + } + + .message.own .message-sender { + display: none; + } + + .message-text { + line-height: 1.4; + } + + .message-time { + font-size: 0.8rem; + color: #999; + margin-top: 0.25rem; + } + + .message.own .message-time { + color: rgba(255,255,255,0.8); + } + + .message-input-area { + padding: 1rem 2rem; + background-color: white; + border-top: 1px solid #ddd; + display: flex; + gap: 1rem; + align-items: center; + } + + .message-input { + flex: 1; + padding: 0.75rem 1rem; + border: 1px solid #ddd; + border-radius: 24px; + font-size: 1rem; + outline: none; + resize: none; + max-height: 120px; + min-height: 44px; + } + + .message-input:focus { + border-color: #3498db; + } + + .send-button { + background-color: #3498db; + color: white; + border: none; + width: 44px; + height: 44px; + border-radius: 50%; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: background-color 0.2s; + } + + .send-button:hover:not(:disabled) { + background-color: #2980b9; + } + + .send-button:disabled { + background-color: #bdc3c7; + cursor: not-allowed; + } + + .empty-state { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: #666; + } + + .empty-state h3 { + margin-bottom: 0.5rem; + } + + .loading { + display: flex; + align-items: center; + justify-content: center; + padding: 2rem; + color: #666; + } + + .error { + background-color: #e74c3c; + color: white; + padding: 1rem; + margin: 1rem; + border-radius: 6px; + } + + /* Mobile responsive */ + @media (max-width: 768px) { + .main-container { + flex-direction: column; + } + + .sidebar { + width: 100%; + height: 200px; + } + + .message { + max-width: 85%; + } + } + </style> +</head> +<body> + <div class="header"> + <h1>JCHAT Client</h1> + <div class="connection-status status-disconnected" id="connectionStatus"> + Disconnected + </div> + </div> + + <div class="main-container"> + <div class="sidebar"> + <div class="sidebar-header"> + <div class="user-info"> + <span id="currentUser">Anonymous User</span> + <button class="user-settings-btn" onclick="showUserSettings()" title="User Settings">⚙️</button> + </div> + <button class="new-conversation-btn" onclick="showNewConversationDialog()">+ New Conversation</button> + </div> + <div class="conversation-list" id="conversationList"> + <div class="loading">Loading conversations...</div> + </div> + </div> + + <div class="chat-area"> + <div class="chat-header" id="chatHeader"> + Select a conversation + </div> + <div class="messages-container" id="messagesContainer"> + <div class="empty-state"> + <h3>Welcome to JCHAT</h3> + <p>Select a conversation to start chatting</p> + </div> + </div> + <div class="message-input-area" id="messageInputArea" style="display: none;"> + <textarea + class="message-input" + id="messageInput" + placeholder="Type a message..." + rows="1"></textarea> + <button class="send-button" id="sendButton" disabled> + <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"> + <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/> + </svg> + </button> + </div> + </div> + </div> + + <!-- Authentication Modals --> + <!-- Login Modal --> + <div class="modal" id="loginModal" style="display: none;"> + <div class="modal-content"> + <h3>Log In</h3> + <div id="loginError" style="color: #e74c3c; margin-bottom: 1rem; display: none;"></div> + <label> + Email: + <input type="email" id="loginEmail" placeholder="Enter your email" required> + </label> + <label> + Password: + <input type="password" id="loginPassword" placeholder="Enter your password" required> + </label> + <div class="modal-buttons"> + <button onclick="performLogin()">Log In</button> + <button onclick="showRegisterModal()">Register Instead</button> + <button onclick="closeModal('loginModal')">Cancel</button> + </div> + </div> + </div> + + <!-- Register Modal --> + <div class="modal" id="registerModal" style="display: none;"> + <div class="modal-content"> + <h3>Create Account</h3> + <div id="registerError" style="color: #e74c3c; margin-bottom: 1rem; display: none;"></div> + <label> + Email: + <input type="email" id="registerEmail" placeholder="Enter your email" required> + </label> + <label> + Display Name: + <input type="text" id="registerDisplayName" placeholder="Enter your display name" required> + </label> + <label> + Password: + <input type="password" id="registerPassword" placeholder="Create a password (min 8 characters)" required> + </label> + <label> + Confirm Password: + <input type="password" id="registerConfirmPassword" placeholder="Confirm your password" required> + </label> + <div class="modal-buttons"> + <button onclick="performRegistration()">Create Account</button> + <button onclick="showLoginModal()">Log In Instead</button> + <button onclick="closeModal('registerModal')">Cancel</button> + </div> + </div> + </div> + + <!-- User Settings Modal --> + <div class="modal" id="userSettingsModal" style="display: none;"> + <div class="modal-content"> + <h3>User Settings</h3> + <label> + Display Name: + <input type="text" id="userDisplayName" placeholder="Enter your name"> + </label> + <div class="modal-buttons"> + <button onclick="saveUserSettings()">Save</button> + <button onclick="closeModal('userSettingsModal')">Cancel</button> + </div> + </div> + </div> + + <!-- New Conversation Modal --> + <div class="modal" id="newConversationModal" style="display: none;"> + <div class="modal-content"> + <h3>New Conversation</h3> + <label> + Conversation Title: + <input type="text" id="newConversationTitle" placeholder="Enter conversation title"> + </label> + <label> + Description (optional): + <textarea id="newConversationDescription" placeholder="Conversation description"></textarea> + </label> + <div class="modal-buttons"> + <button onclick="createNewConversation()">Create</button> + <button onclick="closeModal('newConversationModal')">Cancel</button> + </div> + </div> + </div> + + <script src="config.js"></script> + <script src="jmap-client.js"></script> + <script src="app.js"></script> +</body> +</html> |