diff --git a/external/lang b/external/lang index 2054052c791ff2396dcbde68ae257fa13a93ab6c..de2b94c8d8615b732cbbec3679041e73fd3c7640 160000 --- a/external/lang +++ b/external/lang @@ -1 +1 @@ -Subproject commit 2054052c791ff2396dcbde68ae257fa13a93ab6c +Subproject commit de2b94c8d8615b732cbbec3679041e73fd3c7640 diff --git a/src/components/common/user/UserHover.tsx b/src/components/common/user/UserHover.tsx new file mode 100644 index 0000000000000000000000000000000000000000..28b14ffc2d0426747984421c886316a19333ee7c --- /dev/null +++ b/src/components/common/user/UserHover.tsx @@ -0,0 +1,41 @@ +import { Children } from "../../../types/Preact"; +import { Username } from "./UserShort"; +import styled from "styled-components"; +import UserStatus from "./UserStatus"; +import Tooltip from "../Tooltip"; +import { User } from "revolt.js"; + +interface Props { + user?: User, + children: Children +} + +const Base = styled.div` + display: flex; + flex-direction: column; + + .username { + font-weight: 600; + } + + .status { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } +`; + +export default function UserHover({ user, children }: Props) { + return ( + <Tooltip placement="right-end" content={ + <Base> + <Username className="username" user={user} /> + <span className="status"> + <UserStatus user={user} /> + </span> + </Base> + }> + { children } + </Tooltip> + ) +} diff --git a/src/components/common/user/UserStatus.tsx b/src/components/common/user/UserStatus.tsx index b0fb29ad495334dab6f6788cfa820533b2973f3c..dc96b8e3484a0772864e1056ce96cf5a7c208bae 100644 --- a/src/components/common/user/UserStatus.tsx +++ b/src/components/common/user/UserStatus.tsx @@ -5,12 +5,12 @@ import { Text } from "preact-i18n"; import Tooltip from "../Tooltip"; interface Props { - user: User; + user?: User; tooltip?: boolean; } export default function UserStatus({ user, tooltip }: Props) { - if (user.online) { + if (user?.online) { if (user.status?.text) { if (tooltip) { return ( diff --git a/src/components/navigation/left/HomeSidebar.tsx b/src/components/navigation/left/HomeSidebar.tsx index fe951e14ece743a6ffe8c8219b0f3df4fea02a8e..c4ef1e1de7c01b67b23f89e6ed0661f269c64669 100644 --- a/src/components/navigation/left/HomeSidebar.tsx +++ b/src/components/navigation/left/HomeSidebar.tsx @@ -27,7 +27,6 @@ import { useUsers, } from "../../../context/revoltjs/hooks"; -import UserHeader from "../../common/user/UserHeader"; import Category from "../../ui/Category"; import placeholderSVG from "../items/placeholder.svg"; import { mapChannelWithUnread, useUnreads } from "./common"; @@ -81,7 +80,6 @@ function HomeSidebar(props: Props) { return ( <GenericSidebarBase padding> - <UserHeader user={client.user!} /> <ConnectionStatus /> <GenericSidebarList> {!isTouchscreenDevice && ( diff --git a/src/components/navigation/left/ServerListSidebar.tsx b/src/components/navigation/left/ServerListSidebar.tsx index 838b74c2d073cc6ae83f2432c0e6a5243d73bc72..2ca6c076f8a4fe94789c0c9faeaf8831bafe9457 100644 --- a/src/components/navigation/left/ServerListSidebar.tsx +++ b/src/components/navigation/left/ServerListSidebar.tsx @@ -29,6 +29,7 @@ import LineDivider from "../../ui/LineDivider"; import { mapChannelWithUnread } from "./common"; import { Children } from "../../../types/Preact"; +import UserHover from "../../common/user/UserHover"; function Icon({ children, @@ -241,9 +242,11 @@ export function ServerListSidebar({ unreads, lastOpened }: Props) { onClick={() => homeActive && openContextMenu("Status") }> - <Icon size={42} unread={homeUnread}> - <UserIcon target={self} size={32} status /> - </Icon> + <UserHover user={self}> + <Icon size={42} unread={homeUnread}> + <UserIcon target={self} size={32} status /> + </Icon> + </UserHover> </div> <span /> </ServerEntry> diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx index b3e3de60b7cbbf1da522e1d5554292e305232500..801611f153e023423eb2f8317b11a6775b919aba 100644 --- a/src/lib/ContextMenus.tsx +++ b/src/lib/ContextMenus.tsx @@ -10,6 +10,7 @@ import { LeftArrowAlt, Trash, } from "@styled-icons/boxicons-regular"; +import Tooltip from "../components/common/Tooltip"; import { Cog, UserVoice } from "@styled-icons/boxicons-solid"; import { useHistory } from "react-router-dom"; import { @@ -875,8 +876,14 @@ function ContextMenus(props: Props) { <> <div className="header"> <div className="main"> - <div>@{client.user!.username}</div> - <div className="status"> + <div className="username" + onClick={() => writeClipboard(client.user!.username)}> + <Tooltip content={<Text id="app.special.copy_username" />}> + @{client.user!.username} + </Tooltip> + </div> + <div className="status" + onClick={() => contextClick({ action: 'set_status' })}> <UserStatus user={client.user!} /> </div> </div> @@ -924,23 +931,21 @@ function ContextMenus(props: Props) { <Text id={`app.status.invisible`} /> </MenuItem> <LineDivider /> - <MenuItem - data={{ action: "set_status" }} - disabled={!isOnline}> - <UserVoice size={18} /> - <Text - id={`app.context_menu.custom_status`} - /> - {client.user!.status?.text && ( + <MenuItem + data={{ action: "set_status" }} + disabled={!isOnline}> + <UserVoice size={18} /> + <Text + id={`app.context_menu.custom_status`} + /> + {client.user!.status?.text && ( <IconButton> <MenuItem data={{ action: "clear_status" }}> <Trash size={18} /> </MenuItem> </IconButton> )} - </MenuItem> - - + </MenuItem> </> )} </ContextMenuWithData> diff --git a/src/redux/reducers/index.ts b/src/redux/reducers/index.ts index 029d5f5143ba02b3838a6b9cc5c9a6e510186ae6..979d36eb6346261f82766b638a9ec3c3872c3fea 100644 --- a/src/redux/reducers/index.ts +++ b/src/redux/reducers/index.ts @@ -46,15 +46,3 @@ export type Action = | NotificationsAction | SectionToggleAction | { type: "__INIT"; state: State }; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function filter(obj: any, keys: string[]) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const newObj: any = {}; - for (const key of keys) { - const v = obj[key]; - if (v) newObj[key] = v; - } - - return newObj; -} diff --git a/src/redux/reducers/settings.ts b/src/redux/reducers/settings.ts index d5c898f3aceb61e9f59ec2d3e1e3a2351adbe461..65d367bac5ce3d6e26365ef3b31b01cf4b55c022 100644 --- a/src/redux/reducers/settings.ts +++ b/src/redux/reducers/settings.ts @@ -2,7 +2,6 @@ import type { Theme, ThemeOptions } from "../../context/Theme"; import { setEmojiPack } from "../../components/common/Emoji"; -import { filter } from "."; import type { Sounds } from "../../assets/sounds/Audio"; import type { SyncUpdateAction } from "./sync"; @@ -67,7 +66,7 @@ export function settings( return { ...state, theme: { - ...filter(state.theme, ["custom", "preset", "ligatures"]), + ...state.theme, ...action.theme, }, }; @@ -94,7 +93,7 @@ export function settings( return { ...state, appearance: { - ...filter(state.appearance, ["emojiPack"]), + ...state.appearance, ...action.options, }, }; diff --git a/src/styles/_context-menu.scss b/src/styles/_context-menu.scss index d5f15ee13cb5b84af8b20c876c65353ddd3632ac..55f82c174cdc331b90ca88ec171eb90bdbaff6b8 100644 --- a/src/styles/_context-menu.scss +++ b/src/styles/_context-menu.scss @@ -1,5 +1,5 @@ .preact-context-menu .context-menu { - z-index: 10000; + z-index: 5000; min-width: 190px; padding: 6px 8px; user-select: none; @@ -48,9 +48,17 @@ flex-grow: 1; display: flex; flex-direction: column; + + .username { + > div { + cursor: pointer; + width: fit-content; + } + } } .status { + cursor: pointer; max-width: 132px; font-size: .625rem; color: var(--secondary-foreground);