tweaking layout of channel and card list

This commit is contained in:
Roland Osborne 2022-08-12 19:07:58 -07:00
parent 22f3cc1612
commit 067422cfaf
12 changed files with 190 additions and 118 deletions

View File

@ -11,6 +11,7 @@ const Colors = {
alert: '#ff8888', alert: '#ff8888',
enabled: '#444444', enabled: '#444444',
disabled: '#aaaaaa', disabled: '#aaaaaa',
text: '#444444',
}; };
export default Colors; export default Colors;

View File

@ -66,7 +66,7 @@ export function Session() {
)} )}
{ state.cards && ( { state.cards && (
<div class="reframe"> <div class="reframe">
<Cards /> <Cards close={actions.closeCards} />
</div> </div>
)} )}
</div> </div>
@ -94,7 +94,7 @@ export function Session() {
</Drawer> </Drawer>
<Drawer bodyStyle={{ padding: 0 }} width={'33%'} closable={false} onClose={actions.closeCards} visible={state.cards} zIndex={20}> <Drawer bodyStyle={{ padding: 0 }} width={'33%'} closable={false} onClose={actions.closeCards} visible={state.cards} zIndex={20}>
{ state.cards && ( { state.cards && (
<Cards /> <Cards close={actions.closeCards} />
)} )}
<Drawer bodyStyle={{ padding: 0 }} width={'33%'} closable={false} onClose={actions.closeContact} visible={state.contact} zIndex={30}> <Drawer bodyStyle={{ padding: 0 }} width={'33%'} closable={false} onClose={actions.closeContact} visible={state.contact} zIndex={30}>
{ state.contact && ( { state.contact && (
@ -128,7 +128,7 @@ export function Session() {
)} )}
{ state.cards && ( { state.cards && (
<div class="reframe"> <div class="reframe">
<Cards /> <Cards close={actions.closeCards} />
</div> </div>
)} )}
{ state.contact && ( { state.contact && (

View File

@ -1,10 +1,10 @@
import { Input, List } from 'antd'; import { Input, List } from 'antd';
import { CardsWrapper } from './Cards.styled'; import { CardsWrapper } from './Cards.styled';
import { SearchOutlined } from '@ant-design/icons'; import { RightOutlined, UserOutlined, SearchOutlined } from '@ant-design/icons';
import { useCards } from './useCards.hook'; import { useCards } from './useCards.hook';
import { CardItem } from './cardItem/CardItem'; import { CardItem } from './cardItem/CardItem';
export function Cards() { export function Cards({ close }) {
const { state, actions } = useCards(); const { state, actions } = useCards();
@ -16,12 +16,35 @@ export function Cards() {
<Input bordered={false} allowClear={true} placeholder="Contacts" prefix={<SearchOutlined />} <Input bordered={false} allowClear={true} placeholder="Contacts" prefix={<SearchOutlined />}
size="large" spellCheck="false" onChange={(e) => actions.onFilter(e.target.value)} /> size="large" spellCheck="false" onChange={(e) => actions.onFilter(e.target.value)} />
</div> </div>
{ state.display === 'small' && (
<div class="inline">
<div class="add">
<UserOutlined />
<div class="label">New</div>
</div>
</div>
)}
{ state.display !== 'small' && (
<div class="inline">
<div class="dismiss" onClick={close} >
<RightOutlined />
</div>
</div>
)}
</div> </div>
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.cards} gutter="0" <List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.cards} gutter="0"
renderItem={item => ( renderItem={item => (
<CardItem item={item} /> <CardItem item={item} />
)} /> )} />
</div> </div>
{ state.display !== 'small' && (
<div class="bar">
<div class="add">
<UserOutlined />
<div class="label">New Contact</div>
</div>
</div>
)}
</CardsWrapper> </CardsWrapper>
); );
} }

View File

@ -0,0 +1,81 @@
import styled from 'styled-components';
import Colors from 'constants/Colors';
export const CardsWrapper = styled.div`
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
background-color: ${Colors.formFocus};
.view {
min-height: 0;
overflow: scroll;
flex-grow: 1;
.search {
padding: 16px;
border-bottom: 1px solid ${Colors.divider};
display: flex;
flex-direction: row;
.filter {
border: 1px solid ${Colors.divider};
background-color: ${Colors.white};
border-radius: 8px;
flex-grow: 1;
}
.inline {
padding-left: 8px;
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
flex-direction: row;
align-items: center;
justify-content: center;
}
.dismiss {
font-size: 18px;
color: ${Colors.text};
cursor: pointer;
}
}
}
.bar {
height: 64px;
width: 100%;
display: flex;
flex-shrink: 0;
flex-direction: row;
align-items: center;
justify-content: center;
background-color: ${Colors.formBackground};
border-top: 2px solid ${Colors.divider};
padding-bottom: 16px;
padding-top: 16px;
position: relative;
}
.add {
display: flex;
flex-direction: row;
background-color: ${Colors.primary};
color: ${Colors.white};
align-items: center;
justify-content: center;
padding-left: 16px;
padding-right: 16px;
border-radius: 4px;
font-size: 18px;
cursor: pointer;
height: 100%;
.label {
padding-left: 8px;
}
}
`;

View File

@ -1,16 +1,19 @@
import { useContext, useState, useEffect } from 'react'; import { useContext, useState, useEffect } from 'react';
import { CardContext } from 'context/CardContext'; import { CardContext } from 'context/CardContext';
import { ViewportContext } from 'context/ViewportContext';
export function useCards() { export function useCards() {
const [filter, setFilter] = useState(null); const [filter, setFilter] = useState(null);
const [state, setState] = useState({ const [state, setState] = useState({
display: null,
cards: [], cards: [],
busy: false } busy: false }
); );
const card = useContext(CardContext); const card = useContext(CardContext);
const viewport = useContext(ViewportContext);
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })); setState((s) => ({ ...s, ...value }));
@ -25,5 +28,9 @@ export function useCards() {
useEffect(() => { useEffect(() => {
}, [card]); }, [card]);
useEffect(() => {
updateState({ display: viewport.state.display });
}, [viewport]);
return { state, actions }; return { state, actions };
} }

View File

@ -1,9 +1,8 @@
import { Input, List } from 'antd'; import { Input, List } from 'antd';
import { ChannelsWrapper } from './Channels.styled'; import { ChannelsWrapper } from './Channels.styled';
import { SearchOutlined } from '@ant-design/icons'; import { CommentOutlined, SearchOutlined } from '@ant-design/icons';
import { useChannels } from './useChannels.hook'; import { useChannels } from './useChannels.hook';
import { ChannelItem } from './channelItem/ChannelItem'; import { ChannelItem } from './channelItem/ChannelItem';
import { AddTopic } from './addTopic/AddTopic';
export function Channels() { export function Channels() {
@ -17,6 +16,14 @@ export function Channels() {
<Input bordered={false} allowClear={true} placeholder="Channels" prefix={<SearchOutlined />} <Input bordered={false} allowClear={true} placeholder="Channels" prefix={<SearchOutlined />}
size="large" spellCheck="false" onChange={(e) => actions.onFilter(e.target.value)} /> size="large" spellCheck="false" onChange={(e) => actions.onFilter(e.target.value)} />
</div> </div>
{ state.display === 'small' && (
<div class="inline">
<div class="add">
<CommentOutlined />
<div class="label">New</div>
</div>
</div>
)}
</div> </div>
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.channels} gutter="0" <List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.channels} gutter="0"
renderItem={item => ( renderItem={item => (
@ -24,7 +31,14 @@ export function Channels() {
)} )}
/> />
</div> </div>
<AddTopic /> { state.display !== 'small' && (
<div class="bar">
<div class="add">
<CommentOutlined />
<div class="label">New Channel</div>
</div>
</div>
)}
</ChannelsWrapper> </ChannelsWrapper>
); );
} }

