mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-12 19:50:04 +05:00
Redesign Chat rooms
This commit is contained in:
parent
320886a10d
commit
4ddbf1ee2a
@ -192,7 +192,7 @@ const Message = () => {
|
||||
.replaceAll('<br/>', '\n')
|
||||
.replace(new RegExp('<style[^<]*</style>|<[^>]*>', '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 || '<unnamed>'),
|
||||
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 || '<unnamed>'),
|
||||
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 || '<unnamed>'),
|
||||
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 || '<unnamed>'),
|
||||
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 || '<unnamed>'),
|
||||
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);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user