initial commit

This commit is contained in:
unknown
2021-07-28 18:45:52 +05:30
commit 026f835a87
176 changed files with 10613 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
import React, { useState, useEffect } from 'react';
import './Channel.scss';
import cons from '../../../client/state/cons';
import navigation from '../../../client/state/navigation';
import Welcome from '../welcome/Welcome';
import ChannelView from './ChannelView';
import PeopleDrawer from './PeopleDrawer';
function Channel() {
const [selectedRoomId, changeSelectedRoomId] = useState(null);
const [isDrawerVisible, toggleDrawerVisiblity] = useState(navigation.isPeopleDrawerVisible);
useEffect(() => {
const handleRoomSelected = (roomId) => {
changeSelectedRoomId(roomId);
};
const handleDrawerToggling = (visiblity) => {
toggleDrawerVisiblity(visiblity);
};
navigation.on(cons.events.navigation.ROOM_SELECTED, handleRoomSelected);
navigation.on(cons.events.navigation.PEOPLE_DRAWER_TOGGLED, handleDrawerToggling);
return () => {
navigation.removeListener(cons.events.navigation.ROOM_SELECTED, handleRoomSelected);
navigation.removeListener(cons.events.navigation.PEOPLE_DRAWER_TOGGLED, handleDrawerToggling);
};
}, []);
if (selectedRoomId === null) return <Welcome />;
return (
<div className="channel-container">
<ChannelView roomId={selectedRoomId} />
{ isDrawerVisible && <PeopleDrawer roomId={selectedRoomId} />}
</div>
);
}
export default Channel;

View File

