diff --git a/package.json b/package.json index bb274ee..86af4bb 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "@fontsource/roboto": "^4.5.8", "@fontsource/roboto-mono": "^5.0.16", "@hcaptcha/react-hcaptcha": "^1.9.2", + "@hookform/resolvers": "^3.3.2", "@mattjennings/react-modal-stack": "^1.0.4", "@mdi/js": "^7.3.67", "@mdi/react": "^1.6.1", @@ -65,7 +66,8 @@ "remark-gfm": "^3.0.1", "reoverlay": "^1.0.3", "styled-components": "^5.3.11", - "use-resize-observer": "^9.1.0" + "use-resize-observer": "^9.1.0", + "yup": "^1.3.3" }, "devDependencies": { "@craco/craco": "^7.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10c82ff..2c50b8c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ dependencies: '@hcaptcha/react-hcaptcha': specifier: ^1.9.2 version: 1.9.2(react-dom@18.2.0)(react@18.2.0) + '@hookform/resolvers': + specifier: ^3.3.2 + version: 3.3.2(react-hook-form@7.49.0) '@mattjennings/react-modal-stack': specifier: ^1.0.4 version: 1.0.4(react@18.2.0) @@ -191,6 +194,9 @@ dependencies: use-resize-observer: specifier: ^9.1.0 version: 9.1.0(react-dom@18.2.0)(react@18.2.0) + yup: + specifier: ^1.3.3 + version: 1.3.3 devDependencies: '@craco/craco': @@ -2551,6 +2557,14 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@hookform/resolvers@3.3.2(react-hook-form@7.49.0): + resolution: {integrity: sha512-Tw+GGPnBp+5DOsSg4ek3LCPgkBOuOgS5DsDV7qsWNH9LZc433kgsWICjlsh2J9p04H2K66hsXPPb9qn9ILdUtA==} + peerDependencies: + react-hook-form: ^7.0.0 + dependencies: + react-hook-form: 7.49.0(react@18.2.0) + dev: false + /@humanwhocodes/config-array@0.11.11: resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} @@ -11202,6 +11216,10 @@ packages: object-assign: 4.1.1 react-is: 16.13.1 + /property-expr@2.0.6: + resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} + dev: false + /property-information@5.6.0: resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==} dependencies: @@ -12893,6 +12911,10 @@ packages: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} dev: true + /tiny-case@1.0.3: + resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==} + dev: false + /tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} dev: true @@ -12913,6 +12935,10 @@ packages: engines: {node: '>=0.6'} dev: true + /toposort@2.0.2: + resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} + dev: false + /tough-cookie@4.1.3: resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} engines: {node: '>=6'} @@ -13052,6 +13078,11 @@ packages: engines: {node: '>=10'} dev: true + /type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + dev: false + /type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -14071,6 +14102,15 @@ packages: engines: {node: '>=10'} dev: true + /yup@1.3.3: + resolution: {integrity: sha512-v8QwZSsHH2K3/G9WSkp6mZKO+hugKT1EmnMqLNUcfu51HU9MDyhlETT/JgtzprnrnQHPWsjc6MUDMBp/l9fNnw==} + dependencies: + property-expr: 2.0.6 + tiny-case: 1.0.3 + toposort: 2.0.2 + type-fest: 2.19.0 + dev: false + /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} dev: false diff --git a/src/components/MemberList/MemberListItem.tsx b/src/components/MemberList/MemberListItem.tsx index f968bb5..b19dcc3 100644 --- a/src/components/MemberList/MemberListItem.tsx +++ b/src/components/MemberList/MemberListItem.tsx @@ -79,7 +79,7 @@ function MemberListItem({ item }: Props) { contextMenu.onContextMenu(e, { user: item.user! })} + onContextMenu={(e) => contextMenu.onContextMenu(e, { user: item.user!, member: item })} > diff --git a/src/components/contextMenus/ContextMenu.tsx b/src/components/contextMenus/ContextMenu.tsx index b51bfa0..29cf876 100644 --- a/src/components/contextMenus/ContextMenu.tsx +++ b/src/components/contextMenus/ContextMenu.tsx @@ -21,16 +21,23 @@ export const ContextMenu = styled.div` export const ContextMenuDivider = styled.div` height: 1px; margin: 4px; - background: var(--text); + background: var(--text-disabled); `; -export const ContextMenuItem = styled("a")` +export const ContextMenuItem = styled("button")` display: block; padding: 6px 8px; border-radius: 4px; font-size: 14px; margin: 2px 0; - cursor: pointer; + cursor: ${(props) => (props.disabled ? "not-allowed" : "pointer")}; + opacity: ${(props) => (props.disabled ? 0.5 : 1)}; + + // remove default button styles + border: none; + background: none; + color: inherit; + outline: none; `; const ButtonBase = styled(ContextMenuItem)<{ destructive?: boolean }>` @@ -53,14 +60,15 @@ const ButtonBase = styled(ContextMenuItem)<{ destructive?: boolean }>` type ButtonProps = ComponentProps & { icon?: IconProps["icon"]; + iconProps?: Omit; destructive?: boolean; }; -export function ContextMenuButton(props: ButtonProps) { +export function ContextMenuButton({ icon, children, iconProps, ...props }: ButtonProps) { return ( - {props.children} - {props.icon && } + {children} + {icon && } ); } diff --git a/src/components/contextMenus/UserContextMenu.tsx b/src/components/contextMenus/UserContextMenu.tsx index 2981c51..76c4567 100644 --- a/src/components/contextMenus/UserContextMenu.tsx +++ b/src/components/contextMenus/UserContextMenu.tsx @@ -1,13 +1,16 @@ // loosely based on https://github.com/revoltchat/frontend/blob/master/components/app/menus/UserContextMenu.tsx +import { modalController } from "../../controllers/modals"; +import GuildMember from "../../stores/objects/GuildMember"; import User from "../../stores/objects/User"; import { ContextMenu, ContextMenuButton, ContextMenuDivider } from "./ContextMenu"; interface MenuProps { user: User; + member?: GuildMember; } -function UserContextMenu({ user }: MenuProps) { +function UserContextMenu({ user, member }: MenuProps) { /** * Copy user id to clipboard */ @@ -15,14 +18,61 @@ function UserContextMenu({ user }: MenuProps) { navigator.clipboard.writeText(user.id); } + /** + * Open kick modal + */ + function kick() { + if (!member) return; + modalController.push({ + type: "kick_member", + target: member, + }); + } + + /** + * Open ban modal + */ + function ban() { + if (!member) return; + modalController.push({ + type: "ban_member", + target: member, + }); + } + return ( - - Mention + Profile + Mention + Message + + Change Nickname + Add Friend + Block + + + Kick {member?.nick ?? user.username} + + + Ban {member?.nick ?? user.username} + + + + Roles - + Copy user ID diff --git a/src/components/modals/AddServerModal.tsx b/src/components/modals/AddServerModal.tsx index 4d18202..c6beac2 100644 --- a/src/components/modals/AddServerModal.tsx +++ b/src/components/modals/AddServerModal.tsx @@ -3,12 +3,12 @@ import { ModalProps, modalController } from "../../controllers/modals"; import Button from "../Button"; import { Modal } from "./ModalComponents"; -export const ActionWrapper = styled.div` +const ActionWrapper = styled.div` display: flex; flex-direction: column; gap: 8px; `; -function AddServerModal({ ...props }: ModalProps<"add_server">) { +export function AddServerModal({ ...props }: ModalProps<"add_server">) { return ( @@ -37,5 +37,3 @@ function AddServerModal({ ...props }: ModalProps<"add_server">) { ); } - -export default AddServerModal; diff --git a/src/components/modals/AttachmentPreviewModal.tsx b/src/components/modals/AttachmentPreviewModal.tsx index 854f304..5589046 100644 --- a/src/components/modals/AttachmentPreviewModal.tsx +++ b/src/components/modals/AttachmentPreviewModal.tsx @@ -1,5 +1,3 @@ -function AttachmentPreviewModal() { +export function AttachmentPreviewModal() { return null; } - -export default AttachmentPreviewModal; diff --git a/src/components/modals/BanMemberModal.tsx b/src/components/modals/BanMemberModal.tsx new file mode 100644 index 0000000..aea2509 --- /dev/null +++ b/src/components/modals/BanMemberModal.tsx @@ -0,0 +1,72 @@ +import { yupResolver } from "@hookform/resolvers/yup"; +import { useForm } from "react-hook-form"; +import styled from "styled-components"; +import * as yup from "yup"; +import { ModalProps, modalController } from "../../controllers/modals"; +import { Modal } from "./ModalComponents"; + +const DescriptionText = styled.p` + font-size: 16px; + font-weight: var(--font-weight-regular); + color: var(--text-header-secondary); + margin-top: 8px; +`; + +const schema = yup + .object({ + reason: yup.string(), + }) + .required(); + +export function BanMemberModal({ target, ...props }: ModalProps<"ban_member">) { + const { + register, + control, + setError, + handleSubmit, + formState: { errors, disabled, isLoading, isSubmitting }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const isDisabled = disabled || isLoading || isSubmitting; + + return ( + + Are you sure you want to ban @{target.user?.username}? They won't be able to rejoin unless + they are unbanned. + + } + actions={[ + { + onClick: () => console.log("kick"), + children: Kick, + palette: "danger", + confirmation: true, + disabled: isDisabled, + }, + { + onClick: () => modalController.pop("close"), + children: Cancel, + palette: "link", + disabled: isDisabled, + }, + ]} + > + Thanos Snap GIF + reason form + + ); +} diff --git a/src/components/modals/CreateInviteModal.tsx b/src/components/modals/CreateInviteModal.tsx index 7296402..8f00cc1 100644 --- a/src/components/modals/CreateInviteModal.tsx +++ b/src/components/modals/CreateInviteModal.tsx @@ -85,7 +85,7 @@ interface FormValues extends APICreateInvite { code: string; } -function CreateInviteModal({ target, ...props }: ModalProps<"create_invite">) { +export function CreateInviteModal({ target, ...props }: ModalProps<"create_invite">) { const logger = useLogger("CreateInviteModal"); const app = useAppStore(); const [maxAge, setMaxAge] = React.useState(ExpiryOptions.DAY_7); @@ -290,5 +290,3 @@ function CreateInviteModal({ target, ...props }: ModalProps<"create_invite">) { ); } - -export default CreateInviteModal; diff --git a/src/components/modals/CreateServerModal.tsx b/src/components/modals/CreateServerModal.tsx index 256dd5b..679af67 100644 --- a/src/components/modals/CreateServerModal.tsx +++ b/src/components/modals/CreateServerModal.tsx @@ -11,11 +11,6 @@ import { Input, InputErrorText, InputLabel, InputWrapper, LabelWrapper } from ". import { TextDivider } from "../Divider"; import { InputContainer, Modal } from "./ModalComponents"; -export const ModalHeader = styled.div` - margin-bottom: 30px; - padding: 24px 24px 0; -`; - const UploadIcon = styled.div` padding-top: 4; display: flex; @@ -49,7 +44,7 @@ type FormValues = { name: string; }; -function CreateServerModal({ ...props }: ModalProps<"create_server">) { +export function CreateServerModal({ ...props }: ModalProps<"create_server">) { const app = useAppStore(); const logger = useLogger("CreateServerModal"); const [selectedFile, setSelectedFile] = React.useState(); @@ -210,5 +205,3 @@ function CreateServerModal({ ...props }: ModalProps<"create_server">) { ); } - -export default CreateServerModal; diff --git a/src/components/modals/ErrorModal.tsx b/src/components/modals/ErrorModal.tsx index 8dd6b96..cac131e 100644 --- a/src/components/modals/ErrorModal.tsx +++ b/src/components/modals/ErrorModal.tsx @@ -1,7 +1,7 @@ import { ModalProps } from "../../controllers/modals/types"; import { Modal } from "./ModalComponents"; -function ErrorModal({ error, ...props }: ModalProps<"error">) { +export function ErrorModal({ error, ...props }: ModalProps<"error">) { return ( ) { ); } - -export default ErrorModal; diff --git a/src/components/modals/ForgotPasswordModal.tsx b/src/components/modals/ForgotPasswordModal.tsx index b0b3d16..cb240f4 100644 --- a/src/components/modals/ForgotPasswordModal.tsx +++ b/src/components/modals/ForgotPasswordModal.tsx @@ -1,5 +1,3 @@ -function ForgotPasswordModal() { +export function ForgotPasswordModal() { return null; } - -export default ForgotPasswordModal; diff --git a/src/components/modals/JoinServerModal.tsx b/src/components/modals/JoinServerModal.tsx index 9c95b91..175d5a1 100644 --- a/src/components/modals/JoinServerModal.tsx +++ b/src/components/modals/JoinServerModal.tsx @@ -10,10 +10,6 @@ import { Input, InputErrorText, InputLabel, LabelWrapper } from "../AuthComponen import { TextDivider } from "../Divider"; import { Modal } from "./ModalComponents"; -export const ModalHeader = styled.div` - padding: 16px; -`; - const InviteInputContainer = styled.div` display: flex; flex-direction: column; @@ -23,7 +19,7 @@ type FormValues = { code: string; }; -function JoinServerModal({ ...props }: ModalProps<"join_server">) { +export function JoinServerModal({ ...props }: ModalProps<"join_server">) { const logger = useLogger("JoinServerModal"); const app = useAppStore(); const navigate = useNavigate(); @@ -137,5 +133,3 @@ function JoinServerModal({ ...props }: ModalProps<"join_server">) { ); } - -export default JoinServerModal; diff --git a/src/components/modals/KickMemberModal.tsx b/src/components/modals/KickMemberModal.tsx new file mode 100644 index 0000000..dcfb91f --- /dev/null +++ b/src/components/modals/KickMemberModal.tsx @@ -0,0 +1,63 @@ +import { yupResolver } from "@hookform/resolvers/yup"; +import { useForm } from "react-hook-form"; +import styled from "styled-components"; +import * as yup from "yup"; +import { ModalProps, modalController } from "../../controllers/modals"; +import { Modal } from "./ModalComponents"; + +const DescriptionText = styled.p` + font-size: 16px; + font-weight: var(--font-weight-regular); + color: var(--text-header-secondary); + margin-top: 8px; +`; + +const schema = yup + .object({ + reason: yup.string(), + }) + .required(); + +export function KickMemberModal({ target, ...props }: ModalProps<"kick_member">) { + const { + register, + control, + setError, + handleSubmit, + formState: { errors, disabled, isLoading, isSubmitting }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const isDisabled = disabled || isLoading || isSubmitting; + + return ( + + Are you sure you want to kick @{target.user?.username} from the guild? They will be able to + rejoin again with a new invite. + + } + actions={[ + { + onClick: () => console.log("kick"), + children: Kick, + palette: "danger", + confirmation: true, + disabled: isDisabled, + }, + { + onClick: () => modalController.pop("close"), + children: Cancel, + palette: "link", + disabled: isDisabled, + }, + ]} + > + reason form + + ); +} diff --git a/src/components/modals/KickModal.tsx b/src/components/modals/KickModal.tsx deleted file mode 100644 index 60c44ac..0000000 --- a/src/components/modals/KickModal.tsx +++ /dev/null @@ -1,5 +0,0 @@ -function KickModal() { - return null; -} - -export default KickModal; diff --git a/src/components/modals/LeaveServerModal.tsx b/src/components/modals/LeaveServerModal.tsx index ece6937..0778b64 100644 --- a/src/components/modals/LeaveServerModal.tsx +++ b/src/components/modals/LeaveServerModal.tsx @@ -1,5 +1,3 @@ -function LeaveServerModal() { +export function LeaveServerModal() { return null; } - -export default LeaveServerModal; diff --git a/src/components/modals/ModalComponents.tsx b/src/components/modals/ModalComponents.tsx index dad1d28..a1358c7 100644 --- a/src/components/modals/ModalComponents.tsx +++ b/src/components/modals/ModalComponents.tsx @@ -17,7 +17,7 @@ interface ModalProps { onClose?: (force: boolean) => void; signal?: "close" | "confirm" | "cancel"; title?: string; - description?: string; + description?: React.ReactNode; transparent?: boolean; nonDismissable?: boolean; maxWidth?: string; @@ -214,8 +214,16 @@ export function Modal(props: ModalProps) { {(props.title || props.description) && ( - {props.title && {props.title}} - {props.description && {props.description}} + {props.title && typeof props.title === "string" ? ( + {props.title} + ) : ( + props.title + )} + {props.description && typeof props.description === "string" ? ( + {props.description} + ) : ( + props.description + )} )} {props.children} diff --git a/src/components/modals/SettingsModal.tsx b/src/components/modals/SettingsModal.tsx index 1073980..ac6c06d 100644 --- a/src/components/modals/SettingsModal.tsx +++ b/src/components/modals/SettingsModal.tsx @@ -1,7 +1,3 @@ -import { observer } from "mobx-react-lite"; - -function SettingsModal() { +export function SettingsModal() { return null; } - -export default observer(SettingsModal); diff --git a/src/components/modals/index.ts b/src/components/modals/index.ts new file mode 100644 index 0000000..db738ae --- /dev/null +++ b/src/components/modals/index.ts @@ -0,0 +1,11 @@ +export * from "./AddServerModal"; +export * from "./AttachmentPreviewModal"; +export * from "./BanMemberModal"; +export * from "./CreateInviteModal"; +export * from "./CreateServerModal"; +export * from "./ErrorModal"; +export * from "./ForgotPasswordModal"; +export * from "./JoinServerModal"; +export * from "./KickMemberModal"; +export * from "./LeaveServerModal"; +export * from "./SettingsModal"; diff --git a/src/contexts/ContextMenuContext.tsx b/src/contexts/ContextMenuContext.tsx index 3277ede..0e7437c 100644 --- a/src/contexts/ContextMenuContext.tsx +++ b/src/contexts/ContextMenuContext.tsx @@ -3,10 +3,12 @@ import { FloatingPortal, useFloating } from "@floating-ui/react"; import React from "react"; import UserContextMenu from "../components/contextMenus/UserContextMenu"; import useContextMenu from "../hooks/useContextMenu"; +import GuildMember from "../stores/objects/GuildMember"; import User from "../stores/objects/User"; interface MenuProps { user: User; + member?: GuildMember; } export type ContextMenuContextType = { diff --git a/src/contexts/Theme.tsx b/src/contexts/Theme.tsx index 693b98d..3f4e7c9 100644 --- a/src/contexts/Theme.tsx +++ b/src/contexts/Theme.tsx @@ -6,10 +6,13 @@ import { rgbToHsl } from "../utils/Utils"; const font: ThemeFont["font"] = { weight: { thin: 100, + // extraLight: 200, light: 300, regular: 400, medium: 500, + // semiBold: 600, bold: 700, + // extraBold: 800, black: 900, }, family: "Roboto, Arial, Helvetica, sans-serif", @@ -69,10 +72,13 @@ export type ThemeFont = { font: { weight: { thin?: number; + extraLight?: number; light?: number; regular?: number; medium?: number; + semiBold?: number; bold?: number; + extraBold?: number; black?: number; }; family: string; diff --git a/src/controllers/modals/ModalController.tsx b/src/controllers/modals/ModalController.tsx index 7e93529..3750155 100644 --- a/src/controllers/modals/ModalController.tsx +++ b/src/controllers/modals/ModalController.tsx @@ -1,11 +1,15 @@ // adapted from https://github.com/revoltchat/revite/blob/master/src/controllers/modals/ModalController.tsx import { action, computed, makeObservable, observable } from "mobx"; -import AddServerModal from "../../components/modals/AddServerModal"; -import CreateInviteModal from "../../components/modals/CreateInviteModal"; -import CreateServerModal from "../../components/modals/CreateServerModal"; -import ErrorModal from "../../components/modals/ErrorModal"; -import JoinServerModal from "../../components/modals/JoinServerModal"; +import { + AddServerModal, + BanMemberModal, + CreateInviteModal, + CreateServerModal, + ErrorModal, + JoinServerModal, + KickMemberModal, +} from "../../components/modals"; import { Modal } from "./types"; function randomUUID() { @@ -95,6 +99,7 @@ class ModalController { <> {this.stack.map((modal) => { const Component = this.components[modal.type]; + if (!Component) return null; return this.remove(modal.key!)} />; })} @@ -132,7 +137,7 @@ class ModalControllerExtended extends ModalController { export const modalController = new ModalControllerExtended({ add_server: AddServerModal, // add_friend: AddFriend, - // ban_member: BanMember, + ban_member: BanMemberModal, // changelog: Changelog, // channel_info: ChannelInfo, // clipboard: Clipboard, @@ -156,7 +161,7 @@ export const modalController = new ModalControllerExtended({ // delete_message: DeleteMessage, error: ErrorModal, // image_viewer: ImageViewer, - // kick_member: KickMember, + kick_member: KickMemberModal, // link_warning: LinkWarning, // mfa_flow: MFAFlow, // mfa_recovery: MFARecovery, diff --git a/src/controllers/modals/types.ts b/src/controllers/modals/types.ts index 05c703a..0261bb5 100644 --- a/src/controllers/modals/types.ts +++ b/src/controllers/modals/types.ts @@ -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 GuildMember from "../../stores/objects/GuildMember"; export type Modal = { key?: string; @@ -23,6 +24,14 @@ export type Modal = { type: "create_invite"; target: Channel; } + | { + type: "kick_member"; + target: GuildMember; + } + | { + type: "ban_member"; + target: GuildMember; + } ); export type ModalProps = Modal & { type: T } & { diff --git a/src/hooks/useContextMenu.tsx b/src/hooks/useContextMenu.tsx index b91cea7..f7ba247 100644 --- a/src/hooks/useContextMenu.tsx +++ b/src/hooks/useContextMenu.tsx @@ -1,9 +1,11 @@ import { autoUpdate, flip, offset, shift, useDismiss, useFloating, useInteractions, useRole } from "@floating-ui/react"; import { useMemo, useState } from "react"; +import GuildMember from "../stores/objects/GuildMember"; import User from "../stores/objects/User"; interface MenuProps { user: User; + member?: GuildMember; } export default function (type: "user") { diff --git a/src/index.css b/src/index.css index c2b7805..f0b5706 100644 --- a/src/index.css +++ b/src/index.css @@ -18,9 +18,12 @@ textarea { margin: 0; } +html *:not(code) { + font-family: var(--font-family); +} + body { margin: 0; - font-family: var(--font-family); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; overflow: hidden; diff --git a/src/index.tsx b/src/index.tsx index f99972d..09ae09d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -11,6 +11,7 @@ import "@fontsource/roboto/400.css"; import "@fontsource/roboto/500.css"; import "@fontsource/roboto/700.css"; import "@fontsource/roboto/900.css"; + import dayjs from "dayjs"; import calendar from "dayjs/plugin/calendar"; import relativeTime from "dayjs/plugin/relativeTime";