feat: Add initial frontend components and their corresponding build assets, along with generated API types and configuration.
Some checks failed
Build and Release / build-and-release (push) Failing after 7m50s

This commit is contained in:
Bryan1029384756
2026-02-11 06:24:33 -06:00
parent cb4361da1a
commit c472f0ee2d
369 changed files with 1423 additions and 395 deletions

View File

@@ -187,7 +187,7 @@ const UserControlPanel = ({ username, userId }) => {
)}
<div className="user-control-info" onClick={() => setShowStatusMenu(!showStatusMenu)}>
<div style={{ position: 'relative', marginRight: '8px' }}>
<Avatar username={username} size={32} />
<Avatar username={username} avatarUrl={myUser?.avatarUrl} size={32} />
<div style={{
position: 'absolute',
bottom: '-2px',
@@ -235,15 +235,6 @@ const UserControlPanel = ({ username, userId }) => {
/>
</button>
</Tooltip>
<Tooltip text="Log Out" position="top">
<button style={controlButtonStyle} onClick={handleLogout}>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
<path d="M16 17L21 12L16 7" stroke={ICON_COLOR_DEFAULT} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M21 12H9" stroke={ICON_COLOR_DEFAULT} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M9 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V5C3 4.46957 3.21071 3.96086 3.58579 3.58579C3.96086 3.21071 4.46957 3 5 3H9" stroke={ICON_COLOR_DEFAULT} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</button>
</Tooltip>
</div>
{showUserSettings && (
<UserSettings
@@ -356,6 +347,32 @@ const Sidebar = ({ channels, activeChannel, onSelectChannel, username, channelKe
const convex = useConvex();
// Unread tracking
const channelIds = React.useMemo(() => channels.map(c => c._id), [channels]);
const allReadStates = useQuery(
api.readState.getAllReadStates,
userId ? { userId } : "skip"
) || [];
const latestTimestamps = useQuery(
api.readState.getLatestMessageTimestamps,
channelIds.length > 0 ? { channelIds } : "skip"
) || [];
const unreadChannels = React.useMemo(() => {
const set = new Set();
const readMap = new Map();
for (const rs of allReadStates) {
readMap.set(rs.channelId, rs.lastReadTimestamp);
}
for (const lt of latestTimestamps) {
const lastRead = readMap.get(lt.channelId);
if (lastRead === undefined || lt.latestTimestamp > lastRead) {
set.add(lt.channelId);
}
}
return set;
}, [allReadStates, latestTimestamps]);
const onRenameChannel = () => {};
const onDeleteChannel = (id) => {
@@ -610,7 +627,9 @@ const Sidebar = ({ channels, activeChannel, onSelectChannel, username, channelKe
+
</button>
</div>
{!collapsedCategories[category] && catChannels.map(channel => (
{!collapsedCategories[category] && catChannels.map(channel => {
const isUnread = activeChannel !== channel._id && unreadChannels.has(channel._id);
return (
<React.Fragment key={channel._id}>
<div
className={`channel-item ${activeChannel === channel._id ? 'active' : ''} ${voiceChannelId === channel._id ? 'voice-active' : ''}`}
@@ -623,6 +642,7 @@ const Sidebar = ({ channels, activeChannel, onSelectChannel, username, channelKe
paddingRight: '8px'
}}
>
{isUnread && <div className="channel-unread-indicator" />}
<div style={{ display: 'flex', alignItems: 'center', overflow: 'hidden', flex: 1 }}>
{channel.type === 'voice' ? (
<div style={{ marginRight: 6 }}>
@@ -635,7 +655,7 @@ const Sidebar = ({ channels, activeChannel, onSelectChannel, username, channelKe
) : (
<span style={{ color: 'var(--interactive-normal)', marginRight: '6px', flexShrink: 0 }}>#</span>
)}
<span style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{channel.name}</span>
<span style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', ...(isUnread ? { color: 'var(--header-primary)', fontWeight: 600 } : {}) }}>{channel.name}</span>
</div>
<button
@@ -661,7 +681,8 @@ const Sidebar = ({ channels, activeChannel, onSelectChannel, username, channelKe
</div>
{renderVoiceUsers(channel)}
</React.Fragment>
))}
);
})}
</div>
))}
</div>