@@ -0,0 +1,4 @@
.channel-container {
display: flex;
height: 100%;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,248 @@
.channel-view-flexBox {
display: flex;
flex-direction: column;
}
.channel-view-flexItem {
flex: 1;
min-height: 0;
min-width: 0;
}
.channel-view {
@extend .channel-view-flexItem;
@extend .channel-view-flexBox;
&__content-wrapper {
@extend .channel-view-flexItem;
@extend .channel-view-flexBox;
}
&__scrollable {
@extend .channel-view-flexItem;
position: relative;
}
&__content {
min-height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-end;
& .timeline__wrapper {
--typing-noti-height: 28px;
min-height: 0;
min-width: 0;
padding-bottom: var(--typing-noti-height);
}
}
&__typing {
display: flex;
padding: var(--sp-ultra-tight) var(--sp-normal);
background: var(--bg-surface);
transition: transform 200ms ease-in-out;
& b {
color: var(--tc-surface-high);
}
&--open {
transform: translateY(-99%);
}
& .text {
flex: 1;
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin: 0 var(--sp-tight);
}
}
.bouncingLoader {
transform: translateY(2px);
margin: 0 calc(var(--sp-ultra-tight) / 2);
}
.bouncingLoader > div,
.bouncingLoader:before,
.bouncingLoader:after {
display: inline-block;
width: 8px;
height: 8px;
background: var(--tc-surface-high);
border-radius: 50%;
animation: bouncing-loader 0.6s infinite alternate;
}
.bouncingLoader:before,
.bouncingLoader:after {
content: "";
}
.bouncingLoader > div {
margin: 0 4px;
}
.bouncingLoader > div {
animation-delay: 0.2s;
}
.bouncingLoader:after {
animation-delay: 0.4s;
}
@keyframes bouncing-loader {
to {
opacity: 0.1;
transform: translate3d(0, -4px, 0);
}
}
&__STB {
position: absolute;
right: var(--sp-normal);
bottom: 0;
border-radius: var(--bo-radius);
box-shadow: var(--bs-surface-border);
background-color: var(--bg-surface-low);
transition: transform 200ms ease-in-out;
transform: translateY(100%) scale(0);
[dir=rtl] & {
right: unset;
left: var(--sp-normal);
}
&--open {
transform: translateY(-28px) scale(1);
}
}
&__sticky {
min-height: 85px;
position: relative;
background: var(--bg-surface);
border-top: 1px solid var(--bg-surface-border);
}
}
.channel-input {
padding: var(--sp-extra-tight) calc(var(--sp-normal) - 2px);
display: flex;
min-height: 48px;
&__space {
min-width: 0;
align-self: center;
margin: auto;
padding: 0 var(--sp-tight);
}
&__input-container {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
margin: 0 calc(var(--sp-tight) - 2px);
background-color: var(--bg-surface-low);
box-shadow: var(--bs-surface-border);
border-radius: var(--bo-radius);
& > .ic-raw {
transform: scale(0.8);
margin-left: var(--sp-extra-tight);
[dir=rtl] & {
margin-left: 0;
margin-right: var(--sp-extra-tight);
}
}
& .scrollbar {
max-height: 50vh;
}
}
&__textarea-wrapper {
min-height: 40px;
display: flex;
align-items: center;
& textarea {
resize: none;
width: 100%;
min-width: 0;
min-height: 100%;
padding: var(--sp-ultra-tight) calc(var(--sp-tight) - 2px);
&::placeholder {
color: var(--tc-surface-low);
}
&:focus {
outline: none;
}
}
}
}
.channel-cmd-bar {
--cmd-bar-height: 28px;
min-height: var(--cmd-bar-height);
& .timeline-change {
justify-content: flex-end;
padding: var(--sp-ultra-tight) var(--sp-normal);
&__content {
margin: 0;
flex: unset;
& > .text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
& b {
color: var(--tc-surface-normal);
}
}
}
}
}
.channel-attachment {
--side-spacing: calc(var(--sp-normal) + var(--av-small) + var(--sp-tight));
display: flex;
align-items: center;
margin-left: var(--side-spacing);
margin-top: var(--sp-extra-tight);
line-height: 0;
[dir=rtl] & {
margin-left: 0;
margin-right: var(--side-spacing);
}
&__preview > img {
max-height: 40px;
border-radius: var(--bo-radius);
}
&__icon {
padding: var(--sp-extra-tight);
background-color: var(--bg-surface-low);
box-shadow: var(--bs-surface-border);
border-radius: var(--bo-radius);
}
&__info {
flex: 1;
min-width: 0;
margin: 0 var(--sp-tight);
}
&__option button {
transition: transform 200ms ease-in-out;
transform: translateY(-48px);
& .ic-raw {
transition: transform 200ms ease-in-out;
transform: rotate(45deg);
background-color: var(--bg-caution);
}
}
}

View File

