Commit bfce90c5 authored by insert's avatar insert

Fix sidebar and work on messages.

parent 95b3f310
Pipeline #276 passed with stage
in 1 minute and 55 seconds
import React, { createContext, useState, memo, useEffect } from 'react';
import React, { createContext, useState, memo } from 'react';
import Helmet from 'react-helmet';
import styles from './Chat.module.scss';
......@@ -23,11 +23,13 @@ export const ChatContext = createContext<{
page: Page,
setPage: (page: Page) => void,
channel?: string,
setChannel: (channel: string) => void
setChannel: (channel: string) => void,
setDrawer: (open: boolean) => void
}>({
page: Page.HOME,
setPage: () => {},
setChannel: () => {}
setChannel: () => {},
setDrawer: () => {}
});
const Chat = memo(() => {
......@@ -35,20 +37,22 @@ const Chat = memo(() => {
let [ channel, setChannel ] = useState<string>();
let [ drawer, setDrawer ] = useState(false);
useEffect(() => setDrawer(false), [page, channel]);
let states = {
page, setPage,
channel, setChannel
channel, setChannel,
setDrawer
} as any;
let body;
if (page & 0x7) {
// display a channel
body = <Channel id={channel as string} />;
} else {
// other things
body = <div>other things yes</div>;
} else if (page & Page.HOME) {
body = <div>home-y</div>;
} else if (page & Page.FEED) {
body = <div>feedy</div>;
} else if (page & Page.FRIENDS) {
body = <div>you have no friends lol</div>;
}
return (
......@@ -57,12 +61,14 @@ const Chat = memo(() => {
<meta name="theme-color" content="#333234"/>
</Helmet>
<div className={styles.chat}>
<SwipeableDrawer className={styles.sidebar} open={drawer}
onChange={setDrawer} closeOnOpacityClick={true}>
<Browser />
<div className={styles.conversation}>
{ page ? <HomeSidebar /> : <GuildSidebar /> }
<Profile />
<SwipeableDrawer open={drawer} onChange={setDrawer}
closeOnOpacityClick={true} variant='permanent'>
<div className={styles.sidebar}>
<Browser />
<div className={styles.conversation}>
{ page ? <HomeSidebar /> : <GuildSidebar /> }
<Profile />
</div>
</div>
</SwipeableDrawer>
<div className={styles.main}>
......
......@@ -4,9 +4,7 @@
height: 100vh;
color: var(--body-text);
.header {
flex-shrink: 1;
}
.header { flex-shrink: 1; }
.body {
flex-grow: 1;
......@@ -31,7 +29,7 @@
.pending {
opacity: .45;
opacity: .5;
}
}
......
......@@ -9,7 +9,7 @@ import { Message as RMessage } from 'riotchat.js/dist/internal/Message';
import { scrollable, hiddenScrollbar } from '../../components/util/Scrollbar';
import { Input } from '../../components/ui/elements/Input';
import Header from './channel/Header';
import Message from './channel/Message';
import MessageList from './channel/MessageList';
export const ChannelContext = createContext<RChannel | undefined>(undefined);
......@@ -65,9 +65,10 @@ export default function Channel(props: { id: string }) {
<div className={styles.body}>
<div className={styles.chat}>
<div className={classNames(styles.messages, scrollable)}>
{ messages.map(m => <Message message={m} />) }
<MessageList messages={messages} />
<div style={{ float: 'left', clear: 'both' }}
ref={e => e && e.scrollIntoView()}></div>
ref={e => e && e.scrollIntoView()}>
</div>
</div>
<div className={styles.messageBox}>
<form onSubmit={sendMessage}>
......
......@@ -18,10 +18,7 @@
cursor: pointer;
@media only screen and (max-width: 900px) {display: flex;}
svg {
width: 28px;
height: 28px;
}
svg { width: 28px; height: 28px; }
}
.channel {
......@@ -33,17 +30,22 @@
.title {
font-size: .875rem;
font-weight: 600;
@media only screen and (max-width: 900px) {font-size: 1rem;}
}
.dropdown { margin: 0 4px; cursor: pointer; }
.dropdown {
margin: 0 4px;
svg {
cursor: pointer;
}
}
.divider {
width: 1px;
height: 20px;
margin: 0 12px;
//flex: 0 0 auto;
flex: 0 0 auto;
border-radius: 60px;
//box-sizing: border-box;
background: var(--divider);
}
......@@ -65,9 +67,7 @@
&.away { background-color: var(--yellow); }
&.busy { background-color: var(--red); }
@media only screen and (max-width: 900px) {
display: flex;
}
@media only screen and (max-width: 900px) { display: flex; }
}
}
......
import React, { useContext, Fragment } from 'react';
import styles from './Header.module.scss';
import classNames from 'classnames';
import { ChannelContext } from '../Channel';
import { Channel } from 'riotchat.js';
import { Icon, Icons } from '../../../components/ui/elements/Icon';
import { DMChannel, GroupChannel } from 'riotchat.js/dist/internal/Channel';
import { ChatContext } from '../../Chat';
export default function Header() {
let chat = useContext(ChatContext);
let channel = useContext(ChannelContext) as Channel;
let title, icon: Icons, description;
if (channel instanceof DMChannel) {
title = channel.recipient.username;
......@@ -24,10 +28,10 @@ export default function Header() {
return (
<div className={styles.header}>
<div className={styles.info}>
<div className={styles.hamburger}><Icon icon="menuRegular"/></div>
<div className={styles.hamburger} onClick={() => chat.setDrawer(true)}><Icon icon="menuRegular"/></div>
<Icon className={styles.channel} icon={icon} />
<div className={styles.title}>{title}</div>
{ channel instanceof DMChannel && <div className={styles.indicator}/> }
{ channel instanceof DMChannel && <div className={classNames(styles.indicator, styles[channel.recipient.status])}/> }
{ channel instanceof GroupChannel && <div className={styles.dropdown}><Icon icon="chevronDownRegular"/></div> }
{ description && <Fragment>
<div className={styles.divider}/>
......
.message {
display: flex;
.author {
flex-shrink: 1;
img {
width: 40px;
height: 40px;
border-radius: 50%;
}
}
.content {
flex-grow: 1;
}
}
\ No newline at end of file
import React, { memo } from 'react';
import styles from './Message.module.scss';
import { Message as RMessage } from 'riotchat.js/dist/internal/Message';
const Message = memo((props: { message: RMessage }) => {
let msg = props.message;
return (
<div className={styles.message}>
<div className={styles.author}>
<img alt={msg.author.username} src={msg.author.avatarURL} />
</div>
<div className={styles.content}>
<b>{msg.author.username}</b>
<p>{msg.content}</p>
</div>
</div>
);
});
export default Message;
\ No newline at end of file
.message {
display: flex;
margin: 25px 0;
overflow: hidden;
.avatar {
flex: 0 0 auto;
background-size: cover;
background-position: center;
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 20px;
background-color: grey;
cursor: pointer;
}
.content {
flex-grow: 1;
display: flex;
flex-direction: column;
font-size: 0.875rem;
color: var(--body-text);
.header {
margin-bottom: 2px;
.username {
font-size: 1rem;
font-weight: 600;
padding-right: 6px;
cursor: pointer;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--username);
}
time {
display: inline;
word-break: none;
font-weight: 400;
color: #808080;
font-size: 0.75rem;
}
}
}
}
\ No newline at end of file
import React, { Fragment, memo } from 'react';
import styles from './MessageList.module.scss';
import moment from 'moment';
import { Message as RMessage } from 'riotchat.js/dist/internal/Message';
function isDifferentDay(a: Date, b: Date) {
return a.getDate() !== b.getDate();
}
function diffMinutes(a: Date, b: Date) {
var diff = (a.getTime() - b.getTime()) / 1000;
diff /= 60;
return Math.abs(Math.round(diff));
}
const MessageList = memo((props: { messages: RMessage[] }) => {
if (props.messages.length === 0)
return <Fragment />;
let index: RMessage[][][] = [[[]]];
props.messages.forEach(msg => {
let day = index[index.length - 1];
let separator = day[day.length - 1];
let last = separator[separator.length - 1];
if (!last) {
separator.push(msg);
} else {
if (isDifferentDay(msg.createdAt, last.createdAt)) {
index.push([[ msg ]]);
} if (diffMinutes(msg.createdAt, last.createdAt) > 10
|| msg.author !== last.author) {
day.push([ msg ]);
} else {
separator.push(msg);
}
}
});
return <Fragment>
{
index.map(day => <Fragment>
<div className={styles.separator}>
<div className={styles.bar}/>
<div className={styles.text}>{day[0][0].createdAt.getDate()}</div>
<div className={styles.bar}/>
</div>
{ day.map(group =>
<div className={styles.message}>
<div className={styles.avatar} style={{ backgroundImage: `url("${group[0].author.avatarURL}")` }}></div>
<div className={styles.content}>
<div className={styles.header}>
<span className={styles.username}>{group[0].author.username}</span>
<time>{ moment(group[0].createdAt).calendar() }</time>
</div>
{ group.map(x => <div>x.content</div>) }
</div>
</div>
) }
</Fragment>)
}
</Fragment>;
});
export default MessageList;
\ No newline at end of file
......@@ -2,6 +2,7 @@
display: flex;
align-items: center;
flex-direction: column;
flex: 0 0 auto;
width: 80px;
background: var(--primary);
......@@ -26,8 +27,8 @@
cursor: pointer;
transition: .3s;
flex-shrink: 0;
background: var(--home);
&.active {background: var(--home-active); }
span {
......
......@@ -2,7 +2,7 @@
--icon: #EFEFEF;
--unread: #EFEFEF;
--primary: #333234;
--primary: rgba(51, 50, 52, 1); //#333234
--secondary: #212121;
--tertiary: #404040;
......
......@@ -6981,6 +6981,11 @@ [email protected], [email protected], "[email protected]>=0.5 0", [email protected]^0.5.0, [email protected]^0.5.1, mkdi
dependencies:
minimist "0.0.8"
[email protected]^2.24.0:
version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
[email protected]^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment