Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions client/components/Breadcrumbs/Breadcrumbs.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';

import Breadcrumbs from '.';

export default {
title: 'components/Breadcrumbs',
component: Breadcrumbs,
};

const { Item, Icon, Text, Link, Separator } = Breadcrumbs;

export const Default = () =>
<Breadcrumbs>
<Item>
<Icon name='lock' />
<Text>design</Text>
</Item>
<Separator/>
<Item>
<Icon name='lock' />
<Text>rc-design</Text>
</Item>
</Breadcrumbs>;

export const AsTeamMember = () =>
<Breadcrumbs>
<Item>
<Icon name='lock' />
<Link>design</Link>
</Item>
<Separator/>
<Item>
<Icon name='lock' />
<Text>rc-design</Text>
</Item>
</Breadcrumbs>;

export const WithDiscussion = () =>
<Breadcrumbs>
<Item>
<Icon name='lock' />
<Text>design</Text>
</Item>
<Separator/>
<Item>
<Icon name='lock' />
<Text>rc-design</Text>
</Item>
<Separator/>
<Item>
<Icon name='baloons' />
<Text>storybook</Text>
</Item>
</Breadcrumbs>;
39 changes: 39 additions & 0 deletions client/components/Breadcrumbs/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { Box, Icon } from '@rocket.chat/fuselage';
import colors from '@rocket.chat/fuselage-tokens/colors';
import { css } from '@rocket.chat/css-in-js';

const BreadcrumbsSeparator = () => <Box display='inline-block' fontScale='s2' mi='x4' fontWeight='600' color='neutral-500'>/</Box>;
const BreadcrumbsIcon = ({ name, color, children }) => <Box w='x20' mi='x2' display='inline-flex' justifyContent='center' color={color}>{name ? <Icon size='x20' name={name}/> : children}</Box>;

const BreadcrumbsLink = (props) => <BreadcrumbsText
is='a'
{...props}
className={[
css`
&:hover,
&:focus{
color: ${ colors.b500 } !important;
}
&:visited{
color: ${ colors.n800 };
}
`,
].filter(Boolean)}
/>;

const BreadcrumbsText = (props) => <Box display='inline' is='span' mi='x2' color='default' {...props} />;

const BreadcrumbsItem = (props) => <Box mi='neg-x2' display='inline-flex' flexDirection='row' alignItems='center' color='info' fontScale='s2' {...props} />;

const Breadcrumbs = ({ children }) => <Box withTruncatedText mie='x2' display='flex' flexDirection='row' alignItems='center'>{children}</Box>;

Object.assign(Breadcrumbs, {
Text: BreadcrumbsText,
Link: BreadcrumbsLink,
Icon: BreadcrumbsIcon,
Separator: BreadcrumbsSeparator,
Item: BreadcrumbsItem,
});

export default Breadcrumbs;
12 changes: 8 additions & 4 deletions client/hooks/useRoomIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,25 @@ export const colors = {
offline: 'neutral-600',
};

