diff --git a/src/components/common/user/UserHeader.tsx b/src/components/common/user/UserHeader.tsx index e93f3fd2e084408af832760b08af0d3a63b3cd4f..d234340e42d1158bb4df60e126846a117827b58e 100644 --- a/src/components/common/user/UserHeader.tsx +++ b/src/components/common/user/UserHeader.tsx @@ -47,18 +47,8 @@ interface Props { export default function UserHeader({ user }: Props) { const { writeClipboard } = useIntermediate(); - function openPresenceSelector() { - openContextMenu("Status"); - } - return ( <Header borders placement="secondary"> - <UserIcon - target={user} - size={32} - status - onClick={openPresenceSelector} - /> <HeaderBase> <Localizer> <Tooltip content={<Text id="app.special.copy_username" />}> @@ -69,7 +59,7 @@ export default function UserHeader({ user }: Props) { </Tooltip> </Localizer> <span className="status" - onClick={openPresenceSelector}> + onClick={() => openContextMenu("Status")}> <UserStatus user={user} /> </span> </HeaderBase> diff --git a/src/components/navigation/left/ServerListSidebar.tsx b/src/components/navigation/left/ServerListSidebar.tsx index 5d94fbc51a69f4c96c885eccaa50d186277e6eb3..cb1c7d122f740dbfaeeda3204a809696631ba179 100644 --- a/src/components/navigation/left/ServerListSidebar.tsx +++ b/src/components/navigation/left/ServerListSidebar.tsx @@ -6,7 +6,7 @@ import ServerIcon from "../../common/ServerIcon"; import { Children } from "../../../types/Preact"; import { Plus } from "@styled-icons/boxicons-regular"; import PaintCounter from "../../../lib/PaintCounter"; -import { attachContextMenu } from 'preact-context-menu'; +import { attachContextMenu, openContextMenu } from 'preact-context-menu'; import { connectState } from "../../../redux/connector"; import { useLocation, useParams } from "react-router-dom"; import { Unreads } from "../../../redux/reducers/unreads"; @@ -15,10 +15,11 @@ import { Channel, Servers } from "revolt.js/dist/api/objects"; import { LastOpened } from "../../../redux/reducers/last_opened"; import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice"; import { useIntermediate } from "../../../context/intermediate/Intermediate"; -import { useChannels, useForceUpdate, useServers } from "../../../context/revoltjs/hooks"; +import { useChannels, useForceUpdate, useSelf, useServers } from "../../../context/revoltjs/hooks"; import logoSVG from '../../../assets/logo.svg'; import Tooltip from "../../common/Tooltip"; +import UserIcon from "../../common/user/UserIcon"; function Icon({ children, unread, size }: { children: Children, unread?: 'mention' | 'unread', size: number }) { return ( @@ -81,7 +82,7 @@ const ServerList = styled.div` } `; -const ServerEntry = styled.div<{ active: boolean, invert?: boolean }>` +const ServerEntry = styled.div<{ active: boolean, home?: boolean }>` height: 58px; display: flex; align-items: center; @@ -91,7 +92,7 @@ const ServerEntry = styled.div<{ active: boolean, invert?: boolean }>` // outline: 1px solid red; } - > div, > svg { + > div { width: 46px; height: 46px; display: grid; @@ -139,10 +140,8 @@ const ServerEntry = styled.div<{ active: boolean, invert?: boolean }>` ` } } - ${ props => props.active && props.invert && css` - img { - filter: saturate(0) brightness(10); - } + ${ props => (!props.active || props.home) && css` + cursor: pointer; ` } `; @@ -153,6 +152,7 @@ interface Props { export function ServerListSidebar({ unreads, lastOpened }: Props) { const ctx = useForceUpdate(); + const self = useSelf(ctx); const activeServers = useServers(undefined, ctx) as Servers.Server[]; const channels = (useChannels(undefined, ctx) as Channel[]) .map(x => mapChannelWithUnread(x, unreads)); @@ -199,10 +199,13 @@ export function ServerListSidebar({ unreads, lastOpened }: Props) { <ServersBase> <ServerList> <ConditionalLink active={homeActive} to={lastOpened.home ? `/channel/${lastOpened.home}` : '/'}> - <ServerEntry invert active={homeActive}> - <Icon size={42} unread={homeUnread}> - <img style={{ width: 32, height: 32 }} src={logoSVG} /> - </Icon> + <ServerEntry home active={homeActive}> + <div onContextMenu={attachContextMenu('Status')} + onClick={() => homeActive && openContextMenu("Status")}> + <Icon size={42} unread={homeUnread}> + <UserIcon target={self} size={32} status /> + </Icon> + </div> <span /> </ServerEntry> </ConditionalLink> diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx index c1844451d154302c7591cf3c59ceb46161baaadd..265ca804c64043b85f9aa79fdc25c211601ee304 100644 --- a/src/lib/ContextMenus.tsx +++ b/src/lib/ContextMenus.tsx @@ -19,8 +19,12 @@ import { Children } from "../types/Preact"; import LineDivider from "../components/ui/LineDivider"; import { connectState } from "../redux/connector"; import { internalEmit } from "./eventEmitter"; -import { At, Bell, BellOff, Check, CheckSquare, ChevronRight, Block, Square, LeftArrowAlt } from "@styled-icons/boxicons-regular"; +import { At, Bell, BellOff, Check, CheckSquare, ChevronRight, Block, Square, LeftArrowAlt, Trash } from "@styled-icons/boxicons-regular"; +import { Cog } from "@styled-icons/boxicons-solid"; import { getNotificationState, Notifications, NotificationState } from "../redux/reducers/notifications"; +import UserStatus from "../components/common/user/UserStatus"; +import { Link } from "react-router-dom"; +import IconButton from "../components/ui/IconButton"; interface ContextMenuData { user?: string; @@ -72,6 +76,7 @@ type Action = | { action: "leave_server"; target: Servers.Server } | { action: "delete_server"; target: Servers.Server } | { action: "open_notification_options", channel: Channels.Channel } + | { action: "open_settings" } | { action: "open_channel_settings", id: string } | { action: "open_server_settings", id: string } | { action: "open_server_channel_settings", server: string, id: string } @@ -315,6 +320,7 @@ function ContextMenus(props: Props) { break; } + case "open_settings": history.push('/settings'); break; case "open_channel_settings": history.push(`/channel/${data.id}/settings`); break; case "open_server_channel_settings": history.push(`/server/${data.server}/channel/${data.id}/settings`); break; case "open_server_settings": history.push(`/server/${data.id}/settings`); break; @@ -641,62 +647,75 @@ function ContextMenus(props: Props) { return elements; }} </ContextMenuWithData> - <ContextMenu id="Status" onClose={contextClick}> - <span data-disabled={true}>@{client.user?.username}</span> - <LineDivider /> - <MenuItem - data={{ - action: "set_presence", - presence: Users.Presence.Online - }} - disabled={!isOnline} - > - <div className="indicator online" /> - <Text id={`app.status.online`} /> - </MenuItem> - <MenuItem - data={{ - action: "set_presence", - presence: Users.Presence.Idle - }} - disabled={!isOnline} - > - <div className="indicator idle" /> - <Text id={`app.status.idle`} /> - </MenuItem> - <MenuItem - data={{ - action: "set_presence", - presence: Users.Presence.Busy - }} - disabled={!isOnline} - > - <div className="indicator busy" /> - <Text id={`app.status.busy`} /> - </MenuItem> - <MenuItem - data={{ - action: "set_presence", - presence: Users.Presence.Invisible - }} - disabled={!isOnline} - > - <div className="indicator invisible" /> - <Text id={`app.status.invisible`} /> - </MenuItem> - <LineDivider /> - <MenuItem data={{ action: "set_status" }} disabled={!isOnline}> - <Text id={`app.context_menu.custom_status`} /> - </MenuItem> - {client.user?.status?.text && ( + <ContextMenuWithData id="Status" onClose={contextClick} className="Status"> + {() => <> + <div className="header"> + <div className="main"> + <div>@{client.user!.username}</div> + <div className="status"><UserStatus user={client.user!} /></div> + </div> + <IconButton> + <MenuItem data={{ action: "open_settings" }}> + <Cog size={18} /> + </MenuItem> + </IconButton> + </div> + <LineDivider /> + <MenuItem + data={{ + action: "set_presence", + presence: Users.Presence.Online + }} + disabled={!isOnline} + > + <div className="indicator online" /> + <Text id={`app.status.online`} /> + </MenuItem> + <MenuItem + data={{ + action: "set_presence", + presence: Users.Presence.Idle + }} + disabled={!isOnline} + > + <div className="indicator idle" /> + <Text id={`app.status.idle`} /> + </MenuItem> + <MenuItem + data={{ + action: "set_presence", + presence: Users.Presence.Busy + }} + disabled={!isOnline} + > + <div className="indicator busy" /> + <Text id={`app.status.busy`} /> + </MenuItem> <MenuItem - data={{ action: "clear_status" }} + data={{ + action: "set_presence", + presence: Users.Presence.Invisible + }} disabled={!isOnline} > - <Text id={`app.context_menu.clear_status`} /> + <div className="indicator invisible" /> + <Text id={`app.status.invisible`} /> </MenuItem> - )} - </ContextMenu> + <LineDivider /> + <div className="header"> + <div className="main"> + <MenuItem data={{ action: "set_status" }} disabled={!isOnline}> + <Text id={`app.context_menu.custom_status`} /> + </MenuItem> + </div> + { client.user!.status?.text && <IconButton> + <MenuItem data={{ action: "clear_status" }}> + <Trash size={18} /> + </MenuItem> + </IconButton> } + </div> + </>} + </ContextMenuWithData> <ContextMenuWithData id="NotificationOptions" onClose={contextClick}> {({ channel }: { channel: Channels.Channel }) => { const state = props.notifications[channel._id]; diff --git a/src/styles/_context-menu.scss b/src/styles/_context-menu.scss index 159efac95cd6cdd7ae3bf4da89b390a46395cf07..a90e99e4b41893ba7d4924dc72221e49f5c2ba6f 100644 --- a/src/styles/_context-menu.scss +++ b/src/styles/_context-menu.scss @@ -4,17 +4,17 @@ padding: 6px 8px; user-select: none; border-radius: 4px; + font-size: .875rem; color: var(--secondary-foreground); background: var(--primary-background) !important; box-shadow: 0px 0px 8px 8px rgba(0, 0, 0, 0.05); - > span { + > span, .main > span { gap: 6px; margin: 2px 0; display: flex; padding: 6px 8px; border-radius: 3px; - font-size: .875rem; align-items: center; white-space: nowrap; @@ -33,6 +33,27 @@ color: var(--tertiary-foreground); } } +} + +.context-menu.Status { + .header { + gap: 8px; + display: flex; + padding: 6px 8px; + font-weight: 600; + align-items: center; + color: var(--foreground); + + .main { + flex-grow: 1; + display: flex; + flex-direction: column; + } + + .status { + font-size: .6rem; + } + } .indicator { width: 8px;