Spaces:
Runtime error
Runtime error
feat: Comprehensive mobile adaptive layout, clickable member profiles, enhanced communities/groups, fixed QR modal
Browse files- client.js +70 -10
- index.html +166 -7
client.js
CHANGED
|
@@ -1047,6 +1047,8 @@ function updateMembersList(users) {
|
|
| 1047 |
users.forEach(user => {
|
| 1048 |
const item = document.createElement('div');
|
| 1049 |
item.className = 'member-item';
|
|
|
|
|
|
|
| 1050 |
|
| 1051 |
// Create avatar
|
| 1052 |
const avatar = document.createElement('div');
|
|
@@ -1065,6 +1067,15 @@ function updateMembersList(users) {
|
|
| 1065 |
const name = document.createElement('span');
|
| 1066 |
name.textContent = user.username;
|
| 1067 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1068 |
item.appendChild(avatar);
|
| 1069 |
item.appendChild(status);
|
| 1070 |
item.appendChild(name);
|
|
@@ -1804,11 +1815,36 @@ function applySettingsToUI() {
|
|
| 1804 |
function openCommunitiesModal() {
|
| 1805 |
const modal = document.getElementById('communitiesModal');
|
| 1806 |
const list = document.getElementById('communitiesList');
|
| 1807 |
-
|
| 1808 |
-
|
| 1809 |
-
|
| 1810 |
-
|
| 1811 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1812 |
modal.classList.remove('hidden');
|
| 1813 |
}
|
| 1814 |
|
|
@@ -1819,11 +1855,35 @@ function closeCommunitiesModal() {
|
|
| 1819 |
function openGroupsModal() {
|
| 1820 |
const modal = document.getElementById('groupsModal');
|
| 1821 |
const list = document.getElementById('groupsList');
|
| 1822 |
-
|
| 1823 |
-
|
| 1824 |
-
|
| 1825 |
-
|
| 1826 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1827 |
modal.classList.remove('hidden');
|
| 1828 |
}
|
| 1829 |
|
|
|
|
| 1047 |
users.forEach(user => {
|
| 1048 |
const item = document.createElement('div');
|
| 1049 |
item.className = 'member-item';
|
| 1050 |
+
item.style.cursor = 'pointer';
|
| 1051 |
+
item.title = `Click to view ${user.username}'s profile`;
|
| 1052 |
|
| 1053 |
// Create avatar
|
| 1054 |
const avatar = document.createElement('div');
|
|
|
|
| 1067 |
const name = document.createElement('span');
|
| 1068 |
name.textContent = user.username;
|
| 1069 |
|
| 1070 |
+
// Make item clickable to view profile
|
| 1071 |
+
item.onclick = () => {
|
| 1072 |
+
if (user.id === currentUser.id) {
|
| 1073 |
+
openProfile();
|
| 1074 |
+
} else {
|
| 1075 |
+
visitUserProfile(user.id, user.username);
|
| 1076 |
+
}
|
| 1077 |
+
};
|
| 1078 |
+
|
| 1079 |
item.appendChild(avatar);
|
| 1080 |
item.appendChild(status);
|
| 1081 |
item.appendChild(name);
|
|
|
|
| 1815 |
function openCommunitiesModal() {
|
| 1816 |
const modal = document.getElementById('communitiesModal');
|
| 1817 |
const list = document.getElementById('communitiesList');
|
| 1818 |
+
|
| 1819 |
+
// Show communities with better styling
|
| 1820 |
+
const communities = [
|
| 1821 |
+
{ name: 'Gaming', emoji: '🎮', description: 'Talk about your favorite games' },
|
| 1822 |
+
{ name: 'Coding', emoji: '💻', description: 'Share code and learn together' },
|
| 1823 |
+
{ name: 'Music', emoji: '🎵', description: 'Discuss and share music' },
|
| 1824 |
+
{ name: 'Art', emoji: '🎨', description: 'Share your creative works' },
|
| 1825 |
+
{ name: 'Sports', emoji: '⚽', description: 'Sports fans unite' },
|
| 1826 |
+
{ name: 'Movies', emoji: '🎬', description: 'Film enthusiasts' }
|
| 1827 |
+
];
|
| 1828 |
+
|
| 1829 |
+
list.innerHTML = communities.map(c => {
|
| 1830 |
+
const isJoined = joinedCommunities.includes(c.name);
|
| 1831 |
+
return `
|
| 1832 |
+
<div class="friend-item" style="flex-direction: column; align-items: flex-start; padding: 16px;">
|
| 1833 |
+
<div style="display: flex; width: 100%; justify-content: space-between; align-items: center;">
|
| 1834 |
+
<div>
|
| 1835 |
+
<span class="friend-name" style="font-size: 16px;">${c.emoji} ${c.name}</span>
|
| 1836 |
+
<div style="font-size: 12px; color: var(--text-secondary); margin-top: 4px;">${c.description}</div>
|
| 1837 |
+
</div>
|
| 1838 |
+
<button class="buy-btn"
|
| 1839 |
+
onclick="${isJoined ? `openCommunityChat('${c.name}'); closeCommunitiesModal();` : `joinCommunity('${c.name}')`}"
|
| 1840 |
+
style="${isJoined ? 'background: var(--success);' : ''}">
|
| 1841 |
+
${isJoined ? 'Open' : 'Join'}
|
| 1842 |
+
</button>
|
| 1843 |
+
</div>
|
| 1844 |
+
</div>
|
| 1845 |
+
`;
|
| 1846 |
+
}).join('');
|
| 1847 |
+
|
| 1848 |
modal.classList.remove('hidden');
|
| 1849 |
}
|
| 1850 |
|
|
|
|
| 1855 |
function openGroupsModal() {
|
| 1856 |
const modal = document.getElementById('groupsModal');
|
| 1857 |
const list = document.getElementById('groupsList');
|
| 1858 |
+
|
| 1859 |
+
// Show groups with better styling
|
| 1860 |
+
const groups = [
|
| 1861 |
+
{ name: 'Study Group', emoji: '📚', description: 'Study together and share notes' },
|
| 1862 |
+
{ name: 'Project Team', emoji: '💼', description: 'Collaborate on projects' },
|
| 1863 |
+
{ name: 'Family', emoji: '👨👩👧', description: 'Family group chat' },
|
| 1864 |
+
{ name: 'Friends', emoji: '🎉', description: 'Hang out with friends' },
|
| 1865 |
+
{ name: 'Work', emoji: '🏢', description: 'Work related discussions' }
|
| 1866 |
+
];
|
| 1867 |
+
|
| 1868 |
+
list.innerHTML = groups.map(g => {
|
| 1869 |
+
const isJoined = joinedGroups.includes(g.name);
|
| 1870 |
+
return `
|
| 1871 |
+
<div class="friend-item" style="flex-direction: column; align-items: flex-start; padding: 16px;">
|
| 1872 |
+
<div style="display: flex; width: 100%; justify-content: space-between; align-items: center;">
|
| 1873 |
+
<div>
|
| 1874 |
+
<span class="friend-name" style="font-size: 16px;">${g.emoji} ${g.name}</span>
|
| 1875 |
+
<div style="font-size: 12px; color: var(--text-secondary); margin-top: 4px;">${g.description}</div>
|
| 1876 |
+
</div>
|
| 1877 |
+
<button class="buy-btn"
|
| 1878 |
+
onclick="${isJoined ? `openGroupChat('${g.name}'); closeGroupsModal();` : `joinGroup('${g.name}')`}"
|
| 1879 |
+
style="${isJoined ? 'background: var(--success);' : ''}">
|
| 1880 |
+
${isJoined ? 'Open' : 'Join'}
|
| 1881 |
+
</button>
|
| 1882 |
+
</div>
|
| 1883 |
+
</div>
|
| 1884 |
+
`;
|
| 1885 |
+
}).join('');
|
| 1886 |
+
|
| 1887 |
modal.classList.remove('hidden');
|
| 1888 |
}
|
| 1889 |
|
index.html
CHANGED
|
@@ -1395,29 +1395,167 @@
|
|
| 1395 |
}
|
| 1396 |
}
|
| 1397 |
|
|
|
|
| 1398 |
@media (max-width: 768px) {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1399 |
.main-container {
|
| 1400 |
-
grid-template-columns:
|
|
|
|
|
|
|
|
|
|
| 1401 |
}
|
| 1402 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1403 |
.channel-sidebar {
|
| 1404 |
display: none;
|
| 1405 |
position: fixed;
|
| 1406 |
-
left:
|
| 1407 |
top: 0;
|
| 1408 |
-
width:
|
|
|
|
| 1409 |
height: 100%;
|
|
|
|
| 1410 |
z-index: 999;
|
|
|
|
| 1411 |
}
|
| 1412 |
|
| 1413 |
.channel-sidebar.show {
|
| 1414 |
display: flex;
|
| 1415 |
}
|
| 1416 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1417 |
.picker-panel {
|
| 1418 |
-
width:
|
| 1419 |
-
left:
|
| 1420 |
-
bottom:
|
|
|
|
|
|
|
| 1421 |
}
|
| 1422 |
|
| 1423 |
.voice-recorder {
|
|
@@ -1427,6 +1565,12 @@
|
|
| 1427 |
bottom: 80px;
|
| 1428 |
}
|
| 1429 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1430 |
.settings-panel {
|
| 1431 |
width: 100%;
|
| 1432 |
right: -100%;
|
|
@@ -1452,6 +1596,8 @@
|
|
| 1452 |
white-space: nowrap;
|
| 1453 |
border-left: none;
|
| 1454 |
border-bottom: 3px solid transparent;
|
|
|
|
|
|
|
| 1455 |
}
|
| 1456 |
|
| 1457 |
.settings-nav-item.active {
|
|
@@ -1459,6 +1605,7 @@
|
|
| 1459 |
border-bottom-color: var(--primary-color);
|
| 1460 |
}
|
| 1461 |
|
|
|
|
| 1462 |
.toast-container {
|
| 1463 |
top: 10px;
|
| 1464 |
right: 10px;
|
|
@@ -1467,6 +1614,17 @@
|
|
| 1467 |
|
| 1468 |
.toast {
|
| 1469 |
min-width: auto;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1470 |
}
|
| 1471 |
}
|
| 1472 |
|
|
@@ -1937,7 +2095,7 @@
|
|
| 1937 |
<button onclick="showArchivedChats()" title="Archived Chats" style="padding: 4px 8px; background: var(--secondary-color); border: none; border-radius: 4px; color: var(--text-primary); cursor: pointer; font-size: 12px;">
|
| 1938 |
<i class="fas fa-archive"></i>
|
| 1939 |
</button>
|
| 1940 |
-
<button onclick="toggleChannelSidebar()"><i class="fas fa-times"></i></button>
|
| 1941 |
</div>
|
| 1942 |
</div>
|
| 1943 |
<div class="friend-search-container">
|
|
@@ -2381,6 +2539,7 @@
|
|
| 2381 |
</div>
|
| 2382 |
|
| 2383 |
<!-- COMMUNITIES MODAL -->
|
|
|
|
| 2384 |
<div class="modal-content">
|
| 2385 |
<h2><i class="fas fa-globe"></i> Communities</h2>
|
| 2386 |
<p style="margin-top: 10px; color: var(--text-secondary);">Join public communities to discover people with shared interests.</p>
|
|
|
|
| 1395 |
}
|
| 1396 |
}
|
| 1397 |
|
| 1398 |
+
/* ==================== MOBILE ADAPTIVE LAYOUT ==================== */
|
| 1399 |
@media (max-width: 768px) {
|
| 1400 |
+
body {
|
| 1401 |
+
overflow: hidden;
|
| 1402 |
+
}
|
| 1403 |
+
|
| 1404 |
.main-container {
|
| 1405 |
+
grid-template-columns: 60px 1fr;
|
| 1406 |
+
height: 100vh;
|
| 1407 |
+
height: 100dvh;
|
| 1408 |
+
max-height: -webkit-fill-available;
|
| 1409 |
}
|
| 1410 |
|
| 1411 |
+
/* Mobile Guild Sidebar */
|
| 1412 |
+
.guild-sidebar {
|
| 1413 |
+
padding: 4px 0;
|
| 1414 |
+
}
|
| 1415 |
+
|
| 1416 |
+
.guild-item {
|
| 1417 |
+
width: 48px;
|
| 1418 |
+
height: 48px;
|
| 1419 |
+
font-size: 20px;
|
| 1420 |
+
margin-bottom: 6px;
|
| 1421 |
+
}
|
| 1422 |
+
|
| 1423 |
+
.guild-divider {
|
| 1424 |
+
width: 28px;
|
| 1425 |
+
margin: 6px 0;
|
| 1426 |
+
}
|
| 1427 |
+
|
| 1428 |
+
/* Mobile Channel Sidebar */
|
| 1429 |
.channel-sidebar {
|
| 1430 |
display: none;
|
| 1431 |
position: fixed;
|
| 1432 |
+
left: 0;
|
| 1433 |
top: 0;
|
| 1434 |
+
width: 85%;
|
| 1435 |
+
max-width: 320px;
|
| 1436 |
height: 100%;
|
| 1437 |
+
height: 100dvh;
|
| 1438 |
z-index: 999;
|
| 1439 |
+
box-shadow: 4px 0 20px rgba(0,0,0,0.5);
|
| 1440 |
}
|
| 1441 |
|
| 1442 |
.channel-sidebar.show {
|
| 1443 |
display: flex;
|
| 1444 |
}
|
| 1445 |
|
| 1446 |
+
/* Mobile overlay for sidebar */
|
| 1447 |
+
.channel-sidebar.show::before {
|
| 1448 |
+
content: '';
|
| 1449 |
+
position: fixed;
|
| 1450 |
+
left: 0;
|
| 1451 |
+
top: 0;
|
| 1452 |
+
width: 100vw;
|
| 1453 |
+
height: 100vh;
|
| 1454 |
+
background: rgba(0,0,0,0.5);
|
| 1455 |
+
z-index: -1;
|
| 1456 |
+
}
|
| 1457 |
+
|
| 1458 |
+
/* Mobile Chat Area */
|
| 1459 |
+
.chat-area {
|
| 1460 |
+
height: 100vh;
|
| 1461 |
+
height: 100dvh;
|
| 1462 |
+
max-height: -webkit-fill-available;
|
| 1463 |
+
}
|
| 1464 |
+
|
| 1465 |
+
.chat-header {
|
| 1466 |
+
padding: 12px 16px;
|
| 1467 |
+
flex-shrink: 0;
|
| 1468 |
+
}
|
| 1469 |
+
|
| 1470 |
+
.chat-header-title {
|
| 1471 |
+
font-size: 16px;
|
| 1472 |
+
}
|
| 1473 |
+
|
| 1474 |
+
.build-badge {
|
| 1475 |
+
display: none;
|
| 1476 |
+
}
|
| 1477 |
+
|
| 1478 |
+
.header-btn {
|
| 1479 |
+
font-size: 16px;
|
| 1480 |
+
padding: 8px;
|
| 1481 |
+
}
|
| 1482 |
+
|
| 1483 |
+
.chat-header-actions {
|
| 1484 |
+
gap: 4px;
|
| 1485 |
+
}
|
| 1486 |
+
|
| 1487 |
+
/* Mobile Messages Container */
|
| 1488 |
+
#messages-container {
|
| 1489 |
+
flex: 1;
|
| 1490 |
+
min-height: 0;
|
| 1491 |
+
max-height: none;
|
| 1492 |
+
padding: 12px 16px;
|
| 1493 |
+
padding-bottom: 16px;
|
| 1494 |
+
-webkit-overflow-scrolling: touch;
|
| 1495 |
+
overscroll-behavior: contain;
|
| 1496 |
+
}
|
| 1497 |
+
|
| 1498 |
+
.message {
|
| 1499 |
+
gap: 8px;
|
| 1500 |
+
}
|
| 1501 |
+
|
| 1502 |
+
.message-avatar {
|
| 1503 |
+
width: 36px;
|
| 1504 |
+
height: 36px;
|
| 1505 |
+
font-size: 16px;
|
| 1506 |
+
}
|
| 1507 |
+
|
| 1508 |
+
.message-username {
|
| 1509 |
+
font-size: 14px;
|
| 1510 |
+
}
|
| 1511 |
+
|
| 1512 |
+
.message-text {
|
| 1513 |
+
font-size: 14px;
|
| 1514 |
+
}
|
| 1515 |
+
|
| 1516 |
+
.message-media {
|
| 1517 |
+
max-width: 90%;
|
| 1518 |
+
}
|
| 1519 |
+
|
| 1520 |
+
/* Mobile Input Area */
|
| 1521 |
+
.input-area {
|
| 1522 |
+
padding: 12px 16px;
|
| 1523 |
+
gap: 8px;
|
| 1524 |
+
flex-shrink: 0;
|
| 1525 |
+
border-top: 2px solid var(--border-color);
|
| 1526 |
+
}
|
| 1527 |
+
|
| 1528 |
+
.input-area input {
|
| 1529 |
+
font-size: 16px;
|
| 1530 |
+
padding: 10px 14px;
|
| 1531 |
+
}
|
| 1532 |
+
|
| 1533 |
+
.input-btn {
|
| 1534 |
+
width: 40px;
|
| 1535 |
+
height: 40px;
|
| 1536 |
+
font-size: 16px;
|
| 1537 |
+
flex-shrink: 0;
|
| 1538 |
+
}
|
| 1539 |
+
|
| 1540 |
+
/* Mobile Scroll Rail */
|
| 1541 |
+
.chat-scroll-rail {
|
| 1542 |
+
right: 4px;
|
| 1543 |
+
top: 64px;
|
| 1544 |
+
bottom: 74px;
|
| 1545 |
+
width: 12px;
|
| 1546 |
+
}
|
| 1547 |
+
|
| 1548 |
+
.chat-scroll-thumb {
|
| 1549 |
+
min-height: 40px;
|
| 1550 |
+
}
|
| 1551 |
+
|
| 1552 |
+
/* Mobile Panels */
|
| 1553 |
.picker-panel {
|
| 1554 |
+
width: 100%;
|
| 1555 |
+
left: 0;
|
| 1556 |
+
bottom: 0;
|
| 1557 |
+
height: 50vh;
|
| 1558 |
+
border-radius: 16px 16px 0 0;
|
| 1559 |
}
|
| 1560 |
|
| 1561 |
.voice-recorder {
|
|
|
|
| 1565 |
bottom: 80px;
|
| 1566 |
}
|
| 1567 |
|
| 1568 |
+
.draft-preview {
|
| 1569 |
+
margin: 8px 16px 0;
|
| 1570 |
+
padding: 8px;
|
| 1571 |
+
}
|
| 1572 |
+
|
| 1573 |
+
/* Mobile Settings Panel */
|
| 1574 |
.settings-panel {
|
| 1575 |
width: 100%;
|
| 1576 |
right: -100%;
|
|
|
|
| 1596 |
white-space: nowrap;
|
| 1597 |
border-left: none;
|
| 1598 |
border-bottom: 3px solid transparent;
|
| 1599 |
+
font-size: 13px;
|
| 1600 |
+
padding: 10px 14px;
|
| 1601 |
}
|
| 1602 |
|
| 1603 |
.settings-nav-item.active {
|
|
|
|
| 1605 |
border-bottom-color: var(--primary-color);
|
| 1606 |
}
|
| 1607 |
|
| 1608 |
+
/* Mobile Toasts */
|
| 1609 |
.toast-container {
|
| 1610 |
top: 10px;
|
| 1611 |
right: 10px;
|
|
|
|
| 1614 |
|
| 1615 |
.toast {
|
| 1616 |
min-width: auto;
|
| 1617 |
+
padding: 12px 16px;
|
| 1618 |
+
}
|
| 1619 |
+
|
| 1620 |
+
/* Mobile Profile Panel */
|
| 1621 |
+
.profile-panel {
|
| 1622 |
+
width: 100%;
|
| 1623 |
+
}
|
| 1624 |
+
|
| 1625 |
+
/* Hide members sidebar completely on mobile */
|
| 1626 |
+
.members-sidebar {
|
| 1627 |
+
display: none !important;
|
| 1628 |
}
|
| 1629 |
}
|
| 1630 |
|
|
|
|
| 2095 |
<button onclick="showArchivedChats()" title="Archived Chats" style="padding: 4px 8px; background: var(--secondary-color); border: none; border-radius: 4px; color: var(--text-primary); cursor: pointer; font-size: 12px;">
|
| 2096 |
<i class="fas fa-archive"></i>
|
| 2097 |
</button>
|
| 2098 |
+
<button onclick="toggleChannelSidebar()" class="danger-hover" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; font-size: 20px; padding: 4px 8px;"><i class="fas fa-times"></i></button>
|
| 2099 |
</div>
|
| 2100 |
</div>
|
| 2101 |
<div class="friend-search-container">
|
|
|
|
| 2539 |
</div>
|
| 2540 |
|
| 2541 |
<!-- COMMUNITIES MODAL -->
|
| 2542 |
+
<div class="modal hidden" id="communitiesModal">
|
| 2543 |
<div class="modal-content">
|
| 2544 |
<h2><i class="fas fa-globe"></i> Communities</h2>
|
| 2545 |
<p style="margin-top: 10px; color: var(--text-secondary);">Join public communities to discover people with shared interests.</p>
|