export const useRoomIcon = (room: IRoom): JSX.Element | { name: string; color?: string } | null => {
export const useRoomIcon = (room: IRoom, small = true): JSX.Element | { name: string; color?: string } | null => {
if (room.prid) {
return { name: 'baloons' };
}

switch (room.t) {
case 'p':
return { name: 'lock' };
return { name: 'hashtag-lock' };
case 'c':
return { name: 'hash' };
case 'l':
return { name: 'headset', color: colors[(room as unknown as IOmnichannelRoom).v.status] };
case 'd':
const direct = room as unknown as IDirectMessageRoom;
if (direct.uids && direct.uids.length > 2) {
return { name: 'team' };
return { name: 'baloon-arrow-left' };
}
if (direct.uids && direct.uids.length > 0) {
return <ReactiveUserStatus { ...{ small: 'small', uid: direct.uids.filter((uid) => uid !== room.u._id)[0] || room.u._id } as any } />;
return <ReactiveUserStatus { ...{ small, uid: direct.uids.filter((uid) => uid !== room.u._id)[0] || room.u._id } as any } />;
}
return { name: 'at' };
default:
Expand Down
25 changes: 6 additions & 19 deletions client/sidebar/RoomList.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import memoize from 'memoize-one';

import { usePreventDefault } from './hooks/usePreventDefault';
import { filterMarkdown } from '../../app/markdown/lib/markdown';
import { ReactiveUserStatus, colors } from '../components/UserStatus';
import { useTranslation } from '../contexts/TranslationContext';
import { roomTypes } from '../../app/utils';
import { useUserPreference, useUserId } from '../contexts/UserContext';
Expand All @@ -17,6 +16,7 @@ import { useTemplateByViewMode } from './hooks/useTemplateByViewMode';
import { useShortcutOpenMenu } from './hooks/useShortcutOpenMenu';
import { useAvatarTemplate } from './hooks/useAvatarTemplate';
import { useRoomList } from './hooks/useRoomList';
import { useRoomIcon } from '../hooks/useRoomIcon';
import { useSidebarPaletteColor } from './hooks/useSidebarPaletteColor';
import { escapeHTML } from '../../lib/escapeHTML';
import ScrollableContentWrapper from '../components/ScrollableContentWrapper';
Expand All @@ -38,24 +38,11 @@ export const itemSizeMap = (sidebarViewMode) => {
};

const SidebarIcon = ({ room, small }) => {
switch (room.t) {
case 'p':
case 'c':
return <Sidebar.Item.Icon aria-hidden='true' name={roomTypes.getIcon(room)} />;
case 'l':
return <Sidebar.Item.Icon aria-hidden='true' name='headset' color={colors[room.v.status]}/>;
case 'd':
if (room.uids && room.uids.length > 2) {
return <Sidebar.Item.Icon aria-hidden='true' name='team'/>;
}
if (room.uids && room.uids.length > 0) {
// If the filter fn removes all ids, it's own direct message
return room.uids && room.uids.length && <Sidebar.Item.Icon><ReactiveUserStatus small={small && 'small'} uid={room.uids.filter((uid) => uid !== room.u._id)[0] || room.u._id} /></Sidebar.Item.Icon>;
}
return <Sidebar.Item.Icon aria-hidden='true' name={roomTypes.getIcon(room)}/>;
default:
return null;
}
const icon = useRoomIcon(room, small);

return <Sidebar.Item.Icon {...icon.name && icon}>
{!icon.name && icon}
</Sidebar.Item.Icon>;
};

export const createItemData = memoize((extended, t, SideBarItemTemplate, AvatarTemplate, openedRoom, sidebarViewMode, isAnonymous) => ({
Expand Down
44 changes: 29 additions & 15 deletions client/views/room/Header/Header.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import React from 'react';
import { FlowRouter } from 'meteor/kadira:flow-router';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { ActionButton } from '@rocket.chat/fuselage';

import Header from '../../../components/Header';
import Breadcrumbs from '../../../components/Breadcrumbs';
import { useRoomIcon } from '../../../hooks/useRoomIcon';
import Encrypted from './icons/Encrypted';
import Favorite from './icons/Favorite';
Expand All @@ -12,8 +10,9 @@ import ToolBox from './ToolBox';
import RoomAvatar from '../../../components/avatar/RoomAvatar';
import { useLayout } from '../../../contexts/LayoutContext';
import Burger from './Burger';
import { useTranslation } from '../../../contexts/TranslationContext';
import MarkdownText from '../../../components/MarkdownText';
import { roomTypes } from '../../../../app/utils';
import { useUserRoom } from '../../../contexts/UserContext';

export default React.memo(({ room }) => {
const { isEmbedded, showTopNavbarEmbeddedLayout } = useLayout();
Expand All @@ -23,29 +22,44 @@ export default React.memo(({ room }) => {
return <RoomHeader room={room}/>;
});

const BackToRoom = React.memo(({ small, prid }) => {
const t = useTranslation();
const onClick = useMutableCallback(() => {
FlowRouter.goToRoomById(prid);
});
return <ActionButton mie='x4' icon='back' ghost small={small} title={t('Back_to_room')} onClick={onClick}/>;
});
const HeaderIcon = ({ room }) => {
const icon = useRoomIcon(room);

return <Breadcrumbs.Icon name={icon.name}>{!icon.name && icon}</Breadcrumbs.Icon>;
};

const RoomTitle = ({ room }) => {
const prevRoom = useUserRoom(room.prid);
const prevRoomHref = prevRoom ? roomTypes.getRouteLink(prevRoom.t, prevRoom) : null;

return <Breadcrumbs>
{room.prid && prevRoom && <>
<Breadcrumbs.Item>
<HeaderIcon room={prevRoom}/>
<Breadcrumbs.Link href={prevRoomHref}>{prevRoom.name}</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Separator />
</>}
<Breadcrumbs.Item>
<HeaderIcon room={room}/>
<Breadcrumbs.Text>{room.name}</Breadcrumbs.Text>
</Breadcrumbs.Item>
</Breadcrumbs>;
};


const RoomHeader = ({ room }) => {
const icon = useRoomIcon(room);
const { isMobile } = useLayout();
const avatar = <RoomAvatar room={room}/>;

return <Header>
{ (isMobile || room.prid) && <Header.ToolBox>
{ isMobile && <Burger/>}
{ room.prid && <BackToRoom small={!isMobile} prid={room.prid}/>}
</Header.ToolBox> }
{ avatar && <Header.Avatar>{avatar}</Header.Avatar> }
<Header.Content>
<Header.Content.Row>
{ icon && <Header.Icon icon={icon}/> }
<Header.Title>{room.name}</Header.Title>
<RoomTitle room={room}/>
<Favorite room={room} />
<Encrypted room={room} />
<Translate room={room} />
Expand Down
Loading