@@ -0,0 +1,138 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import './PeopleDrawer.scss';
import initMatrix from '../../../client/initMatrix';
import { getUsername } from '../../../util/matrixUtil';
import colorMXID from '../../../util/colorMXID';
import { openInviteUser } from '../../../client/action/navigation';
import Text from '../../atoms/text/Text';
import Header, { TitleWrapper } from '../../atoms/header/Header';
import IconButton from '../../atoms/button/IconButton';
import Button from '../../atoms/button/Button';
import ScrollView from '../../atoms/scroll/ScrollView';
import Input from '../../atoms/input/Input';
import PeopleSelector from '../../molecules/people-selector/PeopleSelector';
import AddUserIC from '../../../../public/res/ic/outlined/add-user.svg';
function getPowerLabel(powerLevel) {
switch (powerLevel) {
case 100:
return 'Admin';
case 50:
return 'Mod';
default:
return null;
}
}
function compare(m1, m2) {
let aName = m1.name;
let bName = m2.name;
// remove "#" from the room name
// To ignore it in sorting
aName = aName.replaceAll('#', '');
bName = bName.replaceAll('#', '');
if (aName.toLowerCase() < bName.toLowerCase()) {
return -1;
}
if (aName.toLowerCase() > bName.toLowerCase()) {
return 1;
}
return 0;
}
function sortByPowerLevel(m1, m2) {
let pl1 = String(m1.powerLevel);
let pl2 = String(m2.powerLevel);
if (pl1 === '100') pl1 = '90.9';
if (pl2 === '100') pl2 = '90.9';
if (pl1.toLowerCase() > pl2.toLowerCase()) {
return -1;
}
if (pl1.toLowerCase() < pl2.toLowerCase()) {
return 1;
}
return 0;
}
function PeopleDrawer({ roomId }) {
const PER_PAGE_MEMBER = 50;
const room = initMatrix.matrixClient.getRoom(roomId);
const totalMemberList = room.getJoinedMembers().sort(compare).sort(sortByPowerLevel);
const [memberList, updateMemberList] = useState([]);
let isRoomChanged = false;
function loadMorePeople() {
updateMemberList(totalMemberList.slice(0, memberList.length + PER_PAGE_MEMBER));
}
useEffect(() => {
updateMemberList(totalMemberList.slice(0, PER_PAGE_MEMBER));
room.loadMembersIfNeeded().then(() => {
if (isRoomChanged) return;
const newTotalMemberList = room.getJoinedMembers().sort(compare).sort(sortByPowerLevel);
updateMemberList(newTotalMemberList.slice(0, PER_PAGE_MEMBER));
});
return () => {
isRoomChanged = true;
};
}, [roomId]);
return (
<div className="people-drawer">
<Header>
<TitleWrapper>
<Text variant="s1">
People
<Text className="people-drawer__member-count" variant="b3">{`${room.getJoinedMemberCount()} members`}</Text>
</Text>
</TitleWrapper>
<IconButton onClick={() => openInviteUser(roomId)} tooltip="Invite" src={AddUserIC} />
</Header>
<div className="people-drawer__content-wrapper">
<div className="people-drawer__scrollable">
<ScrollView autoHide>
<div className="people-drawer__content">
{
memberList.map((member) => (
<PeopleSelector
key={member.userId}
onClick={() => alert('Viewing profile is yet to be implemented')}
avatarSrc={member.getAvatarUrl(initMatrix.matrixClient.baseUrl, 24, 24, 'crop')}
name={getUsername(member.userId)}
color={colorMXID(member.userId)}
peopleRole={getPowerLabel(member.powerLevel)}
/>
))
}
<div className="people-drawer__load-more">
{
memberList.length !== totalMemberList.length && (
<Button onClick={loadMorePeople}>View more</Button>
)
}
</div>
</div>
</ScrollView>
</div>
<div className="people-drawer__sticky">
<form onSubmit={(e) => e.preventDefault()} className="people-search">
<Input type="text" placeholder="Search" required />
</form>
</div>
</div>
</div>
);
}
PeopleDrawer.propTypes = {
roomId: PropTypes.string.isRequired,
};
export default PeopleDrawer;

View File

@@ -0,0 +1,75 @@
.people-drawer-flexBox {
display: flex;
flex-direction: column;
}
.people-drawer-flexItem {
flex: 1;
min-height: 0;
min-width: 0;
}
.people-drawer {
@extend .people-drawer-flexBox;
width: var(--people-drawer-width);
background-color: var(--bg-surface-low);
border-left: 1px solid var(--bg-surface-border);
[dir=rtl] & {
border: {
left: none;
right: 1px solid var(--bg-surface-hover);
}
}
&__member-count {
color: var(--tc-surface-low);
}
&__content-wrapper {
@extend .people-drawer-flexItem;
@extend .people-drawer-flexBox;
}
&__scrollable {
@extend .people-drawer-flexItem;
}
&__sticky {
display: none;
& .people-search {
min-height: 48px;
margin: 0 var(--sp-normal);
position: relative;
bottom: var(--sp-normal);
& .input {
height: 48px;
}
}
}
}
.people-drawer__content {
padding-top: var(--sp-extra-tight);
padding-bottom: calc( var(--sp-extra-tight) + var(--sp-normal));
}
.people-drawer__load-more {
padding: var(--sp-normal);
padding: {
bottom: 0;
right: var(--sp-extra-tight);
}
[dir=rtl] & {
padding-right: var(--sp-normal);
padding-left: var(--sp-extra-tight);
}
& .btn-surface {
width: 100%;
}
}