From 4ddbf1ee2a4d567cd297a405cb3b0ef994a8914f Mon Sep 17 00:00:00 2001 From: defnax <9952056+defnax@users.noreply.github.com> Date: Sun, 5 Jul 2026 23:49:52 +0200 Subject: [PATCH] Redesign Chat rooms --- webui-src/app/chat/chat.js | 621 +++++++++--- webui-src/app/scss/pages/_chat.scss | 1413 ++++++++++++++++++++------- webui-src/styles.css | 722 ++++++++++++++ 3 files changed, 2262 insertions(+), 494 deletions(-) diff --git a/webui-src/app/chat/chat.js b/webui-src/app/chat/chat.js index 0069b84..987dbe6 100644 --- a/webui-src/app/chat/chat.js +++ b/webui-src/app/chat/chat.js @@ -192,7 +192,7 @@ const Message = () => { .replaceAll('
', '\n') .replace(new RegExp('|<[^>]*>', 'gm'), ''); return m( - '.message', + '.message' + (msg.incoming ? '.incoming' : '.outgoing'), m('span.datetime', datetime), m('span.username', username), m('span.messagetext', text) @@ -395,20 +395,23 @@ const ChatLobbyModel = { } }; - // Lookup for chat-user names (Only for lobbies for now) // Lookup for chat-user names if (detail.gxs_ids) { - let names = []; + let list = []; if (Array.isArray(detail.gxs_ids)) { - names = detail.gxs_ids.reduce((a, u) => a.concat(rs.userList.username(u.key)), []); + list = detail.gxs_ids.map((u) => { + const key = u.key; + return { key, name: rs.userList.username(key) }; + }); } else if (typeof detail.gxs_ids === 'object') { - names = Object.keys(detail.gxs_ids).map(key => rs.userList.username(key)); + list = Object.keys(detail.gxs_ids).map((key) => { + return { key, name: rs.userList.username(key) }; + }); } - names.sort((a, b) => a.localeCompare(b)); - this.users = []; - names.forEach((name) => (this.users = this.users.concat([m('.user', name)]))); + list.sort((a, b) => a.name.localeCompare(b.name)); + this.users = list; } else { - this.users = [m('.user', detail.lobby_name)]; + this.users = [{ key: detail.gxs_id || '', name: detail.lobby_name }]; } m.redraw(); }; @@ -484,6 +487,38 @@ const ChatLobbyModel = { }, }; +// ************************* Chat Hub State **************************** + +function getSafeAvatar(details) { + if ( + details && + details.mAvatar && + details.mAvatar.mData && + details.mAvatar.mData.base64 !== '' + ) { + return details.mAvatar; + } + return undefined; +} + +const ChatHubState = { + selectedRoomId: null, + selectedRoom: null, + selectedRoomType: null, + searchString: '', + ownProfile: { name: 'Loading...' }, + gxsDetails: {}, +}; + +function loadOwnChatProfile() { + rs.rsJsonApiRequest('/rsConfig/getConfigNetStatus', {}, (data) => { + if (data && data.status) { + ChatHubState.ownProfile.name = data.status.ownName || 'Unknown'; + m.redraw(); + } + }); +} + // ************************* views **************************** const Lobby = () => { @@ -523,20 +558,6 @@ const LobbyList = { }, }; -const SubscribedLeftLobbies = { - view() { - return [ - m('h5.lefttitle', 'subscribed:'), - m(LobbyList, { - rooms: sortLobbies(Object.values(ChatRoomsModel.subscribedRooms)), - tagname: '.leftlobby.subscribed', - lobbytagname: 'leftname', - onclick: ChatLobbyModel.switchToEvent, - }), - ]; - }, -}; - const SubscribedLobbies = { view() { return m('.widget', [ @@ -552,22 +573,6 @@ const SubscribedLobbies = { }, }; -const PublicLeftLobbies = { - view() { - return [ - m('h5.lefttitle', 'public:'), - m(LobbyList, { - rooms: Object.values(ChatRoomsModel.allRooms || {}).filter( - (info) => !ChatRoomsModel.subscribed(info) - ), - tagname: '.leftlobby.public', - lobbytagname: 'leftname', - onclick: ChatLobbyModel.setupEvent, - }), - ]; - }, -}; - const PublicLobbies = { view() { return m('.widget', [ @@ -583,78 +588,438 @@ const PublicLobbies = { }, }; -const LobbyName = () => { - return m( - 'h3.lobbyName', - m('.mobile-menu-icons', [ - m('i.fas.fa-bars', { onclick: () => MobileState.toggleLobbies() }), - ]), - ChatLobbyModel.isSubscribed - ? [m('span.chatusername', ChatLobbyModel.lobby_user), m('span.chatatchar', '@')] - : [], - ChatLobbyModel.currentLobby.chatType === 2 - ? m('i.fas.fa-circle', { - style: { - color: - ChatLobbyModel.currentLobby.status === 2 - ? '#2ecc71' // Green (Can Talk) - : ChatLobbyModel.currentLobby.status === 1 - ? '#f39c12' // Orange (Tunnel Down) - : ChatLobbyModel.currentLobby.status === 3 - ? '#e74c3c' // Red (Remotely Closed) - : '#95a5a6', // Grey (Unknown) - fontSize: '0.6em', - marginRight: '10px', - verticalAlign: 'middle', - }, - title: - ChatLobbyModel.currentLobby.status === 2 - ? 'Tunnel Active (Can Talk)' - : ChatLobbyModel.currentLobby.status === 1 - ? 'Tunnel Down (Negotiating...)' - : ChatLobbyModel.currentLobby.status === 3 - ? 'Remotely Closed' - : 'Status Unknown', - }) - : [], - m('span.chatlobbyname', ChatLobbyModel.currentLobby.lobby_name), - m('.mobile-menu-icons', [ - m('i.fas.fa-users', { onclick: () => MobileState.toggleUsers() }), - ]), - m.route.param('subaction') !== 'setup' && ChatLobbyModel.currentLobby.chatType === 3 - ? [ - m('i.fas.fa-cog.setupicon', { - title: 'configure lobby', - onclick: () => - m.route.set( - '/chat/:lobby/:subaction', - { - lobby: m.route.param('lobby'), - subaction: 'setup', +// ************************* Chat Hub Sub-Components **************************** + +const ChatRoomHeader = () => { + return { + view: (vnode) => { + const room = vnode.attrs.room; + const lobbyHexId = rs.idToHex(room.lobby_id); + return m('.chat-hub-header-bar', [ + m('.chat-header-info', [ + m('.chat-header-name', room.lobby_name || ''), + m('.chat-header-topic', room.lobby_topic || 'No topic'), + ]), + m('.chat-header-actions', [ + m( + 'button.red', + { + title: 'Leave Room', + onclick: () => { + ChatLobbyModel.unsubscribeChatLobby(lobbyHexId, () => { + ChatHubState.selectedRoom = null; + ChatHubState.selectedRoomId = null; + ChatHubState.selectedRoomType = null; + m.route.set('/chat'); + }); }, - { replace: true } - ), - }), - ] - : [], - ChatLobbyModel.isSubscribed - ? [ - m('i.fas.fa-sign-out-alt.leaveicon', { - title: 'leaving lobby', - onclick: () => - ChatLobbyModel.unsubscribeChatLobby(m.route.param('lobby'), () => { - m.route.set('/chat', null, { replace: true }); - }), - }), - ] - : [] - ); + }, + [m('i.fas.fa-sign-out-alt'), ' Leave'] + ), + ]), + ]); + }, + }; +}; + +function scrollChatToBottom() { + setTimeout(() => { + const element = document.querySelector('.chat-hub-messages'); + if (element) { + element.scrollTop = element.scrollHeight; + } + }, 50); +} + +const ChatConversationView = () => { + return { + oninit: () => { + scrollChatToBottom(); + }, + view: () => { + return m('.chat-hub-conversation-layout', [ + m('.chat-hub-conversation-main', [ + m( + '.chat-hub-messages', + { + oncreate: () => scrollChatToBottom(), + onupdate: () => scrollChatToBottom(), + }, + ChatLobbyModel.messages + ), + m( + '.chat-hub-input-area', + [ + m('textarea.chat-hub-textarea', { + placeholder: 'Type a message... Press Enter to send', + enterkeyhint: 'send', + onkeydown: (e) => { + if ((e.key === 'Enter' || e.keyCode === 13) && !e.shiftKey) { + const msg = e.target.value; + if (msg.trim() === '') return false; + e.target.value = ' sending ... '; + ChatLobbyModel.sendMessage(msg, () => { + e.target.value = ''; + scrollChatToBottom(); + }); + return false; + } + }, + }), + m( + 'button.chat-hub-send-btn', + { + onclick: (e) => { + const textarea = e.target.closest('.chat-hub-input-area').querySelector('textarea'); + const msg = textarea.value; + if (msg.trim() === '') return; + textarea.value = ' sending ... '; + ChatLobbyModel.sendMessage(msg, () => { + textarea.value = ''; + scrollChatToBottom(); + }); + }, + }, + m('i.fas.fa-paper-plane') + ), + ] + ), + ]), + m('.chat-hub-rightbar', [ + m('.rightbar-title', 'Participants'), + m('.rightbar-users-list', ChatLobbyModel.users.map((user) => { + const gxsId = user.key; + const name = user.name; + + // Load details for avatar if not cached + if (gxsId && ChatHubState.gxsDetails[gxsId] === undefined) { + ChatHubState.gxsDetails[gxsId] = null; // Mark as loading + rs.rsJsonApiRequest('/rsIdentity/getIdDetails', { id: gxsId }, (data) => { + if (data && data.details) { + ChatHubState.gxsDetails[gxsId] = data.details; + m.redraw(); + } + }); + } + + const avatar = getSafeAvatar(ChatHubState.gxsDetails[gxsId]); + const firstLetter = (name || '?').slice(0, 1).toUpperCase(); + + return m('.user', [ + m(peopleUtil.UserAvatar, { avatar, firstLetter }), + m('span.user-name', name), + ]); + })) + ]) + ]); + }, + }; }; // ***************************** Page Layouts ****************************** +const ChatRoomDetailView = () => { + return { + view: () => { + const room = ChatHubState.selectedRoom; + if (!room) return null; + + let participantCount = 0; + let participantNames = []; + if (room.gxs_ids) { + if (Array.isArray(room.gxs_ids)) { + participantCount = room.gxs_ids.length; + participantNames = room.gxs_ids.map((u) => rs.userList.username(u.key) || u.key); + } else if (typeof room.gxs_ids === 'object') { + const keys = Object.keys(room.gxs_ids); + participantCount = keys.length; + participantNames = keys.map((key) => rs.userList.username(key) || key); + } + } + participantNames.sort((a, b) => a.localeCompare(b)); + + const lobbyHexId = rs.idToHex(room.lobby_id); + + return m('.chat-room-detail-view', [ + m('.detail-section', [ + m('h3', 'Room Info'), + m('.info-grid', [ + m('.info-label', 'Room Name'), + m('.info-value', room.lobby_name || ''), + m('.info-label', 'Topic'), + m('.info-value', room.lobby_topic || 'None'), + m('.info-label', 'Participants'), + m('.info-value', participantCount + ' users'), + m('.info-label', 'Your Identity'), + m('.info-value', rs.userList.username(room.gxs_id) || room.gxs_id || '???'), + m('.info-label', 'Lobby ID'), + m('.info-value', lobbyHexId), + ]), + ]), + + m('.detail-section', [ + m('h3', 'Participants (' + participantCount + ')'), + participantNames.length > 0 + ? m( + '.participants-grid', + participantNames.map((name) => + m('.participant-card', m('.participant-name', name)) + ) + ) + : m('p.no-participants', 'No participant information available'), + ]), + ]); + }, + }; +}; + +const ChatRoomJoinView = () => { + let ownIds = []; + return { + oninit: () => peopleUtil.ownIds((data) => (ownIds = data)), + view: () => { + const room = ChatHubState.selectedRoom; + if (!room) return null; + + const lobbyHexId = rs.idToHex(room.lobby_id); + const participantCount = room.total_number_of_peers || 0; + + return m('.chat-room-detail-view', [ + m('.detail-section', [ + m('h3', 'Room Info'), + m('.info-grid', [ + m('.info-label', 'Room Name'), + m('.info-value', room.lobby_name || ''), + m('.info-label', 'Topic'), + m('.info-value', room.lobby_topic || 'None'), + m('.info-label', 'Participants'), + m('.info-value', participantCount + ' users'), + ]), + ]), + + m('.detail-section', [ + m('h3', 'Join Room'), + m('p.join-description', 'Select an identity to join this chat room:'), + m( + '.identities-grid', + ownIds.map((nick) => + m( + '.identity-card', + { onclick: () => ChatLobbyModel.enterPublicLobby(lobbyHexId, nick) }, + [ + m('.identity-name', rs.userList.username(nick) || nick), + m('i.fas.fa-sign-in-alt'), + ] + ) + ) + ), + ]), + ]); + }, + }; +}; + const Layout = { - view: () => m('.node-panel.chat-panel.chat-hub', [m(SubscribedLobbies), m(PublicLobbies)]), + oninit: () => { + ChatHubState.activeTab = 'chat'; + const lobbyId = m.route.param('lobby'); + if (lobbyId) { + ChatHubState.selectedRoomId = lobbyId; + ChatLobbyModel.loadLobby(lobbyId); + } + }, + onupdate: () => { + const lobbyId = m.route.param('lobby'); + if (lobbyId && ChatHubState.selectedRoomId !== lobbyId) { + ChatHubState.selectedRoomId = lobbyId; + ChatLobbyModel.loadLobby(lobbyId); + } + }, + view: () => { + const search = ChatHubState.searchString.toLowerCase(); + + const subscribedRooms = sortLobbies( + Object.values(ChatRoomsModel.subscribedRooms) + ).filter((info) => (info.lobby_name || '').toLowerCase().includes(search)); + + const publicRooms = (ChatRoomsModel.allRooms || []) + .filter((info) => !ChatRoomsModel.subscribed(info)) + .filter((info) => (info.lobby_name || '').toLowerCase().includes(search)); + + const isSelected = (info, type) => + ChatHubState.selectedRoomId === rs.idToHex(info.lobby_id); + + const lobbyId = ChatHubState.selectedRoomId; + let selectedRoom = null; + let selectedRoomType = null; + + if (lobbyId) { + if (ChatRoomsModel.subscribedRooms[lobbyId]) { + selectedRoom = ChatRoomsModel.subscribedRooms[lobbyId]; + selectedRoomType = 'subscribed'; + } else { + selectedRoom = ChatRoomsModel.allRooms.find( + (r) => rs.idToHex(r.lobby_id) === lobbyId + ); + if (selectedRoom) { + selectedRoomType = 'public'; + } + } + } + + if (selectedRoom) { + ChatHubState.selectedRoom = selectedRoom; + ChatHubState.selectedRoomType = selectedRoomType; + } else if (!m.route.param('lobby')) { + ChatHubState.selectedRoom = null; + ChatHubState.selectedRoomId = null; + ChatHubState.selectedRoomType = null; + } + + return m('.chat-hub-container', [ + m('.chat-hub-left-pane', [ + m('.chat-own-profile-card', [ + m('.profile-header', [ + m('i.fas.fa-comments', { style: { fontSize: '1.5rem', color: '#3ba4d7' } }), + m('.profile-info', [ + m('.profile-name', 'Chat rooms'), + ]), + ]), + ]), + + m('.chat-rooms-list-container', [ + m('.searchbar-container', [ + m('input.searchbar', { + type: 'text', + placeholder: 'Search chat rooms...', + value: ChatHubState.searchString, + oninput: (e) => { + ChatHubState.searchString = e.target.value; + }, + }), + ]), + m('.rooms-scroll', [ + subscribedRooms.length > 0 && [ + m('.rooms-section-title', [ + m('i.fas.fa-bookmark'), + m('span', 'Subscribed (' + subscribedRooms.length + ')'), + ]), + subscribedRooms.map((info) => { + const hexId = rs.idToHex(info.lobby_id); + let count = 0; + if (info.gxs_ids) { + if (Array.isArray(info.gxs_ids)) count = info.gxs_ids.length; + else if (typeof info.gxs_ids === 'object') + count = Object.keys(info.gxs_ids).length; + } + return m( + '.chat-room-list-item' + + (isSelected(info, 'subscribed') ? '.selected' : ''), + { + key: hexId, + onclick: () => { + m.route.set('/chat/:lobby', { lobby: hexId }); + }, + }, + [ + m('.room-icon', m('i.fas.fa-comments')), + m('.room-meta', [ + m('.room-name', info.lobby_name || ''), + m('.room-topic', info.lobby_topic || 'No topic'), + ]), + count > 0 && m('.room-badge', count), + ] + ); + }), + ], + + publicRooms.length > 0 && [ + m('.rooms-section-title', [ + m('i.fas.fa-globe'), + m('span', 'Public (' + publicRooms.length + ')'), + ]), + publicRooms.map((info) => { + const hexId = rs.idToHex(info.lobby_id); + const count = info.total_number_of_peers || 0; + return m( + '.chat-room-list-item.public-room' + + (isSelected(info, 'public') ? '.selected' : ''), + { + key: hexId, + onclick: () => { + m.route.set('/chat/:lobby', { lobby: hexId }); + }, + }, + [ + m('.room-icon', m('i.fas.fa-globe')), + m('.room-meta', [ + m('.room-name', info.lobby_name || ''), + m('.room-topic', info.lobby_topic || 'No topic'), + ]), + count > 0 && m('.room-badge', count), + ] + ); + }), + ], + + subscribedRooms.length === 0 && + publicRooms.length === 0 && + m('p.no-rooms', 'No chat rooms found'), + ]), + ]), + ]), + + m('.chat-hub-right-pane', [ + ChatHubState.selectedRoom + ? [ + ChatHubState.selectedRoomType === 'subscribed' + ? [ + m(ChatRoomHeader, { room: ChatHubState.selectedRoom }), + m('.chat-hub-tabs-container', [ + m('.chat-hub-tabs', [ + m( + 'button.tab-btn' + + (ChatHubState.activeTab === 'chat' ? '.active' : ''), + { + onclick: () => { + ChatHubState.activeTab = 'chat'; + scrollChatToBottom(); + }, + }, + [m('i.fas.fa-comments'), ' Chat'] + ), + m( + 'button.tab-btn' + + (ChatHubState.activeTab === 'details' ? '.active' : ''), + { + onclick: () => { + ChatHubState.activeTab = 'details'; + }, + }, + [m('i.fas.fa-info-circle'), ' Details'] + ), + ]), + ]), + m('.chat-hub-tab-content', { style: { padding: ChatHubState.activeTab === 'chat' ? '0' : '1.5rem' } }, [ + ChatHubState.activeTab === 'chat' + ? m(ChatConversationView) + : m(ChatRoomDetailView), + ]), + ] + : [ + m('.chat-hub-tab-content', m(ChatRoomJoinView)), + ], + ] + : m('.chat-pane-placeholder', [ + m('i.fas.fa-comments'), + m( + 'p', + 'Select a chat room from the left panel to view details or join a conversation.' + ), + ]), + ]), + ]); + }, }; const LayoutSingle = () => { @@ -681,10 +1046,7 @@ const LayoutSingle = () => { }, [ m('.chat-overlay', { onclick: () => MobileState.closeAll() }), - LobbyName(), - !isPrivate && m('.lobbies', m(SubscribedLeftLobbies), m(PublicLeftLobbies)), m('.messages', { onclick: () => MobileState.closeAll() }, ChatLobbyModel.messages), - m('.rightbar', ChatLobbyModel.users), m( '.chatMessage', {}, @@ -723,40 +1085,6 @@ const LayoutSingle = () => { }; }; -const LayoutSetup = () => { - let ownIds = []; - return { - oninit: () => peopleUtil.ownIds((data) => (ownIds = data)), - view: (vnode) => - m( - '.node-panel.chat-panel.chat-room.chat-setup', - { - class: - (MobileState.showLobbies ? 'show-lobbies ' : '') + - (MobileState.showUsers ? 'show-users' : ''), - }, - [ - m('.chat-overlay', { onclick: () => MobileState.closeAll() }), - LobbyName(), - m('.lobbies', m(SubscribedLeftLobbies), m(PublicLeftLobbies)), - m('.setup', [ - m('h5.selectidentity', 'Select identity to use'), - ownIds.map((nick) => - m( - '.identity' + - (ChatLobbyModel.currentLobby.gxs_id === nick ? '.selectedidentity' : ''), - { - onclick: () => ChatLobbyModel.setupAction(m.route.param('lobby'), nick), - }, - rs.userList.username(nick) - ) - ), - ]), - ] - ), - }; -}; - /* /rsChats/initiateDistantChatConnexion * @param[in] to_pid RsGxsId to start the connection @@ -802,16 +1130,13 @@ const LayoutCreateDistant = () => { module.exports = { oninit: () => { ChatRoomsModel.loadSubscribedRooms(); + loadOwnChatProfile(); }, view: (vnode) => { - if (m.route.param('lobby') === undefined) { - return m(Layout); - } else if (m.route.param('subaction') === 'setup') { - return m(LayoutSetup); - } else if (m.route.param('subaction') === 'createdistantchat') { + if (m.route.param('subaction') === 'createdistantchat') { return m(LayoutCreateDistant); } else { - return m(LayoutSingle); + return m(Layout); } }, }; diff --git a/webui-src/app/scss/pages/_chat.scss b/webui-src/app/scss/pages/_chat.scss index 84293e5..9f7958e 100644 --- a/webui-src/app/scss/pages/_chat.scss +++ b/webui-src/app/scss/pages/_chat.scss @@ -1,346 +1,1067 @@ -@use '../abstracts' as *; - -.lobby { - margin: 10px; - border: 1px solid #aaa; - border-radius: 20px; -} - -.lobby .mainname { - margin: 20px; - font-weight: 100; - font-size: 1.2em; -} - -.topic { - color: #666; -} - -.lobby>.topic { - font-size: 0.95em; - margin-left: 25px; - margin-bottom: 5px; -} - -.lefttitle { - margin-top: 15px; - margin-bottom: 0; - font-weight: 100; - font-size: 1.2em; -} - -.leftname { - margin-top: 5px; - margin-bottom: 5px; - padding: 5px; - font-weight: 100; - font-size: 1em; -} - -.leftlobby>.topic { - font-size: 0.75em; - margin-left: 15px; - margin-bottom: 5px; -} - -.subscribed, -.public { - cursor: pointer; -} - -.leftlobby { - border: 1px solid #aaa; - border-radius: 10px; - margin-top: 5px; - background-color: white; -} - -.leftlobby.selected-lobby, -.selectedidentity { - color: white; - background-color: #3ba4d7; -} - -.rightbar { - position: absolute; - width: 185px; - background-color: white; - overflow: auto; - top: 130px; - bottom: 15px; - right: 15px; -} - -.user { - padding: 5px; -} - -.lobbyName { - padding: 15px; - margin-top: 2rem; -} - -.lobbies { - position: absolute; - width: 185px; - left: 165px; - bottom: 15px; - top: 130px; - overflow: auto; -} - -.messages, -.setup { - position: absolute; - background-color: white; - top: 130px; - left: 360px; - right: 215px; - overflow: auto; -} - -.messages { - bottom: 115px; -} - -.messagetext { - white-space: break-spaces; - margin-right: 5px; -} - -.message>* { - margin-left: 5px; -} - -.username { - color: darkgreen; - font-weight: bolder; -} - -.chatMessage { - position: absolute; - background-color: white; - height: 85px; - bottom: 15px; - right: 215px; - left: 360px; -} - -textarea.chatMsg { - height: 100%; - width: 100%; -} - -.chatatchar { - margin-left: 0.2em; - margin-right: 0.2em; - color: silver; -} - -.setupicon { - margin-left: 1em; - cursor: pointer; -} - -.leaveicon { - margin-left: 1em; - cursor: pointer; - color: #d40000; -} - -.selectidentity { - margin: 15px; - font-size: 1.2em; -} - -.setup>.identity { - cursor: pointer; -} - -.setup { - bottom: 15px; -} - -.createDistantChat { - margin-top: 1em; -} - -.no-lobbies { - - .messages, - .chatMessage, - .setup { - left: 165px; - } -} - -/* CHAT ROOM (Single Chat) - Desktop Grid Layout */ -@media (min-width: 900px) { - .node-panel.chat-room { - display: grid !important; - grid-template-columns: 250px 1fr 200px !important; - /* Lobbies, Chat, Users */ - grid-template-rows: auto 1fr auto !important; - /* Header, Messages, Input */ - grid-template-areas: - "lobbies header rightbar" - "lobbies messages rightbar" - "lobbies input rightbar" !important; - padding: 0 !important; - height: 100% !important; - } - - .node-panel.chat-room .lobbyName { - grid-area: header; - padding: 10px; - border-bottom: 1px solid #eee; - margin: 0; - z-index: 10; - background: white; - } - - .node-panel.chat-room .lobbies { - grid-area: lobbies; - position: static !important; - width: auto !important; - height: auto !important; - border-right: 1px solid #ccc; - overflow-y: auto; - display: block !important; - top: auto !important; - bottom: auto !important; - left: auto !important; - } - - .node-panel.chat-room .messages { - grid-area: messages; - position: static !important; - width: auto !important; - height: auto !important; - overflow-y: auto; - padding: 10px; - left: auto !important; - right: auto !important; - top: auto !important; - bottom: auto !important; - margin: 0 !important; - } - - .node-panel.chat-room .rightbar { - grid-area: rightbar; - position: static !important; - width: auto !important; - border-left: 1px solid #ccc; - overflow-y: auto; - display: block !important; - } - - .node-panel.chat-room .chatMessage { - grid-area: input; - position: static !important; - width: auto !important; - height: auto !important; - border-top: 1px solid #eee; - left: auto !important; - right: auto !important; - bottom: auto !important; - flex: 0 0 auto; - padding: 10px !important; - background: white; - z-index: 10; - } -} - -/* Mobile Overrides - Ensure Flex Column */ -@media (max-width: 899px) { - .node-panel.chat-room { - display: flex !important; - flex-direction: column !important; - height: 100% !important; - position: relative !important; - } - - .node-panel.chat-room .lobbyName { - flex: 0 0 auto; - } - - .node-panel.chat-room .messages { - flex: 1 !important; - overflow-y: auto !important; - position: relative !important; - top: 0 !important; - bottom: 0 !important; - left: 0 !important; - right: 0 !important; - width: 100% !important; - height: auto !important; - margin: 0 !important; - } - - .node-panel.chat-room .chatMessage { - flex: 0 0 auto !important; - position: relative !important; - bottom: 0 !important; - left: 0 !important; - right: 0 !important; - width: 100% !important; - height: auto !important; - z-index: 100; - } - - .node-panel.chat-room .rightbar, - .node-panel.chat-room .lobbies { - display: none !important; - position: fixed !important; - top: 60px !important; - bottom: 0 !important; - width: 80% !important; - background: white !important; - z-index: 200 !important; - box-shadow: 2px 0 10px rgba(0, 0, 0, 0.2) !important; - } - - .node-panel.chat-room.show-lobbies .lobbies { - display: block !important; - left: 0 !important; - } - - .node-panel.chat-room.show-users .rightbar { - display: block !important; - right: 0 !important; - } - - .chat-overlay { - display: none; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.4); - z-index: 150; - } - - .show-lobbies .chat-overlay, - .show-users .chat-overlay { - display: block; - } - - /* Mobile Icons in Header */ - .mobile-menu-icons { - display: flex; - gap: 15px; - font-size: 1.2rem; - } - - .mobile-menu-icons i { - cursor: pointer; - padding: 5px; - } -} - -@media (min-width: 900px) { - .mobile-menu-icons { - display: none; - } -} \ No newline at end of file +@use '../abstracts' as *; + +.lobby { + margin: 10px; + border: 1px solid #aaa; + border-radius: 20px; +} + +.lobby .mainname { + margin: 20px; + font-weight: 100; + font-size: 1.2em; +} + +.topic { + color: #666; +} + +.lobby>.topic { + font-size: 0.95em; + margin-left: 25px; + margin-bottom: 5px; +} + +.lefttitle { + margin-top: 15px; + margin-bottom: 0; + font-weight: 100; + font-size: 1.2em; +} + +.leftname { + margin-top: 5px; + margin-bottom: 5px; + padding: 5px; + font-weight: 100; + font-size: 1em; +} + +.leftlobby>.topic { + font-size: 0.75em; + margin-left: 15px; + margin-bottom: 5px; +} + +.subscribed, +.public { + cursor: pointer; +} + +.leftlobby { + border: 1px solid #aaa; + border-radius: 10px; + margin-top: 5px; + background-color: white; +} + +.leftlobby.selected-lobby, +.selectedidentity { + color: white; + background-color: #3ba4d7; +} + +.rightbar { + position: absolute; + width: 185px; + background-color: white; + overflow: auto; + top: 130px; + bottom: 15px; + right: 15px; +} + +.user { + padding: 5px; +} + +.lobbyName { + padding: 15px; + margin-top: 2rem; +} + +.lobbies { + position: absolute; + width: 185px; + left: 165px; + bottom: 15px; + top: 130px; + overflow: auto; +} + +.messages, +.setup { + position: absolute; + background-color: white; + top: 130px; + left: 360px; + right: 215px; + overflow: auto; +} + +.messages { + bottom: 115px; +} + +.messagetext { + white-space: break-spaces; + margin-right: 5px; +} + +.message>* { + margin-left: 5px; +} + +.username { + color: darkgreen; + font-weight: bolder; +} + +.chatMessage { + position: absolute; + background-color: white; + height: 85px; + bottom: 15px; + right: 215px; + left: 360px; +} + +textarea.chatMsg { + height: 100%; + width: 100%; +} + +.chatatchar { + margin-left: 0.2em; + margin-right: 0.2em; + color: silver; +} + +.setupicon { + margin-left: 1em; + cursor: pointer; +} + +.leaveicon { + margin-left: 1em; + cursor: pointer; + color: #d40000; +} + +.selectidentity { + margin: 15px; + font-size: 1.2em; +} + +.setup>.identity { + cursor: pointer; +} + +.setup { + bottom: 15px; +} + +.createDistantChat { + margin-top: 1em; +} + +.no-lobbies { + + .messages, + .chatMessage, + .setup { + left: 165px; + } +} + +/* CHAT ROOM (Single Chat) - Desktop Grid Layout */ +@media (min-width: 900px) { + .node-panel.chat-room { + display: grid !important; + grid-template-columns: 250px 1fr 200px !important; + /* Lobbies, Chat, Users */ + grid-template-rows: auto 1fr auto !important; + /* Header, Messages, Input */ + grid-template-areas: + "lobbies header rightbar" + "lobbies messages rightbar" + "lobbies input rightbar" !important; + padding: 0 !important; + height: 100% !important; + } + + .node-panel.chat-room .lobbyName { + grid-area: header; + padding: 10px; + border-bottom: 1px solid #eee; + margin: 0; + z-index: 10; + background: white; + } + + .node-panel.chat-room .lobbies { + grid-area: lobbies; + position: static !important; + width: auto !important; + height: auto !important; + border-right: 1px solid #ccc; + overflow-y: auto; + display: block !important; + top: auto !important; + bottom: auto !important; + left: auto !important; + } + + .node-panel.chat-room .messages { + grid-area: messages; + position: static !important; + width: auto !important; + height: auto !important; + overflow-y: auto; + padding: 10px; + left: auto !important; + right: auto !important; + top: auto !important; + bottom: auto !important; + margin: 0 !important; + } + + .node-panel.chat-room .rightbar { + grid-area: rightbar; + position: static !important; + width: auto !important; + border-left: 1px solid #ccc; + overflow-y: auto; + display: block !important; + } + + .node-panel.chat-room .chatMessage { + grid-area: input; + position: static !important; + width: auto !important; + height: auto !important; + border-top: 1px solid #eee; + left: auto !important; + right: auto !important; + bottom: auto !important; + flex: 0 0 auto; + padding: 10px !important; + background: white; + z-index: 10; + } +} + +/* Mobile Overrides - Ensure Flex Column */ +@media (max-width: 899px) { + .node-panel.chat-room { + display: flex !important; + flex-direction: column !important; + height: 100% !important; + position: relative !important; + } + + .node-panel.chat-room .lobbyName { + flex: 0 0 auto; + } + + .node-panel.chat-room .messages { + flex: 1 !important; + overflow-y: auto !important; + position: relative !important; + top: 0 !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + width: 100% !important; + height: auto !important; + margin: 0 !important; + } + + .node-panel.chat-room .chatMessage { + flex: 0 0 auto !important; + position: relative !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + width: 100% !important; + height: auto !important; + z-index: 100; + } + + .node-panel.chat-room .rightbar, + .node-panel.chat-room .lobbies { + display: none !important; + position: fixed !important; + top: 60px !important; + bottom: 0 !important; + width: 80% !important; + background: white !important; + z-index: 200 !important; + box-shadow: 2px 0 10px rgba(0, 0, 0, 0.2) !important; + } + + .node-panel.chat-room.show-lobbies .lobbies { + display: block !important; + left: 0 !important; + } + + .node-panel.chat-room.show-users .rightbar { + display: block !important; + right: 0 !important; + } + + .chat-overlay { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.4); + z-index: 150; + } + + .show-lobbies .chat-overlay, + .show-users .chat-overlay { + display: block; + } + + /* Mobile Icons in Header */ + .mobile-menu-icons { + display: flex; + gap: 15px; + font-size: 1.2rem; + } + + .mobile-menu-icons i { + cursor: pointer; + padding: 5px; + } +} + +@media (min-width: 900px) { + .mobile-menu-icons { + display: none; + } +} + +/* ===================================================== + CHAT HUB - Two-Pane Layout (matching Network page) + ===================================================== */ + +.chat-hub-container { + display: flex; + height: 100%; + width: 100%; + overflow: hidden; + background-color: #f1f5f9; +} + +.chat-hub-left-pane { + width: 320px; + min-width: 300px; + max-width: 350px; + border-right: 1px solid #cbd5e1; + display: flex; + flex-direction: column; + background: #ffffff; + box-shadow: 2px 0 5px rgba(0, 0, 0, 0.05); +} + +.chat-own-profile-card { + padding: 1.25rem; + border-bottom: 1px solid #e2e8f0; + background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); + + .profile-header { + display: flex; + align-items: center; + gap: 1rem; + } + + .profile-info { + display: flex; + flex-direction: column; + flex: 1; + overflow: hidden; + + .profile-name { + font-weight: 700; + color: #1e293b; + font-size: 1.1rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .profile-status { + font-size: 0.85rem; + color: #10b981; + font-weight: 500; + display: flex; + align-items: center; + gap: 0.35rem; + + &::before { + content: ''; + display: inline-block; + width: 8px; + height: 8px; + background-color: #10b981; + border-radius: 50%; + } + } + } +} + +.chat-rooms-list-container { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; + + .searchbar-container { + padding: 0.75rem 1rem; + border-bottom: 1px solid #e2e8f0; + + input.searchbar { + width: 100%; + padding: 0.5rem 0.75rem; + font-size: 0.9rem; + border: 1px solid #cbd5e1; + border-radius: 0.375rem; + background-color: #f8fafc; + outline: none; + transition: all 0.2s; + + &:focus { + background-color: #ffffff; + border-color: #3ba4d7; + box-shadow: 0 0 0 3px rgba(59, 164, 215, 0.15); + } + } + } + + .rooms-scroll { + flex: 1; + overflow-y: auto; + padding: 0.5rem 0; + } +} + +.rooms-section-title { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.75rem 1rem 0.375rem; + font-size: 0.75rem; + font-weight: 700; + color: #64748b; + text-transform: uppercase; + letter-spacing: 0.05em; + + i { + font-size: 0.7rem; + color: #94a3b8; + } +} + +.chat-room-list-item { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.75rem 1rem; + margin: 0.125rem 0.5rem; + border-radius: 0.5rem; + cursor: pointer; + transition: all 0.2s; + + &:hover { + background-color: #f1f5f9; + } + + &.selected { + background-color: #e0f2fe; + + .room-name { + color: #0369a1; + font-weight: 600; + } + } + + .room-icon { + flex-shrink: 0; + width: 36px; + height: 36px; + border-radius: 0.5rem; + background: linear-gradient(135deg, #3ba4d7, #0ea5e9); + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + font-size: 0.85rem; + } + + &.public-room .room-icon { + background: linear-gradient(135deg, #10b981, #059669); + } + + .room-meta { + flex: 1; + min-width: 0; + + .room-name { + font-size: 0.95rem; + color: #334155; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transition: color 0.2s; + } + + .room-topic { + font-size: 0.8rem; + color: #94a3b8; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + + .room-badge { + flex-shrink: 0; + min-width: 24px; + height: 24px; + border-radius: 12px; + background-color: #e2e8f0; + color: #475569; + font-size: 0.75rem; + font-weight: 700; + display: flex; + align-items: center; + justify-content: center; + padding: 0 0.375rem; + } +} + +.chat-hub-right-pane { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; + background-color: #f8fafc; +} + +.chat-pane-placeholder { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: #94a3b8; + gap: 1rem; + padding: 2rem; + text-align: center; + + i { + font-size: 4rem; + color: #cbd5e1; + } + + p { + font-size: 1.1rem; + max-width: 400px; + } +} + +.chat-hub-tab-content { + flex: 1; + overflow-y: auto; + padding: 1.5rem; +} + +.chat-room-detail-view { + display: flex; + flex-direction: column; + gap: 1.5rem; + + .detail-header { + display: flex; + align-items: flex-start; + gap: 1.5rem; + padding-bottom: 1.5rem; + border-bottom: 1px solid #e2e8f0; + flex-wrap: wrap; + + .detail-title { + flex: 1; + min-width: 200px; + + h2 { + font-size: 1.75rem; + font-weight: 800; + color: #1e293b; + margin-bottom: 0.25rem; + } + + .detail-subtitle { + font-size: 0.9rem; + color: #64748b; + display: flex; + align-items: center; + gap: 0.5rem; + } + } + + .detail-actions { + display: flex; + gap: 0.75rem; + flex-wrap: wrap; + + button { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + font-size: 0.9rem; + } + } + } + + .detail-section { + background-color: #ffffff; + border-radius: 0.5rem; + border: 1px solid #e2e8f0; + padding: 1.25rem; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02); + + h3 { + font-size: 1.1rem; + font-weight: 700; + color: #334155; + margin-bottom: 1rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid #f1f5f9; + } + + .info-grid { + display: grid; + grid-template-columns: 130px 1fr; + row-gap: 0.75rem; + font-size: 0.9rem; + + .info-label { + font-weight: 600; + color: #64748b; + } + + .info-value { + color: #1e293b; + word-break: break-all; + } + } + } +} + +.participants-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); + gap: 0.5rem; +} + +.participant-card { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 0.75rem; + background-color: #f8fafc; + border: 1px solid #e2e8f0; + border-radius: 0.375rem; + + .participant-name { + font-size: 0.875rem; + color: #334155; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +} + +.no-participants { + color: #94a3b8; + font-size: 0.9rem; + font-style: italic; +} + +.detail-actions-footer { + display: flex; + gap: 0.75rem; + + button { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + font-size: 0.9rem; + } +} + +.join-description { + color: #64748b; + font-size: 0.9rem; + margin-bottom: 1rem; +} + +.identities-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 0.75rem; +} + +.identity-card { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.75rem 1rem; + background-color: #f8fafc; + border: 1px solid #e2e8f0; + border-radius: 0.5rem; + cursor: pointer; + transition: all 0.2s; + + &:hover { + background-color: #e0f2fe; + border-color: #3ba4d7; + } + + .identity-name { + font-size: 0.95rem; + font-weight: 600; + color: #334155; + } + + i { + color: #3ba4d7; + font-size: 0.9rem; + } +} + +.no-rooms { + padding: 1rem; + color: #94a3b8; + text-align: center; + font-style: italic; +} + +/* Chat Hub Responsive - Mobile */ +@media (max-width: 899px) { + .chat-hub-container { + flex-direction: column; + } + + .chat-hub-left-pane { + width: 100%; + min-width: 0; + max-width: none; + max-height: 45%; + border-right: none; + border-bottom: 1px solid #cbd5e1; + } + + .chat-hub-right-pane { + flex: 1; + min-height: 0; + } +} + +/* ===================================================== + CHAT HUB - Right Pane Conversation & Tabs Styling + ===================================================== */ + +.chat-hub-header-bar { + padding: 0.75rem 1.5rem; + background-color: #ffffff; + border-bottom: 1px solid #e2e8f0; + display: flex; + align-items: center; + justify-content: space-between; + height: 65px; + flex-shrink: 0; +} + +.chat-hub-header-bar .chat-header-info { + display: flex; + flex-direction: column; + overflow: hidden; +} + +.chat-hub-header-bar .chat-header-info .chat-header-name { + font-size: 1.15rem; + font-weight: 800; + color: #1e293b; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.chat-hub-header-bar .chat-header-info .chat-header-topic { + font-size: 0.85rem; + color: #64748b; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-top: 0.125rem; +} + +.chat-hub-header-bar .chat-header-actions { + display: flex; + gap: 0.5rem; +} + +.chat-hub-header-bar .chat-header-actions button { + display: flex; + align-items: center; + gap: 0.35rem; + padding: 0.375rem 0.75rem; + font-size: 0.85rem; +} + +.chat-hub-tabs-container { + background-color: #ffffff; + border-bottom: 1px solid #cbd5e1; + padding: 0.5rem 1.5rem 0; +} + +.chat-hub-tabs { + display: flex; + gap: 0.5rem; +} + +.chat-hub-tabs .tab-btn { + padding: 0.625rem 1.25rem; + font-size: 0.95rem; + font-weight: 600; + color: #64748b; + background: transparent; + border: none; + border-radius: 0.375rem 0.375rem 0 0; + border-bottom: 3px solid transparent; + cursor: pointer; + box-shadow: none; + transition: all 0.2s; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.chat-hub-tabs .tab-btn:hover { + color: #334155; + background-color: #f1f5f9; +} + +.chat-hub-tabs .tab-btn.active { + color: #3ba4d7; + border-bottom-color: #3ba4d7; + background-color: transparent; +} + +.chat-hub-tab-content { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; + background-color: #f8fafc; +} + +.chat-hub-conversation-layout { + display: flex; + flex-direction: row; + height: 100%; + width: 100%; + overflow: hidden; +} + +.chat-hub-conversation-main { + display: flex; + flex-direction: column; + flex: 1; + height: 100%; + overflow: hidden; +} + +.chat-hub-rightbar { + width: 200px; + border-left: 1px solid #cbd5e1; + background-color: #ffffff; + display: flex; + flex-direction: column; + flex-shrink: 0; +} + +.chat-hub-rightbar .rightbar-title { + padding: 0.75rem 1rem; + font-size: 0.85rem; + font-weight: 700; + color: #64748b; + text-transform: uppercase; + letter-spacing: 0.05em; + border-bottom: 1px solid #e2e8f0; +} + +.chat-hub-rightbar .rightbar-users-list { + flex: 1; + overflow-y: auto; + padding: 0.5rem; +} + +.chat-hub-rightbar .user { + padding: 0.5rem 0.75rem; + font-size: 0.9rem; + color: #334155; + border-radius: 0.375rem; + transition: all 0.2s; + display: flex; + align-items: center; + gap: 0.5rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.chat-hub-rightbar .user:hover { + background-color: #f1f5f9; + color: #0f172a; +} + +.chat-hub-rightbar .user .defaultAvatar { + width: 2rem; + height: 2rem; + font-size: 0.9rem; + flex-shrink: 0; +} + +.chat-hub-rightbar .user img.avatar { + width: 2rem; + height: 2rem; + flex-shrink: 0; +} + +@media (max-width: 899px) { + .chat-hub-rightbar { + display: none; + } +} + +.chat-hub-messages { + flex: 1; + overflow-y: auto; + padding: 1.25rem 1.5rem; + display: flex; + flex-direction: column; + gap: 1rem; +} + +/* Chat bubble overrides for two-pane layout */ +.chat-hub-messages .message { + display: flex; + flex-direction: column; + max-width: 70%; + padding: 0.625rem 0.875rem; + border-radius: 0.75rem; + font-size: 0.925rem; + line-height: 1.4; + word-break: break-word; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.chat-hub-messages .message.incoming { + align-self: flex-start; + align-items: flex-start; + background-color: #ffffff; + color: #1e293b; + border: 1px solid #e2e8f0; + border-bottom-left-radius: 0.125rem; +} + +.chat-hub-messages .message.outgoing { + align-self: flex-end; + align-items: flex-end; + background-color: #3ba4d7; + color: #ffffff; + border-bottom-right-radius: 0.125rem; +} + +.chat-hub-messages .message .username { + font-size: 0.75rem; + margin-bottom: 0.25rem; + padding: 0 0.125rem; + font-weight: 700; +} + +.chat-hub-messages .message.incoming .username { + color: #0369a1; +} + +.chat-hub-messages .message.outgoing .username { + color: #e0f2fe; +} + +.chat-hub-messages .message .messagetext { + white-space: break-spaces; + margin: 0; +} + +.chat-hub-messages .message .datetime { + font-size: 0.7rem; + margin-top: 0.25rem; + padding: 0 0.125rem; + opacity: 0.8; +} + +.chat-hub-messages .message.incoming .datetime { + color: #64748b; +} + +.chat-hub-messages .message.outgoing .datetime { + color: #f1f5f9; +} + +.chat-hub-input-area { + padding: 1rem 1.5rem; + background-color: #ffffff; + border-top: 1px solid #cbd5e1; + display: flex; + gap: 0.75rem; + align-items: center; + flex-shrink: 0; +} + +.chat-hub-input-area textarea.chat-hub-textarea { + flex: 1; + resize: none; + height: 40px; + padding: 0.5rem 0.75rem; + border: 1px solid #cbd5e1; + border-radius: 0.375rem; + font-size: 0.9rem; + outline: none; + transition: all 0.2s; + background-color: #f8fafc; +} + +.chat-hub-input-area textarea.chat-hub-textarea:focus { + background-color: #ffffff; + border-color: #3ba4d7; + box-shadow: 0 0 0 3px rgba(59, 164, 215, 0.15); +} + +.chat-hub-input-area button.chat-hub-send-btn { + padding: 0.5rem 1.25rem; + font-size: 0.9rem; + height: 40px; + display: flex; + align-items: center; + gap: 0.5rem; + border-radius: 0.375rem; +} + \ No newline at end of file diff --git a/webui-src/styles.css b/webui-src/styles.css index d7f2c37..acb0af8 100644 --- a/webui-src/styles.css +++ b/webui-src/styles.css @@ -623,3 +623,725 @@ h1{font-size:3rem}h2{font-size:2.25rem}h3{font-size:1.875rem}h4{font-size:1.5rem font-weight: 600; font-size: 0.9rem; } + +/* ===================================================== + CHAT HUB - Two-Pane Layout + ===================================================== */ + +.chat-hub-container { + display: flex; + height: 100%; + width: 100%; + overflow: hidden; + background-color: #f1f5f9; +} + +.chat-hub-left-pane { + width: 320px; + min-width: 300px; + max-width: 350px; + border-right: 1px solid #cbd5e1; + display: flex; + flex-direction: column; + background: #ffffff; + box-shadow: 2px 0 5px rgba(0, 0, 0, 0.05); +} + +.chat-own-profile-card { + padding: 1.25rem; + border-bottom: 1px solid #e2e8f0; + background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); +} + +.chat-own-profile-card .profile-header { + display: flex; + align-items: center; + gap: 1rem; +} + +.chat-own-profile-card .profile-info { + display: flex; + flex-direction: column; + flex: 1; + overflow: hidden; +} + +.chat-own-profile-card .profile-info .profile-name { + font-weight: 700; + color: #1e293b; + font-size: 1.1rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.chat-own-profile-card .profile-info .profile-status { + font-size: 0.85rem; + color: #10b981; + font-weight: 500; + display: flex; + align-items: center; + gap: 0.35rem; +} + +.chat-own-profile-card .profile-info .profile-status::before { + content: ''; + display: inline-block; + width: 8px; + height: 8px; + background-color: #10b981; + border-radius: 50%; +} + +.chat-rooms-list-container { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.chat-rooms-list-container .searchbar-container { + padding: 0.75rem 1rem; + border-bottom: 1px solid #e2e8f0; +} + +.chat-rooms-list-container .searchbar-container input.searchbar { + width: 100%; + padding: 0.5rem 0.75rem; + font-size: 0.9rem; + border: 1px solid #cbd5e1; + border-radius: 0.375rem; + background-color: #f8fafc; + outline: none; + transition: all 0.2s; +} + +.chat-rooms-list-container .searchbar-container input.searchbar:focus { + background-color: #ffffff; + border-color: #3ba4d7; + box-shadow: 0 0 0 3px rgba(59, 164, 215, 0.15); +} + +.chat-rooms-list-container .rooms-scroll { + flex: 1; + overflow-y: auto; + padding: 0.5rem 0; +} + +.rooms-section-title { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.75rem 1rem 0.375rem; + font-size: 0.75rem; + font-weight: 700; + color: #64748b; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.rooms-section-title i { + font-size: 0.7rem; + color: #94a3b8; +} + +.chat-room-list-item { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.75rem 1rem; + margin: 0.125rem 0.5rem; + border-radius: 0.5rem; + cursor: pointer; + transition: all 0.2s; +} + +.chat-room-list-item:hover { + background-color: #f1f5f9; +} + +.chat-room-list-item.selected { + background-color: #e0f2fe; +} + +.chat-room-list-item.selected .room-meta .room-name { + color: #0369a1; + font-weight: 600; +} + +.chat-room-list-item .room-icon { + flex-shrink: 0; + width: 36px; + height: 36px; + border-radius: 0.5rem; + background: linear-gradient(135deg, #3ba4d7, #0ea5e9); + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + font-size: 0.85rem; +} + +.chat-room-list-item.public-room .room-icon { + background: linear-gradient(135deg, #10b981, #059669); +} + +.chat-room-list-item .room-meta { + flex: 1; + min-width: 0; +} + +.chat-room-list-item .room-meta .room-name { + font-size: 0.95rem; + color: #334155; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transition: color 0.2s; +} + +.chat-room-list-item .room-meta .room-topic { + font-size: 0.8rem; + color: #94a3b8; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.chat-room-list-item .room-badge { + flex-shrink: 0; + min-width: 24px; + height: 24px; + border-radius: 12px; + background-color: #e2e8f0; + color: #475569; + font-size: 0.75rem; + font-weight: 700; + display: flex; + align-items: center; + justify-content: center; + padding: 0 0.375rem; +} + +.chat-hub-right-pane { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; + background-color: #f8fafc; +} + +.chat-pane-placeholder { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: #94a3b8; + gap: 1rem; + padding: 2rem; + text-align: center; +} + +.chat-pane-placeholder i { + font-size: 4rem; + color: #cbd5e1; +} + +.chat-pane-placeholder p { + font-size: 1.1rem; + max-width: 400px; +} + +.chat-hub-tab-content { + flex: 1; + overflow-y: auto; + padding: 1.5rem; +} + +.chat-room-detail-view { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.chat-room-detail-view .detail-header { + display: flex; + align-items: flex-start; + gap: 1.5rem; + padding-bottom: 1.5rem; + border-bottom: 1px solid #e2e8f0; + flex-wrap: wrap; +} + +.chat-room-detail-view .detail-header .detail-title { + flex: 1; + min-width: 200px; +} + +.chat-room-detail-view .detail-header .detail-title h2 { + font-size: 1.75rem; + font-weight: 800; + color: #1e293b; + margin-bottom: 0.25rem; +} + +.chat-room-detail-view .detail-header .detail-title .detail-subtitle { + font-size: 0.9rem; + color: #64748b; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.chat-room-detail-view .detail-header .detail-actions { + display: flex; + gap: 0.75rem; + flex-wrap: wrap; +} + +.chat-room-detail-view .detail-header .detail-actions button { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + font-size: 0.9rem; +} + +.chat-room-detail-view .detail-section { + background-color: #ffffff; + border-radius: 0.5rem; + border: 1px solid #e2e8f0; + padding: 1.25rem; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02); +} + +.chat-room-detail-view .detail-section h3 { + font-size: 1.1rem; + font-weight: 700; + color: #334155; + margin-bottom: 1rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid #f1f5f9; +} + +.chat-room-detail-view .detail-section .info-grid { + display: grid; + grid-template-columns: 130px 1fr; + row-gap: 0.75rem; + font-size: 0.9rem; +} + +.chat-room-detail-view .detail-section .info-grid .info-label { + font-weight: 600; + color: #64748b; +} + +.chat-room-detail-view .detail-section .info-grid .info-value { + color: #1e293b; + word-break: break-all; +} + +.participants-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); + gap: 0.5rem; +} + +.participant-card { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 0.75rem; + background-color: #f8fafc; + border: 1px solid #e2e8f0; + border-radius: 0.375rem; +} + +.participant-card .participant-name { + font-size: 0.875rem; + color: #334155; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.no-participants { + color: #94a3b8; + font-size: 0.9rem; + font-style: italic; +} + +.detail-actions-footer { + display: flex; + gap: 0.75rem; +} + +.detail-actions-footer button { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + font-size: 0.9rem; +} + +.join-description { + color: #64748b; + font-size: 0.9rem; + margin-bottom: 1rem; +} + +.identities-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 0.75rem; +} + +.identity-card { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.75rem 1rem; + background-color: #f8fafc; + border: 1px solid #e2e8f0; + border-radius: 0.5rem; + cursor: pointer; + transition: all 0.2s; +} + +.identity-card:hover { + background-color: #e0f2fe; + border-color: #3ba4d7; +} + +.identity-card .identity-name { + font-size: 0.95rem; + font-weight: 600; + color: #334155; +} + +.identity-card i { + color: #3ba4d7; + font-size: 0.9rem; +} + +.no-rooms { + padding: 1rem; + color: #94a3b8; + text-align: center; + font-style: italic; +} + +/* Chat Hub Responsive - Mobile */ +@media (max-width: 899px) { + .chat-hub-container { + flex-direction: column; + } + + .chat-hub-left-pane { + width: 100%; + min-width: 0; + max-width: none; + max-height: 45%; + border-right: none; + border-bottom: 1px solid #cbd5e1; + } + + .chat-hub-right-pane { + flex: 1; + min-height: 0; + } +} + +/* ===================================================== + CHAT HUB - Right Pane Conversation & Tabs Styling + ===================================================== */ + +.chat-hub-header-bar { + padding: 0.75rem 1.5rem; + background-color: #ffffff; + border-bottom: 1px solid #e2e8f0; + display: flex; + align-items: center; + justify-content: space-between; + height: 65px; + flex-shrink: 0; +} + +.chat-hub-header-bar .chat-header-info { + display: flex; + flex-direction: column; + overflow: hidden; +} + +.chat-hub-header-bar .chat-header-info .chat-header-name { + font-size: 1.15rem; + font-weight: 800; + color: #1e293b; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.chat-hub-header-bar .chat-header-info .chat-header-topic { + font-size: 0.85rem; + color: #64748b; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-top: 0.125rem; +} + +.chat-hub-header-bar .chat-header-actions { + display: flex; + gap: 0.5rem; +} + +.chat-hub-header-bar .chat-header-actions button { + display: flex; + align-items: center; + gap: 0.35rem; + padding: 0.375rem 0.75rem; + font-size: 0.85rem; +} + +.chat-hub-tabs-container { + background-color: #ffffff; + border-bottom: 1px solid #cbd5e1; + padding: 0.5rem 1.5rem 0; +} + +.chat-hub-tabs { + display: flex; + gap: 0.5rem; +} + +.chat-hub-tabs .tab-btn { + padding: 0.625rem 1.25rem; + font-size: 0.95rem; + font-weight: 600; + color: #64748b; + background: transparent; + border: none; + border-radius: 0.375rem 0.375rem 0 0; + border-bottom: 3px solid transparent; + cursor: pointer; + box-shadow: none; + transition: all 0.2s; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.chat-hub-tabs .tab-btn:hover { + color: #334155; + background-color: #f1f5f9; +} + +.chat-hub-tabs .tab-btn.active { + color: #3ba4d7; + border-bottom-color: #3ba4d7; + background-color: transparent; +} + +.chat-hub-tab-content { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; + background-color: #f8fafc; +} + +.chat-hub-conversation-layout { + display: flex; + flex-direction: row; + height: 100%; + width: 100%; + overflow: hidden; +} + +.chat-hub-conversation-main { + display: flex; + flex-direction: column; + flex: 1; + height: 100%; + overflow: hidden; +} + +.chat-hub-rightbar { + width: 200px; + border-left: 1px solid #cbd5e1; + background-color: #ffffff; + display: flex; + flex-direction: column; + flex-shrink: 0; +} + +.chat-hub-rightbar .rightbar-title { + padding: 0.75rem 1rem; + font-size: 0.85rem; + font-weight: 700; + color: #64748b; + text-transform: uppercase; + letter-spacing: 0.05em; + border-bottom: 1px solid #e2e8f0; +} + +.chat-hub-rightbar .rightbar-users-list { + flex: 1; + overflow-y: auto; + padding: 0.5rem; +} + +.chat-hub-rightbar .user { + padding: 0.5rem 0.75rem; + font-size: 0.9rem; + color: #334155; + border-radius: 0.375rem; + transition: all 0.2s; + display: flex; + align-items: center; + gap: 0.5rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.chat-hub-rightbar .user:hover { + background-color: #f1f5f9; + color: #0f172a; +} + +.chat-hub-rightbar .user .defaultAvatar { + width: 2rem; + height: 2rem; + font-size: 0.9rem; + flex-shrink: 0; +} + +.chat-hub-rightbar .user img.avatar { + width: 2rem; + height: 2rem; + flex-shrink: 0; +} + +@media (max-width: 899px) { + .chat-hub-rightbar { + display: none; + } +} + +.chat-hub-messages { + flex: 1; + overflow-y: auto; + padding: 1.25rem 1.5rem; + display: flex; + flex-direction: column; + gap: 1rem; +} + +/* Chat bubble overrides for two-pane layout */ +.chat-hub-messages .message { + display: flex; + flex-direction: column; + max-width: 70%; + padding: 0.625rem 0.875rem; + border-radius: 0.75rem; + font-size: 0.925rem; + line-height: 1.4; + word-break: break-word; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.chat-hub-messages .message.incoming { + align-self: flex-start; + align-items: flex-start; + background-color: #ffffff; + color: #1e293b; + border: 1px solid #e2e8f0; + border-bottom-left-radius: 0.125rem; +} + +.chat-hub-messages .message.outgoing { + align-self: flex-end; + align-items: flex-end; + background-color: #3ba4d7; + color: #ffffff; + border-bottom-right-radius: 0.125rem; +} + +.chat-hub-messages .message .username { + font-size: 0.75rem; + margin-bottom: 0.25rem; + padding: 0 0.125rem; + font-weight: 700; +} + +.chat-hub-messages .message.incoming .username { + color: #0369a1; +} + +.chat-hub-messages .message.outgoing .username { + color: #e0f2fe; +} + +.chat-hub-messages .message .messagetext { + white-space: break-spaces; + margin: 0; +} + +.chat-hub-messages .message .datetime { + font-size: 0.7rem; + margin-top: 0.25rem; + padding: 0 0.125rem; + opacity: 0.8; +} + +.chat-hub-messages .message.incoming .datetime { + color: #64748b; +} + +.chat-hub-messages .message.outgoing .datetime { + color: #f1f5f9; +} + +.chat-hub-input-area { + padding: 1rem 1.5rem; + background-color: #ffffff; + border-top: 1px solid #cbd5e1; + display: flex; + gap: 0.75rem; + align-items: center; + flex-shrink: 0; +} + +.chat-hub-input-area textarea.chat-hub-textarea { + flex: 1; + resize: none; + height: 40px; + padding: 0.5rem 0.75rem; + border: 1px solid #cbd5e1; + border-radius: 0.375rem; + font-size: 0.9rem; + outline: none; + transition: all 0.2s; + background-color: #f8fafc; +} + +.chat-hub-input-area textarea.chat-hub-textarea:focus { + background-color: #ffffff; + border-color: #3ba4d7; + box-shadow: 0 0 0 3px rgba(59, 164, 215, 0.15); +} + +.chat-hub-input-area button.chat-hub-send-btn { + padding: 0.5rem 1.25rem; + font-size: 0.9rem; + height: 40px; + display: flex; + align-items: center; + gap: 0.5rem; + border-radius: 0.375rem; +} + +