mirror of
https://github.com/spacebarchat/client.git
synced 2024-11-22 18:32:34 +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 { observer } from "mobx-react-lite";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
import { useAppStore } from "../../stores/AppStore";
|
||||||
|
import ListSection from "../ListSection";
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -20,10 +22,50 @@ const Wrapper = styled.aside`
|
|||||||
display: flex;
|
display: flex;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const List = styled.ul`
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
list-style: none;
|
||||||
|
overflow-y: auto;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
function MemberList() {
|
function MemberList() {
|
||||||
|
const app = useAppStore();
|
||||||
|
|
||||||
|
if (!app.activeGuild || !app.activeChannel) return null;
|
||||||
|
const { memberList } = app.activeGuild;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<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>
|
</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 groups: GatewayGuildMemberListUpdateGroup[] = [];
|
||||||
@observable member_count: number;
|
@observable member_count: number;
|
||||||
@observable online_count: number;
|
@observable online_count: number;
|
||||||
@observable list: (string | GuildMember)[] = [];
|
@observable list: { name: string; items: GuildMember[] }[] = [];
|
||||||
|
|
||||||
constructor(app: AppStore, guild: Guild, data: GatewayGuildMemberListUpdateDispatchData) {
|
constructor(app: AppStore, guild: Guild, data: GatewayGuildMemberListUpdateDispatchData) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
@ -98,9 +98,24 @@ export default class GuildMemberListStore {
|
|||||||
// ...i.data.sort((a, b) => a.index - b.index).map(i => i.member),
|
// ...i.data.sort((a, b) => a.index - b.index).map(i => i.member),
|
||||||
// ]);
|
// ]);
|
||||||
|
|
||||||
this.list = listData.flatMap((i) => [
|
// this.list = listData.flatMap((i) => [
|
||||||
i.title,
|
// i.title,
|
||||||
...i.data
|
// ...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) => {
|
.sort((a, b) => {
|
||||||
const ua = a.member.user?.username;
|
const ua = a.member.user?.username;
|
||||||
const ub = b.member.user?.username;
|
const ub = b.member.user?.username;
|
||||||
@ -111,7 +126,7 @@ export default class GuildMemberListStore {
|
|||||||
return 0;
|
return 0;
|
||||||
})
|
})
|
||||||
.map((i) => i.member),
|
.map((i) => i.member),
|
||||||
]);
|
}));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user