adding a card view

This commit is contained in:
Roland Osborne 2024-02-25 09:21:26 -08:00
parent 18127e2442
commit 330b98f835
10 changed files with 98 additions and 81 deletions

View File

@ -10,6 +10,7 @@ export const en = {
ok: 'OK', ok: 'OK',
cancel: 'Cancel', cancel: 'Cancel',
new: 'New',
newMessage: 'New Message', newMessage: 'New Message',
topics: 'Topics', topics: 'Topics',
unsetSealing: 'Unset Sealing Key', unsetSealing: 'Unset Sealing Key',
@ -33,6 +34,7 @@ export const en = {
operationFailed: 'Operation Failed', operationFailed: 'Operation Failed',
tryAgain: 'Please try again.', tryAgain: 'Please try again.',
add: 'Add',
save: 'Save', save: 'Save',
forget: 'Forget', forget: 'Forget',
unlock: 'Unlock', unlock: 'Unlock',
@ -53,7 +55,7 @@ export const en = {
registry: 'Visible in Registry', registry: 'Visible in Registry',
sealedTopics: 'Sealed Topics', sealedTopics: 'Sealed Topics',
changeLogin: 'Change Login', changeLogin: 'Change Login',
selectImage: 'Select Image', selectImage: 'Select',
profileImage: 'Profile Image', profileImage: 'Profile Image',
profileDetails: 'Profile Details', profileDetails: 'Profile Details',
enableSealed: 'Enabled Sealed Topics', enableSealed: 'Enabled Sealed Topics',
@ -64,6 +66,15 @@ export const en = {
delete: 'delete', delete: 'delete',
username: 'Username', username: 'Username',
updateProfile: 'Update Profile', updateProfile: 'Update Profile',
syncError: 'Sync Error',
callTip: 'Call Contact',
messageTip: 'Message Contact',
connectedTip: 'Connected Contact',
requestedTip: 'Connection Requested by Contact',
connectingTip: 'Connection Requested',
pendingTip: 'Connection Requested by Unknown Contact',
confirmedTip: 'Disconnected Contact',
}; };
export const fr = { export const fr = {
@ -78,6 +89,7 @@ export const fr = {
ok: 'OK', ok: 'OK',
cancel: 'Annuler', cancel: 'Annuler',
new: 'Nouveau',
newMessage: 'Nouveau Message', newMessage: 'Nouveau Message',
topics: 'Sujets', topics: 'Sujets',
unsetSealing: 'Clé de sécurité non définie', unsetSealing: 'Clé de sécurité non définie',
@ -101,6 +113,7 @@ export const fr = {
operationFailed: 'Opération Échouée', operationFailed: 'Opération Échouée',
tryAgain: 'Veuillez réessayer.', tryAgain: 'Veuillez réessayer.',
add: 'Ajouter',
save: 'Enregistrer', save: 'Enregistrer',
forget: 'Oublier', forget: 'Oublier',
unlock: 'Déverrouiller', unlock: 'Déverrouiller',
@ -121,7 +134,7 @@ export const fr = {
registry: 'Visible dans le Registre', registry: 'Visible dans le Registre',
sealedTopics: 'Sujets Sécurisé', sealedTopics: 'Sujets Sécurisé',
changeLogin: 'Changer Identifiants', changeLogin: 'Changer Identifiants',
selectImage: 'Sélectionner une Image', selectImage: 'Sélectionner',
profileImage: 'Image de Profil', profileImage: 'Image de Profil',
profileDetails: 'Détails du Profil', profileDetails: 'Détails du Profil',
enableSealed: 'Activer les Sujets Sécurisé', enableSealed: 'Activer les Sujets Sécurisé',
@ -132,5 +145,14 @@ export const fr = {
delete: 'supprimer', delete: 'supprimer',
username: 'Nom d\'Utilisateur', username: 'Nom d\'Utilisateur',
updateProfile: 'Mettre à Jour le Profil', updateProfile: 'Mettre à Jour le Profil',
syncError: 'Erreur de synchronisation',
callTip: 'Appeler le Contact',
messageTip: 'Envoyer un message au contact',
connectedTip: 'Contact connecté',
requestedTip: 'Demande de connexion envoyée par le contact',
connectingTip: 'Demande de connexion en cours',
pendingTip: 'Demande de connexion envoyée par un contact inconnu',
confirmedTip: 'Contact déconnecté'
}; };

View File

@ -158,7 +158,7 @@ export function Session() {
actions.closeDetails(); actions.closeDetails();
} }
const drawerStyle = { padding: 0, backgroundColor: settings.state.colors.baseArea }; const drawerStyle = { overscrollBehavior: 'none', padding: 0, backgroundColor: settings.state.colors.baseArea };
return ( return (
<ThemeProvider theme={settings.state.colors}> <ThemeProvider theme={settings.state.colors}>

View File

@ -6,7 +6,7 @@ import { useAccount } from './useAccount.hook';
export function Account({ closeAccount, openProfile }) { export function Account({ closeAccount, openProfile }) {
const { state, actions } = useAccount(); const { state } = useAccount();
return ( return (
<AccountWrapper> <AccountWrapper>

View File

@ -17,9 +17,9 @@ export function Cards({ closeCards, openContact, openChannel, openListing }) {
catch (err) { catch (err) {
console.log(err); console.log(err);
modal.error({ modal.error({
title: 'Failed to Create Topic', title: <span style={state.menuStyle}>{state.strings.operationFailed}</span>,
content: 'Please try again.', content: <span style={state.menuStyle}>{state.strings.tryAgain}</span>,
bodyStyle: { padding: 16 }, bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle },
}); });
}; };
}; };
@ -31,9 +31,9 @@ export function Cards({ closeCards, openContact, openChannel, openListing }) {
catch (err) { catch (err) {
console.log(err); console.log(err);
modal.error({ modal.error({
title: 'Failed to Start Call', title: <span style={state.menuStyle}>{state.strings.operationFailed}</span>,
content: 'Please try again.', content: <span style={state.menuStyle}>{state.strings.tryAgain}</span>,
bodyStyle: { padding: 16 }, bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle },
}); });
}; };
}; };
@ -53,11 +53,11 @@ export function Cards({ closeCards, openContact, openChannel, openListing }) {
</div> </div>
)} )}
<div className="filter"> <div className="filter">
<Input bordered={false} allowClear={true} placeholder="Contacts" prefix={<SearchOutlined />} <Input className="filterControl" bordered={false} placeholder={state.strings.contacts} prefix={<SearchOutlined />}
spellCheck="false" onChange={(e) => actions.onFilter(e.target.value)} /> spellCheck="false" onChange={(e) => actions.onFilter(e.target.value)} />
</div> </div>
<div className="inline"> <div className="inline">
<Button type="primary" icon={<UserOutlined />} onClick={openListing}>Add</Button> <Button type="primary" icon={<UserOutlined />} onClick={openListing}>{state.strings.add}</Button>
</div> </div>
{ state.display === 'xlarge' && ( { state.display === 'xlarge' && (
<div className="inline"> <div className="inline">
@ -72,7 +72,7 @@ export function Cards({ closeCards, openContact, openChannel, openListing }) {
<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} enableIce={state.enableIce} tooltip={state.tooltip} resync={() => actions.resync(item.cardId)} <CardItem item={item} enableIce={state.enableIce} tooltip={state.tooltip} resync={() => actions.resync(item.cardId)}
open={() => openContact(item.guid)} message={() => message(item.cardId)} open={() => openContact(item.guid)} message={() => message(item.cardId)} strings={state.strings}
call={() => call(item)} display={state.display} canMessage={state.allowUnsealed || (item.seal && state.sealable)} /> call={() => call(item)} display={state.display} canMessage={state.allowUnsealed || (item.seal && state.sealable)} />
)} /> )} />
)} )}

