mirror of
https://github.com/spacebarchat/client.git
synced 2024-11-25 11:42:30 +01:00
guild action menu
This commit is contained in:
parent
52f7f63ba9
commit
ba31016686
@ -44,18 +44,6 @@ export default styled.button<Props>`
|
||||
return "45px";
|
||||
}
|
||||
}};
|
||||
width: ${(props) => {
|
||||
if (props.grow) return "auto";
|
||||
switch (props.size) {
|
||||
default:
|
||||
case "small":
|
||||
return "96px";
|
||||
case "medium":
|
||||
return "96px";
|
||||
case "large":
|
||||
return "130px";
|
||||
}
|
||||
}};
|
||||
min-width: ${(props) => {
|
||||
if (props.grow) return "auto";
|
||||
switch (props.size) {
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { observer } from "mobx-react-lite";
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import styled from "styled-components";
|
||||
import { useAppStore } from "../stores/AppStore";
|
||||
import Icon, { IconProps } from "./Icon";
|
||||
import { SectionHeader } from "./SectionHeader";
|
||||
import Floating from "./floating/Floating";
|
||||
import FloatingTrigger from "./floating/FloatingTrigger";
|
||||
|
||||
const Wrapper = styled(SectionHeader)`
|
||||
background-color: var(--background-secondary);
|
||||
@ -26,13 +28,17 @@ const HeaderText = styled.header`
|
||||
function ChannelHeader() {
|
||||
const app = useAppStore();
|
||||
|
||||
const [isOpen, setOpen] = React.useState(false);
|
||||
const [icon, setIcon] = React.useState<IconProps["icon"]>("mdiChevronDown");
|
||||
|
||||
function openMenu(e: React.MouseEvent<HTMLDivElement>) {
|
||||
e.stopPropagation();
|
||||
const onOpenChange = (open: boolean) => {
|
||||
setOpen(open);
|
||||
};
|
||||
|
||||
setIcon("mdiClose");
|
||||
}
|
||||
useEffect(() => {
|
||||
if (isOpen) setIcon("mdiChevronDown");
|
||||
else setIcon("mdiClose");
|
||||
}, [isOpen]);
|
||||
|
||||
if (app.activeGuildId === "@me") {
|
||||
return (
|
||||
@ -52,10 +58,14 @@ function ChannelHeader() {
|
||||
if (!app.activeGuild) return null;
|
||||
|
||||
return (
|
||||
<Wrapper onClick={openMenu}>
|
||||
<HeaderText>{app.activeGuild.name}</HeaderText>
|
||||
<Icon icon={icon} size="20px" color="var(--text)" />
|
||||
</Wrapper>
|
||||
<Floating type="guild" open={isOpen} onOpenChange={onOpenChange} props={{ guild: app.activeGuild! }}>
|
||||
<FloatingTrigger>
|
||||
<Wrapper>
|
||||
<HeaderText>{app.activeGuild.name}</HeaderText>
|
||||
<Icon icon={icon} size="20px" color="var(--text)" />
|
||||
</Wrapper>
|
||||
</FloatingTrigger>
|
||||
</Floating>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,11 @@ import { FloatingArrow, FloatingPortal, Placement } from "@floating-ui/react";
|
||||
import { motion } from "framer-motion";
|
||||
import { FloatingContext } from "../../contexts/FloatingContext";
|
||||
import useFloating from "../../hooks/useFloating";
|
||||
import Guild from "../../stores/objects/Guild";
|
||||
import GuildMember from "../../stores/objects/GuildMember";
|
||||
import User from "../../stores/objects/User";
|
||||
import Tooltip from "../Tooltip";
|
||||
import GuildMenuPopout from "./GuildMenuPopout";
|
||||
import UserProfilePopout from "./UserProfilePopout";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@ -13,6 +15,7 @@ type Components = Record<string, React.FC<any>>;
|
||||
const components: Components = {
|
||||
userPopout: UserProfilePopout,
|
||||
tooltip: Tooltip,
|
||||
guild: GuildMenuPopout,
|
||||
};
|
||||
|
||||
export type FloatingOptions = {
|
||||
@ -36,6 +39,12 @@ export type FloatingOptions = {
|
||||
aria?: string;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: "guild";
|
||||
props: {
|
||||
guild: Guild;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export type FloatingProps<T extends FloatingOptions["type"]> = (FloatingOptions & {
|
||||
|
53
src/components/floating/GuildMenuPopout.tsx
Normal file
53
src/components/floating/GuildMenuPopout.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import styled from "styled-components";
|
||||
import useLogger from "../../hooks/useLogger";
|
||||
|
||||
import { modalController } from "../../controllers/modals";
|
||||
import { useAppStore } from "../../stores/AppStore";
|
||||
import { ContextMenu, ContextMenuButton, ContextMenuDivider } from "../contextMenus/ContextMenu";
|
||||
|
||||
const CustomContextMenu = styled(ContextMenu)`
|
||||
width: 200px;
|
||||
`;
|
||||
|
||||
function GuildMenuPopout() {
|
||||
const { activeGuild } = useAppStore();
|
||||
const logger = useLogger("GuildMenuPopout");
|
||||
if (!activeGuild) {
|
||||
logger.error("activeGuild is undefined");
|
||||
return null;
|
||||
}
|
||||
|
||||
function leaveGuild() {
|
||||
modalController.push({
|
||||
type: "leave_server",
|
||||
target: activeGuild!,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<CustomContextMenu>
|
||||
<ContextMenuButton icon="mdiCog" disabled>
|
||||
Server Settings
|
||||
</ContextMenuButton>
|
||||
<ContextMenuButton icon="mdiPlusCircle" disabled>
|
||||
Create Channel
|
||||
</ContextMenuButton>
|
||||
<ContextMenuButton icon="mdiFolderPlus" disabled>
|
||||
Create Channel
|
||||
</ContextMenuButton>
|
||||
<ContextMenuDivider />
|
||||
<ContextMenuButton icon="mdiBell" disabled>
|
||||
Notification Settings
|
||||
</ContextMenuButton>
|
||||
<ContextMenuButton icon="mdiShieldLock" disabled>
|
||||
Privacy Settings
|
||||
</ContextMenuButton>
|
||||
<ContextMenuDivider />
|
||||
<ContextMenuButton icon="mdiLocationExit" destructive onClick={leaveGuild}>
|
||||
Leave Guild
|
||||
</ContextMenuButton>
|
||||
</CustomContextMenu>
|
||||
);
|
||||
}
|
||||
|
||||
export default GuildMenuPopout;
|
@ -1,3 +1,53 @@
|
||||
export function LeaveServerModal() {
|
||||
return null;
|
||||
import { Routes } from "@spacebarchat/spacebar-api-types/v9";
|
||||
import { useState } from "react";
|
||||
import { ModalProps, modalController } from "../../controllers/modals";
|
||||
import { useAppStore } from "../../stores/AppStore";
|
||||
import { Modal } from "./ModalComponents";
|
||||
|
||||
export function LeaveServerModal({ target, ...props }: ModalProps<"leave_server">) {
|
||||
const app = useAppStore();
|
||||
const [isDisabled, setDisabled] = useState(false);
|
||||
|
||||
async function leaveGuild() {
|
||||
setDisabled(true);
|
||||
await app.rest
|
||||
.delete(Routes.guildMember(target.id, "@me"))
|
||||
.then(() => {
|
||||
modalController.pop("close");
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
})
|
||||
.finally(() => setDisabled(false));
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
{...props}
|
||||
title={`Leave '${target.name}'`}
|
||||
description={
|
||||
<span>
|
||||
Are you sure you want to leave <b>{target.name}</b>? You won't be able to rejoin this guild unless
|
||||
you are re-invited.
|
||||
</span>
|
||||
}
|
||||
actions={[
|
||||
{
|
||||
onClick: leaveGuild,
|
||||
children: <span>Leave Server</span>,
|
||||
palette: "danger",
|
||||
confirmation: true,
|
||||
disabled: isDisabled,
|
||||
size: "small",
|
||||
},
|
||||
{
|
||||
onClick: () => modalController.pop("close"),
|
||||
children: <span>Cancel</span>,
|
||||
palette: "link",
|
||||
disabled: isDisabled,
|
||||
size: "small",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ export type ModalAction = Omit<React.HTMLAttributes<HTMLButtonElement>, "as"> &
|
||||
};
|
||||
|
||||
interface ModalProps {
|
||||
children: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
onClose?: (force: boolean) => void;
|
||||
signal?: "close" | "confirm" | "cancel";
|
||||
title?: string;
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
ErrorModal,
|
||||
JoinServerModal,
|
||||
KickMemberModal,
|
||||
LeaveServerModal,
|
||||
} from "../../components/modals";
|
||||
import { Modal } from "./types";
|
||||
|
||||
@ -144,7 +145,7 @@ export const modalController = new ModalControllerExtended({
|
||||
// clipboard: Clipboard,
|
||||
// leave_group: ConfirmLeave,
|
||||
// close_dm: Confirmation,
|
||||
// leave_server: ConfirmLeave,
|
||||
leave_server: LeaveServerModal,
|
||||
// delete_server: Confirmation,
|
||||
// delete_channel: Confirmation,
|
||||
// delete_bot: Confirmation,
|
||||
|
@ -1,6 +1,7 @@
|
||||
// adapted from https://github.com/revoltchat/revite/blob/master/src/controllers/modals/types.ts
|
||||
|
||||
import Channel from "../../stores/objects/Channel";
|
||||
import Guild from "../../stores/objects/Guild";
|
||||
import GuildMember from "../../stores/objects/GuildMember";
|
||||
import Message from "../../stores/objects/Message";
|
||||
|
||||
@ -37,6 +38,10 @@ export type Modal = {
|
||||
type: "delete_message";
|
||||
target: Message;
|
||||
}
|
||||
| {
|
||||
type: "leave_server";
|
||||
target: Guild;
|
||||
}
|
||||
);
|
||||
|
||||
export type ModalProps<T extends Modal["type"]> = Modal & { type: T } & {
|
||||
|
Loading…
Reference in New Issue
Block a user