View File

@ -16,12 +16,60 @@ export const ChannelsWrapper = styled.div`
.search { .search {
padding: 16px; padding: 16px;
border-bottom: 1px solid ${Colors.divider}; border-bottom: 1px solid ${Colors.divider};
display: flex;
flex-direction: row;
.filter { .filter {
border: 1px solid ${Colors.divider}; border: 1px solid ${Colors.divider};
background-color: ${Colors.white}; background-color: ${Colors.white};
border-radius: 8px; border-radius: 8px;
flex-grow: 1;
}
.inline {
padding-left: 8px;
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
flex-direction: row;
align-items: center;
justify-content: center;
} }
} }
} }
.bar {
height: 64px;
width: 100%;
display: flex;
flex-shrink: 0;
flex-direction: row;
align-items: center;
justify-content: center;
background-color: ${Colors.formBackground};
border-top: 2px solid ${Colors.divider};
padding-bottom: 16px;
padding-top: 16px;
position: relative;
}
.add {
display: flex;
flex-direction: row;
background-color: ${Colors.primary};
color: ${Colors.white};
align-items: center;
justify-content: center;
padding-left: 16px;
padding-right: 16px;
border-radius: 4px;
font-size: 18px;
cursor: pointer;
height: 100%;
.label {
padding-left: 8px;
}
}
`; `;

View File

@ -1,25 +0,0 @@
import { AddTopicWrapper } from './AddTopic.styled';
import { CommentOutlined } from '@ant-design/icons';
import { useAddTopic } from './useAddTopic.hook';
export function AddTopic() {
const { state, actions } = useAddTopic();
return (
<AddTopicWrapper>
{ state.mode === 'bar' && (
<div class="bar">
<div class="add">
<CommentOutlined />
<div class="label">New Channel</div>
</div>
</div>
)}
{ state.mode === 'button' && (
<div class="button">New Channel</div>
)}
</AddTopicWrapper>
);
}

View File

@ -1,53 +0,0 @@
import styled from 'styled-components';
import Colors from 'constants/Colors';
export const AddTopicWrapper = styled.div`
background-color: ${Colors.formBackground};
.button {
position: absolute;
bottom: 32px;
right: 32px;
padding-left: 8px;
padding-right: 8px;
padding-top: 4px;
padding-bottom: 4px;
background-color: ${Colors.primary};
color: ${Colors.white};
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
}
.bar {
height: 64px;
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
background-color: ${Colors.formBackground};
border-top: 2px solid ${Colors.divider};
.add {
display: flex;
flex-direction: row;
background-color: ${Colors.primary};
color: ${Colors.white};
align-items: center;
justify-content: center;
padding-left: 16px;
padding-right: 16px;
border-radius: 4px;
font-size: 18px;
cursor: pointer;
.label {
padding-left: 8px;
}
}
}
`;

View File

@ -1,30 +0,0 @@
import { useState, useEffect, useContext } from 'react';
import { ViewportContext } from 'context/ViewportContext';
export function useAddTopic() {
const [state, setState] = useState({
mode: null
});
const viewport = useContext(ViewportContext);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
useEffect(() => {
if (viewport.state.display === 'small') {
updateState({ mode: 'button' });
}
else {
updateState({ mode: 'bar' });
}
}, [viewport]);
const actions = {
};
return { state, actions };
}

View File

@ -4,8 +4,6 @@ import { AppstoreFilled, SolutionOutlined } from '@ant-design/icons';
export function ChannelItem({ item }) { export function ChannelItem({ item }) {
console.log(item.contacts);
return ( return (
<ChannelItemWrapper> <ChannelItemWrapper>
{ item.contacts.length === 0 && ( { item.contacts.length === 0 && (

View File

@ -3,12 +3,14 @@ import { StoreContext } from 'context/StoreContext';
import { ChannelContext } from 'context/ChannelContext'; import { ChannelContext } from 'context/ChannelContext';
import { CardContext } from 'context/CardContext'; import { CardContext } from 'context/CardContext';
import { ProfileContext } from 'context/ProfileContext'; import { ProfileContext } from 'context/ProfileContext';
import { ViewportContext } from 'context/ViewportContext';
export function useChannels() { export function useChannels() {
const [filter, setFilter] = useState(null); const [filter, setFilter] = useState(null);
const [state, setState] = useState({ const [state, setState] = useState({
display: null,
channels: [], channels: [],
busy: false } busy: false }
); );
@ -17,6 +19,7 @@ export function useChannels() {
const channel = useContext(ChannelContext); const channel = useContext(ChannelContext);
const store = useContext(StoreContext); const store = useContext(StoreContext);
const profile = useContext(ProfileContext); const profile = useContext(ProfileContext);
const viewport = useContext(ViewportContext);
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })); setState((s) => ({ ...s, ...value }));
@ -130,5 +133,10 @@ export function useChannels() {
}, [channel, card, store, filter]); }, [channel, card, store, filter]);
useEffect(() => {
console.log(viewport.state);
updateState({ display: viewport.state.display });
}, [viewport]);
return { state, actions }; return { state, actions };
} }