Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small screen updates for copilot side panel #1230

Merged
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// Copyright (c) Microsoft. All rights reserved.

import { useMsal } from '@azure/msal-react';
import { Text, makeStyles, mergeClasses, Persona, shorthands, tokens } from '@fluentui/react-components';
import { Persona, Text, makeStyles, mergeClasses, shorthands, tokens } from '@fluentui/react-components';
import React from 'react';
import { AuthorRoles, ChatMessageState, IChatMessage } from '../../libs/models/ChatMessage';
import { useChat } from '../../libs/useChat';
import { parsePlan } from '../../libs/utils/PlanUtils';
import { useAppDispatch, useAppSelector } from '../../redux/app/hooks';
import { RootState } from '../../redux/app/store';
import { updateMessageState } from '../../redux/features/conversations/conversationsSlice';
import { Breakpoints } from '../../styles';
import { convertToAnchorTags } from '../utils/TextUtils';
import { PlanViewer } from './plan-viewer/PlanViewer';

Expand All @@ -18,6 +19,9 @@ const useClasses = makeStyles({
flexDirection: 'row',
maxWidth: '75%',
...shorthands.borderRadius(tokens.borderRadiusMedium),
...Breakpoints.small({
maxWidth: '100%',
}),
},
debug: {
position: 'absolute',
Expand All @@ -41,7 +45,7 @@ const useClasses = makeStyles({
time: {
color: tokens.colorNeutralForeground3,
fontSize: '12px',
fontWeight: 400
fontWeight: 400,
},
header: {
position: 'relative',
Expand Down Expand Up @@ -158,7 +162,7 @@ export const ChatHistoryItem: React.FC<ChatHistoryItemProps> = ({ message, getRe
return (
<>
<div className={isMe ? mergeClasses(classes.root, classes.alignEnd) : classes.root}>
{!isMe && <Persona className={classes.persona} avatar={avatar} />}
{!isMe && <Persona className={classes.persona} avatar={avatar} presence={{ status: 'available' }} />}
<div className={isMe ? mergeClasses(classes.item, classes.me) : classes.item}>
<div className={classes.header}>
{!isMe && <Text weight="semibold">{fullName}</Text>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { FC } from 'react';
import { isPlan } from '../../../libs/utils/PlanUtils';
import { useAppSelector } from '../../../redux/app/hooks';
import { RootState } from '../../../redux/app/store';
import { Breakpoints } from '../../../styles';
import { ChatListItem } from './ChatListItem';
import { NewBotMenu } from './NewBotMenu';

Expand All @@ -14,6 +15,7 @@ const useClasses = makeStyles({
...shorthands.overflow('hidden'),
display: 'flex',
width: '25%',
minWidth: '5rem',
backgroundColor: '#F0F0F0',
flexDirection: 'column',
'@media (max-width: 25%)': {
Expand All @@ -33,6 +35,7 @@ const useClasses = makeStyles({
'&::-webkit-scrollbar-track': {
backgroundColor: 'transparent',
},
alignItems: 'stretch',
},
header: {
...shorthands.padding(tokens.spacingVerticalXXS, tokens.spacingHorizontalXS),
Expand All @@ -43,6 +46,14 @@ const useClasses = makeStyles({
marginLeft: '1em',
alignItems: 'center',
height: '4.8em',
...Breakpoints.small({
justifyContent: 'center',
}),
},
title: {
...Breakpoints.small({
display: 'none',
}),
},
});

Expand All @@ -53,7 +64,7 @@ export const ChatList: FC = () => {
return (
<div className={classes.root}>
<div className={classes.header}>
<Text weight="bold" size={500}>
<Text weight="bold" size={500} className={classes.title}>
Conversations
</Text>
<NewBotMenu />
Expand All @@ -63,14 +74,17 @@ export const ChatList: FC = () => {
const convo = conversations[id];
const messages = convo.messages;
const lastMessage = convo.messages.length - 1;
const isSelected = id === selectedId;

return (
<TreeItem
key={id}
leaf
style={id === selectedId ? { background: tokens.colorNeutralBackground1 } : undefined}
style={isSelected ? { background: tokens.colorNeutralBackground1 } : undefined}
>
<ChatListItem
id={id}
isSelected={isSelected}
header={convo.title}
timestamp={convo.lastUpdatedTimestamp ?? messages[lastMessage].timestamp}
preview={
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { Avatar, makeStyles, shorthands, Text } from '@fluentui/react-components';
import {
makeStyles,
Persona,
Popover,
PopoverSurface,
PopoverTrigger,
shorthands,
Text,
} from '@fluentui/react-components';
import { FC } from 'react';
import { Constants } from '../../../Constants';
import { useAppDispatch } from '../../../redux/app/hooks';
import { setSelectedConversation } from '../../../redux/features/conversations/conversationsSlice';
import { Breakpoints } from '../../../styles';

const useClasses = makeStyles({
root: {
Expand All @@ -11,6 +21,9 @@ const useClasses = makeStyles({
paddingBottom: '0.8rem',
paddingRight: '1rem',
width: '93%',
...Breakpoints.small({
justifyContent: 'center',
}),
},
avatar: {
flexShrink: '0',
Expand All @@ -23,6 +36,9 @@ const useClasses = makeStyles({
flexGrow: '1',
lineHeight: '1.6rem',
paddingLeft: '0.8rem',
...Breakpoints.small({
display: 'none',
}),
},
header: {
display: 'flex',
Expand Down Expand Up @@ -56,6 +72,13 @@ const useClasses = makeStyles({
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
},
popoverSurface: {
display: 'none',
...Breakpoints.small({
display: 'flex',
flexDirection: 'column',
}),
},
});

interface IChatListItemProps {
Expand All @@ -64,9 +87,17 @@ interface IChatListItemProps {
timestamp: number;
preview: string;
botProfilePicture: string;
isSelected: boolean;
}

export const ChatListItem: FC<IChatListItemProps> = ({ id, header, timestamp, preview, botProfilePicture }) => {
export const ChatListItem: FC<IChatListItemProps> = ({
id,
header,
timestamp,
preview,
botProfilePicture,
isSelected,
}) => {
const classes = useClasses();
const dispatch = useAppDispatch();

Expand All @@ -89,27 +120,42 @@ export const ChatListItem: FC<IChatListItemProps> = ({ id, header, timestamp, pr
}

return (
<div className={classes.root} onClick={onClick}>
<Avatar image={{ src: botProfilePicture }} />
<div className={classes.body}>
<div className={classes.header}>
<Text className={classes.title} style={{ color: 'var(--colorNeutralForeground1)' }}>
{header}
</Text>
<Text className={classes.timestamp} size={300}>
{time}
</Text>
</div>
{preview && (
<div className={classes.preview}>
{
<Text id={`message-preview-${id}`} size={200} className={classes.previewText}>
{preview}
<Popover
openOnHover={!isSelected}
mouseLeaveDelay={0}
positioning={{
position: 'after',
autoSize: 'width',
}}
>
<PopoverTrigger disableButtonEnhancement>
<div className={classes.root} onClick={onClick}>
<Persona avatar={{ image: { src: botProfilePicture } }} presence={{ status: 'available' }} />
<div className={classes.body}>
<div className={classes.header}>
<Text className={classes.title} style={{ color: 'var(--colorNeutralForeground1)' }}>
{header}
</Text>
}
<Text className={classes.timestamp} size={300}>
{time}
</Text>
</div>
{preview && (
<div className={classes.preview}>
{
<Text id={`message-preview-${id}`} size={200} className={classes.previewText}>
{preview}
</Text>
}
</div>
)}
</div>
)}
</div>
</div>
</div>
</PopoverTrigger>
<PopoverSurface className={classes.popoverSurface}>
<Text weight="bold">{Constants.bot.profile.fullName}</Text>
<Text>{time}</Text>
</PopoverSurface>
</Popover>
);
};
8 changes: 8 additions & 0 deletions samples/apps/copilot-chat-app/webapp/src/styles.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { GriffelStyle } from '@fluentui/react-components';

export const CopilotChatTokens = {
backgroundColor: '#9c2153',
titleColor: '#943670',
};

export const Breakpoints = {
small: (style: GriffelStyle): Record<string, GriffelStyle> => {
return { '@media (max-width: 744px)': style };
},
};