2021-06-19 10:29:04 -04:00
|
|
|
import { Channel, Servers } from "revolt.js/dist/api/objects";
|
|
|
|
import { Link, useLocation, useParams } from "react-router-dom";
|
|
|
|
import { useChannels, useForceUpdate, useServers } from "../../../context/revoltjs/hooks";
|
|
|
|
import { mapChannelWithUnread } from "./common";
|
|
|
|
import { Unreads } from "../../../redux/reducers/unreads";
|
|
|
|
import { connectState } from "../../../redux/connector";
|
|
|
|
import styled, { css } from "styled-components";
|
|
|
|
import { Children } from "../../../types/Preact";
|
|
|
|
import LineDivider from "../../ui/LineDivider";
|
|
|
|
import ServerIcon from "../../common/ServerIcon";
|
|
|
|
import PaintCounter from "../../../lib/PaintCounter";
|
2021-06-19 17:37:12 -04:00
|
|
|
import { attachContextMenu } from 'preact-context-menu';
|
2021-06-19 10:29:04 -04:00
|
|
|
|
|
|
|
function Icon({ children, unread, size }: { children: Children, unread?: 'mention' | 'unread', size: number }) {
|
|
|
|
return (
|
|
|
|
<svg
|
|
|
|
width={size}
|
|
|
|
height={size}
|
|
|
|
aria-hidden="true"
|
|
|
|
viewBox="0 0 32 32"
|
|
|
|
>
|
|
|
|
<foreignObject x="0" y="0" width="32" height="32">
|
|
|
|
{ children }
|
|
|
|
</foreignObject>
|
|
|
|
{unread === 'unread' && (
|
|
|
|
<circle
|
|
|
|
cx="27"
|
|
|
|
cy="27"
|
|
|
|
r="5"
|
|
|
|
fill={"white"}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{unread === 'mention' && (
|
|
|
|
<circle
|
|
|
|
cx="27"
|
|
|
|
cy="27"
|
|
|
|
r="5"
|
|
|
|
fill={"red"}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</svg>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const ServersBase = styled.div`
|
|
|
|
width: 52px;
|
|
|
|
height: 100%;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const ServerList = styled.div`
|
|
|
|
flex-grow: 1;
|
|
|
|
display: flex;
|
|
|
|
overflow-y: scroll;
|
|
|
|
padding-bottom: 48px;
|
|
|
|
flex-direction: column;
|
|
|
|
border-inline-end: 2px solid var(--sidebar-active);
|
|
|
|
|
|
|
|
scrollbar-width: none;
|
|
|
|
|
|
|
|
> :first-child > svg {
|
|
|
|
margin: 6px 0 6px 4px;
|
|
|
|
}
|
|
|
|
|
|
|
|
&::-webkit-scrollbar {
|
|
|
|
width: 0px;
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
|
|
|
const ServerEntry = styled.div<{ active: boolean, invert?: boolean }>`
|
|
|
|
height: 44px;
|
|
|
|
padding: 4px;
|
|
|
|
margin: 2px 0 2px 4px;
|
|
|
|
|
|
|
|
border-top-left-radius: 4px;
|
|
|
|
border-bottom-left-radius: 4px;
|
|
|
|
|
|
|
|
img {
|
|
|
|
width: 32px;
|
|
|
|
height: 32px;
|
|
|
|
}
|
|
|
|
|
|
|
|
${ props => props.active && css`
|
|
|
|
background: var(--sidebar-active);
|
|
|
|
` }
|
|
|
|
|
|
|
|
${ props => props.active && props.invert && css`
|
|
|
|
img {
|
|
|
|
filter: saturate(0) brightness(10);
|
|
|
|
}
|
|
|
|
` }
|
|
|
|
`;
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
unreads: Unreads;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function ServerListSidebar({ unreads }: Props) {
|
|
|
|
const ctx = useForceUpdate();
|
|
|
|
const activeServers = useServers(undefined, ctx) as Servers.Server[];
|
|
|
|
const channels = (useChannels(undefined, ctx) as Channel[])
|
|
|
|
.map(x => mapChannelWithUnread(x, unreads));
|
|
|
|
|
|
|
|
const unreadChannels = channels.filter(x => x.unread)
|
|
|
|
.map(x => x._id);
|
|
|
|
|
|
|
|
const servers = activeServers.map(server => {
|
|
|
|
let alertCount = 0;
|
|
|
|
for (let id of server.channels) {
|
|
|
|
let channel = channels.find(x => x._id === id);
|
|
|
|
if (channel?.alertCount) {
|
|
|
|
alertCount += channel.alertCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
...server,
|
|
|
|
unread: (typeof server.channels.find(x => unreadChannels.includes(x)) !== 'undefined' ?
|
|
|
|
( alertCount > 0 ? 'mention' : 'unread' ) : undefined) as 'mention' | 'unread' | undefined,
|
|
|
|
alertCount
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
const path = useLocation().pathname;
|
|
|
|
const { server: server_id } = useParams<{ server?: string }>();
|
|
|
|
const server = servers.find(x => x!._id == server_id);
|
|
|
|
|
|
|
|
// const { openScreen } = useContext(IntermediateContext);
|
|
|
|
|
|
|
|
let homeUnread: 'mention' | 'unread' | undefined;
|
|
|
|
let alertCount = 0;
|
|
|
|
for (let x of channels) {
|
|
|
|
if (((x.channel_type === 'DirectMessage' && x.active) || x.channel_type === 'Group') && x.unread) {
|
|
|
|
homeUnread = 'unread';
|
|
|
|
alertCount += x.alertCount ?? 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (alertCount > 0) homeUnread = 'mention';
|
|
|
|
|
|
|
|
return (
|
|
|
|
<ServersBase>
|
|
|
|
<ServerList>
|
|
|
|
<Link to={`/`}>
|
|
|
|
<ServerEntry invert
|
|
|
|
active={typeof server === 'undefined' && !path.startsWith('/invite')}>
|
|
|
|
<Icon size={36} unread={homeUnread}>
|
|
|
|
<img src="/assets/app_icon.png" />
|
|
|
|
</Icon>
|
|
|
|
</ServerEntry>
|
|
|
|
</Link>
|
|
|
|
<LineDivider />
|
|
|
|
{
|
|
|
|
servers.map(entry =>
|
|
|
|
<Link to={`/server/${entry!._id}`}>
|
|
|
|
<ServerEntry
|
|
|
|
active={entry!._id === server?._id}
|
2021-06-19 17:37:12 -04:00
|
|
|
onContextMenu={attachContextMenu('Menu', { server: entry!._id })}>
|
2021-06-19 10:29:04 -04:00
|
|
|
<Icon size={36} unread={entry.unread}>
|
|
|
|
<ServerIcon size={32} target={entry} />
|
|
|
|
</Icon>
|
|
|
|
</ServerEntry>
|
|
|
|
</Link>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
<PaintCounter small />
|
|
|
|
</ServerList>
|
|
|
|
</ServersBase>
|
2021-06-19 17:37:12 -04:00
|
|
|
// ! FIXME: add overlay back
|
2021-06-19 10:29:04 -04:00
|
|
|
/*<div className={styles.servers}>
|
|
|
|
<div className={styles.list}>
|
|
|
|
<Link to={`/`}>
|
|
|
|
<div className={styles.entry}
|
|
|
|
data-active={typeof server === 'undefined' && !path.startsWith('/invite')}>
|
|
|
|
<Icon size={36} unread={homeUnread} alertCount={alertCount}>
|
|
|
|
<div className={styles.logo} />
|
|
|
|
</Icon>
|
|
|
|
</div>
|
|
|
|
</Link>
|
|
|
|
<LineDivider className={styles.divider} />
|
|
|
|
{
|
|
|
|
servers.map(entry =>
|
|
|
|
<Link to={`/server/${entry!._id}`}>
|
|
|
|
<div className={styles.entry}
|
|
|
|
data-active={entry!._id === server?._id}
|
|
|
|
onContextMenu={attachContextMenu('Menu', { server: entry!._id })}>
|
|
|
|
<Icon size={36} unread={entry.unread}>
|
|
|
|
<ServerIcon id={entry!._id} size={32} />
|
|
|
|
</Icon>
|
|
|
|
</div>
|
|
|
|
</Link>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
</div>
|
|
|
|
<div className={styles.overlay}>
|
|
|
|
<div className={styles.actions}>
|
|
|
|
<IconButton onClick={() => openScreen({ id: 'special_input', type: 'create_server' })}>
|
|
|
|
<PlusCircle size={36} />
|
|
|
|
</IconButton>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div> */
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
export default connectState(
|
|
|
|
ServerListSidebar,
|
|
|
|
state => {
|
|
|
|
return {
|
|
|
|
unreads: state.unreads
|
|
|
|
};
|
|
|
|
}
|
|
|
|
);
|