v0.11.20 UI updates
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jama-backend",
|
"name": "jama-backend",
|
||||||
"version": "0.11.19",
|
"version": "0.11.20",
|
||||||
"description": "TeamChat backend server",
|
"description": "TeamChat backend server",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
2
build.sh
2
build.sh
@@ -13,7 +13,7 @@
|
|||||||
# ─────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
VERSION="${1:-0.11.19}"
|
VERSION="${1:-0.11.20}"
|
||||||
ACTION="${2:-}"
|
ACTION="${2:-}"
|
||||||
REGISTRY="${REGISTRY:-}"
|
REGISTRY="${REGISTRY:-}"
|
||||||
IMAGE_NAME="jama"
|
IMAGE_NAME="jama"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jama-frontend",
|
"name": "jama-frontend",
|
||||||
"version": "0.11.19",
|
"version": "0.11.20",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ import { useSocket } from '../contexts/SocketContext.jsx';
|
|||||||
import './ChatWindow.css';
|
import './ChatWindow.css';
|
||||||
import GroupInfoModal from './GroupInfoModal.jsx';
|
import GroupInfoModal from './GroupInfoModal.jsx';
|
||||||
|
|
||||||
|
// Must match Avatar.jsx and Sidebar.jsx exactly so header colours are consistent with message avatars
|
||||||
|
const AVATAR_COLORS = ['#1a73e8','#ea4335','#34a853','#fa7b17','#a142f4','#00897b','#e91e8c','#0097a7'];
|
||||||
|
function nameToColor(name) {
|
||||||
|
return AVATAR_COLORS[(name || '').charCodeAt(0) % AVATAR_COLORS.length];
|
||||||
|
}
|
||||||
|
|
||||||
export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMessage, onMessageDeleted, onlineUserIds = new Set() }) {
|
export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMessage, onMessageDeleted, onlineUserIds = new Set() }) {
|
||||||
const { user: currentUser } = useAuth();
|
const { user: currentUser } = useAuth();
|
||||||
const { socket } = useSocket();
|
const { socket } = useSocket();
|
||||||
@@ -237,13 +243,21 @@ export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMess
|
|||||||
<img src={group.peer_avatar} alt={group.name} className="group-icon-sm" style={{ objectFit: 'cover', padding: 0 }} />
|
<img src={group.peer_avatar} alt={group.name} className="group-icon-sm" style={{ objectFit: 'cover', padding: 0 }} />
|
||||||
{isOnline && <span className="online-dot" style={{ position: 'absolute', bottom: 1, right: 1 }} />}
|
{isOnline && <span className="online-dot" style={{ position: 'absolute', bottom: 1, right: 1 }} />}
|
||||||
</div>
|
</div>
|
||||||
|
) : isDirect && !group.is_managed ? (
|
||||||
|
// No custom avatar — use same per-user colour as Avatar.jsx and Sidebar.jsx
|
||||||
|
<div style={{ position: 'relative', flexShrink: 0 }}>
|
||||||
|
<div className="group-icon-sm" style={{ background: nameToColor(group.peer_real_name || group.name), flexShrink: 0 }}>
|
||||||
|
{(group.peer_real_name || group.name)[0]?.toUpperCase()}
|
||||||
|
</div>
|
||||||
|
{isOnline && <span className="online-dot" style={{ position: 'absolute', bottom: 1, right: 1 }} />}
|
||||||
|
</div>
|
||||||
) : group.is_managed ? (
|
) : group.is_managed ? (
|
||||||
<div className="group-icon-sm" style={{ background: avatarColors.dm, borderRadius: 8, flexShrink: 0, fontSize: 11, fontWeight: 700 }}>
|
<div className="group-icon-sm" style={{ background: avatarColors.dm, borderRadius: 8, flexShrink: 0, fontSize: 11, fontWeight: 700 }}>
|
||||||
{group.is_multi_group ? 'MG' : 'UG'}
|
{group.is_multi_group ? 'MG' : 'UG'}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="group-icon-sm" style={{ background: group.type === 'public' ? avatarColors.public : avatarColors.dm, flexShrink: 0 }}>
|
<div className="group-icon-sm" style={{ background: group.type === 'public' ? avatarColors.public : avatarColors.dm, flexShrink: 0 }}>
|
||||||
{group.type === 'public' ? '#' : isDirect ? (group.peer_real_name || group.name)[0]?.toUpperCase() : group.name[0]?.toUpperCase()}
|
{group.type === 'public' ? '#' : group.name[0]?.toUpperCase()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ export default function Sidebar({ groups, activeGroupId, onSelectGroup, notifica
|
|||||||
return (
|
return (
|
||||||
<div className="sidebar">
|
<div className="sidebar">
|
||||||
<div className="sidebar-newchat-bar">
|
<div className="sidebar-newchat-bar">
|
||||||
{!isMobile && !groupMessagesMode && (
|
{!isMobile && (
|
||||||
<button className="newchat-btn" onClick={onNewChat}>
|
<button className="newchat-btn" onClick={onNewChat}>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" width="18" height="18">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" width="18" height="18">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 0 1 .865-.501 48.172 48.172 0 0 0 3.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 0 1 .865-.501 48.172 48.172 0 0 0 3.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z" />
|
||||||
@@ -180,7 +180,7 @@ export default function Sidebar({ groups, activeGroupId, onSelectGroup, notifica
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isMobile && !groupMessagesMode && (
|
{isMobile && (
|
||||||
<button className="newchat-fab" onClick={onNewChat} title="New Chat">
|
<button className="newchat-fab" onClick={onNewChat} title="New Chat">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" width="24" height="24">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" width="24" height="24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 0 1 .865-.501 48.172 48.172 0 0 0 3.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 0 1 .865-.501 48.172 48.172 0 0 0 3.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z" />
|
||||||
|
|||||||
@@ -433,6 +433,7 @@ export default function Chat() {
|
|||||||
onSelectGroup={selectGroup}
|
onSelectGroup={selectGroup}
|
||||||
notifications={notifications}
|
notifications={notifications}
|
||||||
unreadGroups={unreadGroups}
|
unreadGroups={unreadGroups}
|
||||||
|
onNewChat={() => setModal('newchat')}
|
||||||
onProfile={() => setModal('profile')}
|
onProfile={() => setModal('profile')}
|
||||||
onUsers={() => setPage('users')}
|
onUsers={() => setPage('users')}
|
||||||
onSettings={() => setModal('settings')}
|
onSettings={() => setModal('settings')}
|
||||||
@@ -472,6 +473,7 @@ export default function Chat() {
|
|||||||
{modal === 'branding' && <BrandingModal onClose={() => setModal(null)} />}
|
{modal === 'branding' && <BrandingModal onClose={() => setModal(null)} />}
|
||||||
{modal === 'help' && <HelpModal onClose={() => setModal(null)} dismissed={helpDismissed} />}
|
{modal === 'help' && <HelpModal onClose={() => setModal(null)} dismissed={helpDismissed} />}
|
||||||
{modal === 'about' && <AboutModal onClose={() => setModal(null)} />}
|
{modal === 'about' && <AboutModal onClose={() => setModal(null)} />}
|
||||||
|
{modal === 'newchat' && <NewChatModal onClose={() => setModal(null)} onCreated={(g) => { loadGroups(); setModal(null); setActiveGroupId(g.id); setPage('chat'); }} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user