3f33859f4a
Frontend: - Settings link in header next to logout - [+] button to create server (name + optional icon) - [#] button to join server via invite code - [+] button to create channel (name, type, category) - Server name shown instead of UUID in channel list header - /invites/:code route wired for JoinServer component Backend: - Wire role CRUD + member-role assignment routes (MANAGE_SERVER gated) - Seed @everyone default role on server creation
76 lines
2.9 KiB
TypeScript
76 lines
2.9 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { useServerStore } from '../stores/server.ts';
|
|
import { useChannelStore } from '../stores/channel.ts';
|
|
import { CreateServerModal } from './CreateServerModal.tsx';
|
|
import { JoinServerModal } from './JoinServerModal.tsx';
|
|
|
|
function getInitials(name: string): string {
|
|
const words = name.trim().split(/\s+/);
|
|
if (words.length === 1) {
|
|
return words[0].slice(0, 2).toUpperCase();
|
|
}
|
|
return (words[0][0] + words[words.length - 1][0]).toUpperCase();
|
|
}
|
|
|
|
export function ServerBar() {
|
|
const servers = useServerStore((state) => state.servers);
|
|
const activeServerId = useServerStore((state) => state.activeServerId);
|
|
const fetchServers = useServerStore((state) => state.fetchServers);
|
|
const setActiveServer = useServerStore((state) => state.setActiveServer);
|
|
const setActiveChannel = useChannelStore((state) => state.setActiveChannel);
|
|
const [showCreate, setShowCreate] = useState(false);
|
|
const [showJoin, setShowJoin] = useState(false);
|
|
|
|
useEffect(() => {
|
|
fetchServers();
|
|
}, [fetchServers]);
|
|
|
|
const handleSelect = (id: string) => {
|
|
setActiveServer(id);
|
|
setActiveChannel(null);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div className="h-full w-16 bg-gb-bg-h border-r border-gb-bg-t flex flex-col items-center py-3 gap-2 overflow-y-auto">
|
|
{servers.map((server) => (
|
|
<button
|
|
key={server.id}
|
|
onClick={() => handleSelect(server.id)}
|
|
className={`w-11 h-11 flex items-center justify-center font-mono text-sm border ${
|
|
server.id === activeServerId
|
|
? 'bg-gb-bg-t text-gb-orange border-gb-orange'
|
|
: 'bg-gb-bg-s text-gb-fg border-gb-bg-t hover:border-gb-fg-t hover:text-gb-aqua'
|
|
}`}
|
|
title={server.name}
|
|
>
|
|
{server.unread && server.id !== activeServerId ? (
|
|
<span className="text-gb-aqua">[{getInitials(server.name)}]</span>
|
|
) : (
|
|
`[${getInitials(server.name)}]`
|
|
)}
|
|
</button>
|
|
))}
|
|
<div className="mt-2 flex flex-col gap-2 items-center">
|
|
<button
|
|
onClick={() => setShowCreate(true)}
|
|
className="w-11 h-11 flex items-center justify-center font-mono text-sm border bg-gb-bg-s text-gb-fg border-gb-bg-t hover:border-gb-fg-t hover:text-gb-aqua"
|
|
title="Create server"
|
|
>
|
|
[+]
|
|
</button>
|
|
<button
|
|
onClick={() => setShowJoin(true)}
|
|
className="w-11 h-11 flex items-center justify-center font-mono text-xs border bg-gb-bg-s text-gb-fg border-gb-bg-t hover:border-gb-fg-t hover:text-gb-aqua"
|
|
title="Join server"
|
|
>
|
|
[#]
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{showCreate && <CreateServerModal onClose={() => setShowCreate(false)} />}
|
|
{showJoin && <JoinServerModal onClose={() => setShowJoin(false)} />}
|
|
</>
|
|
);
|
|
}
|