View File

@ -6,7 +6,8 @@ export const CardsWrapper = styled.div`
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: ${Colors.card}; background-color: ${props => props.theme.itemArea};
color: ${props => props.theme.mainText};
.view { .view {
min-height: 0; min-height: 0;
@ -18,23 +19,48 @@ export const CardsWrapper = styled.div`
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-style: italic; font-style: italic;
color: ${Colors.grey}; color: ${props => props.theme.hintText};
height: 100%; height: 100%;
} }
} }
.search { .search {
border-bottom: 1px solid ${Colors.divider};
display: flex;
flex-direction: row;
height: 48px;
padding-left: 16px;
padding-right: 16px;
padding-top: 8px; padding-top: 8px;
padding-bottom: 8px; padding-bottom: 8px;
padding-left: 16px;
padding-right: 16px;
border-bottom: 1px solid ${props => props.theme.sectionBorder};
display: flex;
flex-direction: row;
.filter {
border: 1px solid ${props => props.theme.sectionBorder};
background-color: ${props => props.theme.inputArea};
border-radius: 8px;
flex-grow: 1;
.filterControl {
color: ${props => props.theme.mainText};
input {
padding-left: 4px;
color: ${props => props.theme.mainText};
}
input::placeholder {
color: ${props => props.theme.placeholderText};
}
}
}
.dismiss {
font-size: 18px;
color: ${props => props.theme.hintText};
cursor: pointer;
}
.sorted { .sorted {
color: ${Colors.enabled}; color: ${props => props.theme.mainText};
font-size: 18px; font-size: 18px;
padding-right: 8px; padding-right: 8px;
display: flex; display: flex;
@ -43,7 +69,7 @@ export const CardsWrapper = styled.div`
} }
.unsorted { .unsorted {
color: ${Colors.disabled}; color: ${props => props.theme.hintText};
font-size: 18px; font-size: 18px;
padding-right: 8px; padding-right: 8px;
display: flex; display: flex;
@ -51,14 +77,6 @@ export const CardsWrapper = styled.div`
cursor: pointer; cursor: pointer;
} }
.filter {
border: 1px solid ${Colors.divider};
background-color: ${Colors.white};
border-radius: 8px;
flex-grow: 1;
}
.inline { .inline {
padding-left: 8px; padding-left: 8px;
display: flex; display: flex;
@ -69,32 +87,10 @@ export const CardsWrapper = styled.div`
align-items: center; align-items: center;
justify-content: center; justify-content: center;
.add { .anticon {
display: flex; color: ${props => props.theme.enabledText};
flex-direction: row;
color: ${Colors.white};
background-color: ${Colors.primary};
align-items: center;
justify-content: center;
padding-left: 16px;
padding-right: 16px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
height: 100%;
flex-shrink: 0;
.label {
padding-left: 8px;
}
} }
} }
.dismiss {
font-size: 18px;
color: ${Colors.text};
cursor: pointer;
}
} }
.bar { .bar {
@ -105,8 +101,8 @@ export const CardsWrapper = styled.div`
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background-color: ${Colors.formBackground}; background-color: ${props => props.theme.enabledArea};
border-top: 1px solid ${Colors.divider}; border-top: 1px solid ${props => props.theme.sectionBorder};
padding-bottom: 12px; padding-bottom: 12px;
padding-top: 12px; padding-top: 12px;
position: relative; position: relative;
@ -114,7 +110,7 @@ export const CardsWrapper = styled.div`
.add { .add {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
color: ${Colors.primary}; color: ${props => props.theme.mainText};
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding-left: 16px; padding-left: 16px;

View File

@ -6,7 +6,7 @@ import { Logo } from 'logo/Logo';
import { Tooltip } from 'antd'; import { Tooltip } from 'antd';
import { MessageOutlined, PhoneOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; import { MessageOutlined, PhoneOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
export function CardItem({ item, tooltip, enableIce, resync, open, call, message, display, canMessage }) { export function CardItem({ item, tooltip, enableIce, resync, open, call, message, display, canMessage, strings }) {
const onResync = (e) => { const onResync = (e) => {
e.stopPropagation(); e.stopPropagation();
@ -31,13 +31,8 @@ export function CardItem({ item, tooltip, enableIce, resync, open, call, message
<div className="handle">{ item.handle }</div> <div className="handle">{ item.handle }</div>
</div> </div>
<div className="markup"> <div className="markup">
{ item.offsync && !item.tooltip && ( { item.offsync && (
<StatusError onClick={onResync}> <Tooltip placement="left" title={strings.syncError}>
<ExclamationCircleOutlined />
</StatusError>
)}
{ item.offsync && item.tooltip && (
<Tooltip placement="left" title="sync error">
<StatusError onClick={onResync}> <StatusError onClick={onResync}>
<ExclamationCircleOutlined /> <ExclamationCircleOutlined />
</StatusError> </StatusError>
@ -60,39 +55,39 @@ export function CardItem({ item, tooltip, enableIce, resync, open, call, message
{ item.status === 'connected' && display !== 'small' && ( { item.status === 'connected' && display !== 'small' && (
<ComOptions> <ComOptions>
{ canMessage && ( { canMessage && (
<Tooltip className="option" placement="left" title="message contact"> <Tooltip className="option" placement="left" title={strings.messageTip}>
<MessageOutlined onClick={onMessage} /> <MessageOutlined onClick={onMessage} />
</Tooltip> </Tooltip>
)} )}
{ enableIce && ( { enableIce && (
<Tooltip className="option" placement="left" title="call contact"> <Tooltip className="option" placement="left" title={strings.callTip}>
<PhoneOutlined onClick={onCall} /> <PhoneOutlined onClick={onCall} />
</Tooltip> </Tooltip>
)} )}
</ComOptions> </ComOptions>
)} )}
{ item.status === 'connected' && ( { item.status === 'connected' && (
<Tooltip placement="left" title="connected contact"> <Tooltip placement="left" title={strings.connectedTip}>
<StatusConnected /> <StatusConnected />
</Tooltip> </Tooltip>
)} )}
{ item.status === 'requested' && ( { item.status === 'requested' && (
<Tooltip placement="left" title="connection requested by contact"> <Tooltip placement="left" title={strings.requestedTip}>
<StatusRequested /> <StatusRequested />
</Tooltip> </Tooltip>
)} )}
{ item.status === 'connecting' && ( { item.status === 'connecting' && (
<Tooltip placement="left" title="requested contact connection"> <Tooltip placement="left" title={strings.connectingTip}>
<StatusConnecting /> <StatusConnecting />
</Tooltip> </Tooltip>
)} )}
{ item.status === 'pending' && ( { item.status === 'pending' && (
<Tooltip placement="left" title="unknwon contact connection request"> <Tooltip placement="left" title={strings.pendingTip}>
<StatusPending /> <StatusPending />
</Tooltip> </Tooltip>
)} )}
{ item.status === 'confirmed' && ( { item.status === 'confirmed' && (
<Tooltip placement="left" title="disconnected contact"> <Tooltip placement="left" title={strings.confirmedTip}>
<StatusConfirmed /> <StatusConfirmed />
</Tooltip> </Tooltip>
)} )}

View File

@ -6,12 +6,13 @@ export const CardItemWrapper = styled.div`
width: 100%; width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
border-bottom: 1px solid ${Colors.divider}; border-bottom: 1px solid ${props => props.theme.itemBorder};
color: ${props => props.theme.mainText};
padding-left: 16px; padding-left: 16px;
padding-right: 16px; padding-right: 16px;
&:hover { &:hover {
background-color: ${Colors.formHover}; background-color: ${props => props.theme.hoverArea};
cursor: pointer; cursor: pointer;
} }
@ -50,13 +51,13 @@ export const CardItemWrapper = styled.div`
`; `;
export const StatusError = styled.div` export const StatusError = styled.div`
color: ${Colors.error}; color: ${props => props.theme.alertText};
font-size: 14px; font-size: 14px;
padding-right: 12px; padding-right: 12px;
` `
export const ComOptions = styled.div` export const ComOptions = styled.div`
color: ${Colors.primary}; color: ${props => props.theme.linkText};
font-size: 16px; font-size: 16px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -17,6 +17,8 @@ export function useCards() {
display: 'small', display: 'small',
enableIce: false, enableIce: false,
sealable: false, sealable: false,
strings: {},
menuStyle: {},
allowUnsealed: false, allowUnsealed: false,
cards: [], cards: [],
}); });
@ -33,8 +35,8 @@ export function useCards() {
} }
useEffect(() => { useEffect(() => {
const { display } = settings.state; const { display, strings, menuStyle } = settings.state;
updateState({ display }); updateState({ display, strings, menuStyle });
}, [settings.state]); }, [settings.state]);
useEffect(() => { useEffect(() => {

View File

@ -18,12 +18,12 @@ export function Channels({ open, active }) {
<ChannelsWrapper> <ChannelsWrapper>
<div className="search"> <div className="search">
<div className="filter"> <div className="filter">
<Input className="filterControl" bordered={false} allowClear={true} placeholder={state.strings.topics} prefix={<SearchOutlined />} <Input className="filterControl" bordered={false} placeholder={state.strings.topics} prefix={<SearchOutlined />}
spellCheck="false" onChange={(e) => actions.onFilter(e.target.value)} /> spellCheck="false" onChange={(e) => actions.onFilter(e.target.value)} />
</div> </div>
{ state.display === 'small' && ( { state.display === 'small' && (
<div className="inline"> <div className="inline">
<Button type="primary" disabled={!state.allowAdd} icon={<CommentOutlined />} onClick={actions.setShowAdd}>New</Button> <Button type="primary" disabled={!state.allowAdd} icon={<CommentOutlined />} onClick={actions.setShowAdd}>{state.strings.new}</Button>
</div> </div>
)} )}
</div> </div>

View File

@ -38,6 +38,7 @@ export const ChannelsWrapper = styled.div`
border-radius: 8px; border-radius: 8px;
flex-grow: 1; flex-grow: 1;
.filterControl { .filterControl {
color: ${props => props.theme.mainText}; color: ${props => props.theme.mainText};