mirror of
https://github.com/spacebarchat/client.git
synced 2024-11-25 19:52:31 +01:00
Start implementing member list
This commit is contained in:
parent
c13dd8aaef
commit
e3b438d0cb
53
src/components/ListSection.tsx
Normal file
53
src/components/ListSection.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
const Container = styled.div`
|
||||
padding: 24px 8px 0 16px;
|
||||
`;
|
||||
|
||||
const Title = styled.span`
|
||||
font-size: 12px;
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--text-secondary);
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div<{ open?: boolean }>`
|
||||
margin-top: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
display: ${(props) => (props.open === false ? "flex" : "none")};
|
||||
`;
|
||||
|
||||
const Item = styled.span`
|
||||
font-size: 16px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--text-normal);
|
||||
user-select: none;
|
||||
margin-left: 8px;
|
||||
padding: 4px 0;
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
name: string;
|
||||
items: string[];
|
||||
}
|
||||
|
||||
function ListSection(props: Props) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const toggle = () => setOpen((prev) => !prev);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Title onClick={toggle}>{props.name}</Title>
|
||||
<Wrapper open={open}>
|
||||
{props.items.map((item) => (
|
||||
<Item>{item}</Item>
|
||||
))}
|
||||
</Wrapper>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListSection;
|
@ -1,5 +1,7 @@
|
||||
import { observer } from "mobx-react-lite";
|
||||
import styled from "styled-components";
|
||||
import { useAppStore } from "../../stores/AppStore";
|
||||
import ListSection from "../ListSection";
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
@ -20,10 +22,50 @@ const Wrapper = styled.aside`
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const List = styled.ul`
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
function MemberList() {
|
||||
const app = useAppStore();
|
||||
|
||||
if (!app.activeGuild || !app.activeChannel) return null;
|
||||
const { memberList } = app.activeGuild;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Wrapper>MemberList</Wrapper>
|
||||
{/* <AutoSizer>
|
||||
{({ width, height }) => (
|
||||
<List
|
||||
height={height}
|
||||
overscanRowCount={2}
|
||||
rowCount={memberList.length}
|
||||
rowHeight={({ index }) => {
|
||||
// const item = channels[index];
|
||||
// if (item.type === ChannelType.GuildCategory) {
|
||||
// return 44;
|
||||
// }
|
||||
return 33;
|
||||
}}
|
||||
rowRenderer={rowRenderer}
|
||||
width={width}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer> */}
|
||||
|
||||
<List>
|
||||
{memberList.map((category) => (
|
||||
<ListSection
|
||||
name={category.name}
|
||||
items={category.items.map((x) => x.nick ?? x.user?.username).filter((x) => x) as string[]}
|
||||
/>
|
||||
))}
|
||||
</List>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
68
src/components/MemberList/MemberListItem.tsx
Normal file
68
src/components/MemberList/MemberListItem.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import { useModals } from "@mattjennings/react-modal-stack";
|
||||
import React from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import styled from "styled-components";
|
||||
import { ContextMenuContext } from "../../contexts/ContextMenuContext";
|
||||
import GuildMember from "../../stores/objects/GuildMember";
|
||||
import { IContextMenuItem } from "../ContextMenuItem";
|
||||
|
||||
const ListItem = styled.div<{ isCategory?: boolean }>`
|
||||
padding: ${(props) => (props.isCategory ? "16px 8px 0 0" : "1px 8px 0 0")};
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div<{ isCategory?: boolean }>`
|
||||
margin-left: ${(props) => (props.isCategory ? "0" : "8px")};
|
||||
height: ${(props) => (props.isCategory ? "28px" : "33px")};
|
||||
border-radius: 4px;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
padding: 0 8px;
|
||||
background-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--background-primary-alt);
|
||||
}
|
||||
`;
|
||||
|
||||
const Text = styled.span<{ isCategory?: boolean }>`
|
||||
font-size: 16px;
|
||||
font-weight: var(--font-weight-regular);
|
||||
white-space: nowrap;
|
||||
color: var(--text-secondary);
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
item: string | GuildMember;
|
||||
}
|
||||
|
||||
function MemberListItem({ item }: Props) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { openModal } = useModals();
|
||||
|
||||
const contextMenu = React.useContext(ContextMenuContext);
|
||||
const [contextMenuItems, setContextMenuItems] = React.useState<IContextMenuItem[]>([]);
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
key={typeof item === "string" ? item : item.user?.id}
|
||||
isCategory={typeof item === "string"}
|
||||
// onClick={() => {
|
||||
// // prevent navigating to non-text channels
|
||||
// if (!channel.isTextChannel) return;
|
||||
|
||||
// navigate(`/channels/${channel.guildId}/${channel.id}`);
|
||||
// }}
|
||||
onContextMenu={(e) => contextMenu.open2(e, contextMenuItems)}
|
||||
>
|
||||
<Wrapper isCategory={typeof item === "string"}>
|
||||
<Text isCategory={typeof item === "string"}>
|
||||
{typeof item === "string" ? item : item.nick ?? item.user?.username}
|
||||
</Text>
|
||||
</Wrapper>
|
||||
</ListItem>
|
||||
);
|
||||
}
|
||||
|
||||
export default MemberListItem;
|
@ -18,7 +18,7 @@ export default class GuildMemberListStore {
|
||||
@observable groups: GatewayGuildMemberListUpdateGroup[] = [];
|
||||
@observable member_count: number;
|
||||
@observable online_count: number;
|
||||
@observable list: (string | GuildMember)[] = [];
|
||||
@observable list: { name: string; items: GuildMember[] }[] = [];
|
||||
|
||||
constructor(app: AppStore, guild: Guild, data: GatewayGuildMemberListUpdateDispatchData) {
|
||||
this.app = app;
|
||||
@ -98,9 +98,24 @@ export default class GuildMemberListStore {
|
||||
// ...i.data.sort((a, b) => a.index - b.index).map(i => i.member),
|
||||
// ]);
|
||||
|
||||
this.list = listData.flatMap((i) => [
|
||||
i.title,
|
||||
...i.data
|
||||
// this.list = listData.flatMap((i) => [
|
||||
// i.title,
|
||||
// ...i.data
|
||||
// .sort((a, b) => {
|
||||
// const ua = a.member.user?.username;
|
||||
// const ub = b.member.user?.username;
|
||||
// if (ua && ub) {
|
||||
// return ua.toLowerCase() > ub.toLowerCase() ? 1 : -1;
|
||||
// }
|
||||
|
||||
// return 0;
|
||||
// })
|
||||
// .map((i) => i.member),
|
||||
// ]);
|
||||
|
||||
this.list = listData.map((i) => ({
|
||||
name: i.title,
|
||||
items: i.data
|
||||
.sort((a, b) => {
|
||||
const ua = a.member.user?.username;
|
||||
const ub = b.member.user?.username;
|
||||
@ -111,7 +126,7 @@ export default class GuildMemberListStore {
|
||||
return 0;
|
||||
})
|
||||
.map((i) => i.member),
|
||||
]);
|
||||
}));
|
||||
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user