adding dark mode and translation to thread component

This commit is contained in:
Roland Osborne 2024-03-02 21:29:18 -08:00
parent 71d6598556
commit 3629f30029
11 changed files with 202 additions and 125 deletions

View File

@ -149,6 +149,17 @@ export const en = {
webPassword: 'WebRTC Password', webPassword: 'WebRTC Password',
failedLoad: 'Failed to Load', failedLoad: 'Failed to Load',
limit: 'Limit', limit: 'Limit',
deleteMessage: 'Deleting Message',
messageHint: 'Are you sure you want to delete the message?',
newMessage: 'New Message',
attachImage: 'Attach Image',
attachVideo: 'Attach Video',
attachAudio: 'Attach Audio',
attachFile: 'Attach File',
fontColor: 'Change Font Color',
fontSize: 'Change Font Size',
postMessage: 'Post Message',
}; };
export const fr = { export const fr = {
@ -302,5 +313,16 @@ export const fr = {
webPassword: 'Mot de Passe WebRTC', webPassword: 'Mot de Passe WebRTC',
failedLoad: 'Échec du Chargement', failedLoad: 'Échec du Chargement',
limit: 'Limite', limit: 'Limite',
deleteMessage: 'Suppression du Message',
messageHint: 'Êtes-vous Sûr de Vouloir Supprimer le Message?',
newMessage: 'Nouveau Message',
attachImage: 'Joindre une Image',
attachVideo: 'Joindre une Vidéo',
attachAudio: 'Joindre un Audio',
attachFile: 'Joindre un Fichier',
fontColor: 'Changer la Couleur du Message',
fontSize: 'Changer la Taille du Message',
postMessage: 'Publier le Message',
}; };

View File

@ -18,6 +18,8 @@ export function Conversation({ closeConversation, openDetails, cardId, channelId
remove={() => actions.removeTopic(topic.id)} remove={() => actions.removeTopic(topic.id)}
update={(text) => actions.updateTopic(topic, text)} update={(text) => actions.updateTopic(topic, text)}
sealed={state.sealed && !state.contentKey} sealed={state.sealed && !state.contentKey}
strings={state.strings}
menuStyle={state.menuStyle}
/>) />)
} }
@ -43,9 +45,9 @@ export function Conversation({ closeConversation, openDetails, cardId, channelId
return ( return (
<ConversationWrapper> <ConversationWrapper>
<ChannelHeader openDetails={openDetails} closeConversation={closeConversation} contentKey={state.contentKey}/> <ChannelHeader openDetails={openDetails} closeConversation={closeConversation} contentKey={state.contentKey}/>
<div class="thread" ref={thread} onScroll={scrollThread}> <div className="thread" ref={thread} onScroll={scrollThread}>
{ state.delayed && state.topics.length === 0 && ( { state.delayed && state.topics.length === 0 && (
<div class="empty">This Topic Has No Messages</div> <div className="empty">This Topic Has No Messages</div>
)} )}
{ state.topics.length !== 0 && ( { state.topics.length !== 0 && (
<ReactResizeDetector handleHeight={true}> <ReactResizeDetector handleHeight={true}>
@ -59,34 +61,34 @@ export function Conversation({ closeConversation, openDetails, cardId, channelId
</ReactResizeDetector> </ReactResizeDetector>
)} )}
{ state.loadingInit && ( { state.loadingInit && (
<div class="loading"> <div className="loading">
<Spin size="large" delay={250} /> <Spin size="large" delay={250} />
</div> </div>
)} )}
{ state.loadingMore && ( { state.loadingMore && (
<div class="loading"> <div className="loading">
<Spin size="large" delay={500} /> <Spin size="large" delay={500} />
</div> </div>
)} )}
</div> </div>
<div class="divider"> <div className="divider">
<div class="line" /> <div className="line" />
{ state.uploadError && ( { state.uploadError && (
<div class="progress-error" /> <div className="progress-error" />
)} )}
{ state.upload && !state.uploadError && ( { state.upload && !state.uploadError && (
<div class="progress-active" style={{ width: state.uploadPercent + '%' }} /> <div className="progress-active" style={{ width: state.uploadPercent + '%' }} />
)} )}
{ !state.upload && ( { !state.upload && (
<div class="progress-idle" /> <div className="progress-idle" />
)} )}
</div> </div>
<div class="topic"> <div className="topic">
{ (!state.sealed || state.contentKey) && ( { (!state.sealed || state.contentKey) && (
<AddTopic contentKey={state.contentKey} /> <AddTopic contentKey={state.contentKey} strings={state.strings} menuStyle={state.menuStyle} />
)} )}
{ state.uploadError && ( { state.uploadError && (
<div class="upload-error"> <div className="upload-error">
{ state.display === 'small' && ( { state.display === 'small' && (
<StatusError> <StatusError>
<div onClick={() => actions.clearUploadErrors(cardId, channelId)}> <div onClick={() => actions.clearUploadErrors(cardId, channelId)}>

View File

@ -1,18 +1,17 @@
import styled from 'styled-components'; import styled from 'styled-components';
import { Colors } from 'constants/Colors';
export const ConversationWrapper = styled.div` export const ConversationWrapper = styled.div`
height: 100%; height: 100%;
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: ${Colors.profileForm}; background-color: ${props => props.theme.selectedArea};
.header { .header {
margin-left: 16px; margin-left: 16px;
margin-right: 16px; margin-right: 16px;
height: 48px; height: 48px;
border-bottom: 1px solid ${Colors.profileDivider}; border-bottom: 1px solid ${props => props.theme.headerBorder};
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
@ -27,6 +26,7 @@ export const ConversationWrapper = styled.div`
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
min-width: 0; min-width: 0;
color: ${props => props.theme.mainText};
.label { .label {
padding-left: 8px; padding-left: 8px;
@ -43,7 +43,7 @@ export const ConversationWrapper = styled.div`
.button { .button {
font-size: 18px; font-size: 18px;
color: ${Colors.grey}; color: ${props => props.theme.hintText};
cursor: pointer; cursor: pointer;
padding-right: 16px; padding-right: 16px;
padding-left: 16px; padding-left: 16px;
@ -65,7 +65,7 @@ export const ConversationWrapper = styled.div`
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 20; font-size: 20;
color: ${Colors.grey}; color: ${props => props.theme.hintText};
} }
.loading { .loading {
@ -85,21 +85,21 @@ export const ConversationWrapper = styled.div`
padding-right: 16px; padding-right: 16px;
.line { .line {
border-top: 1px solid ${Colors.divider}; border-top: 1px solid ${props => props.theme.itemBorder};
} }
.progress-idle { .progress-idle {
border-top: 1px solid ${Colors.divider}; border-top: 1px solid ${props => props.theme.itemBorder};
height: 1px; height: 1px;
} }
.progress-active { .progress-active {
border-top: 1px solid ${Colors.primary}; border-top: 1px solid ${props => props.theme.linkText};
height: 1px; height: 1px;
} }
.progress-error { .progress-error {
border-top: 1px solid ${Colors.alert}; border-top: 1px solid ${props => props.theme.alertText};
width: 100%; width: 100%;
height: 1px; height: 1px;
display: flex; display: flex;
@ -122,7 +122,7 @@ export const ConversationWrapper = 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-left: 8px; padding-left: 8px;
cursor: pointer; cursor: pointer;

View File

@ -1,6 +1,6 @@
import { AddTopicWrapper } from './AddTopic.styled'; import { AddTopicWrapper } from './AddTopic.styled';
import { useAddTopic } from './useAddTopic.hook'; import { useAddTopic } from './useAddTopic.hook';
import { Modal, Input, Menu, Dropdown, Spin } from 'antd'; import { Modal, Tooltip, Input, Menu, Dropdown, Spin } from 'antd';
import { useRef } from 'react'; import { useRef } from 'react';
import { FieldBinaryOutlined, SoundOutlined, VideoCameraOutlined, PictureOutlined, FontColorsOutlined, FontSizeOutlined, SendOutlined } from '@ant-design/icons'; import { FieldBinaryOutlined, SoundOutlined, VideoCameraOutlined, PictureOutlined, FontColorsOutlined, FontSizeOutlined, SendOutlined } from '@ant-design/icons';
import { SketchPicker } from "react-color"; import { SketchPicker } from "react-color";
@ -10,7 +10,7 @@ import { BinaryFile } from './binaryFile/BinaryFile';
import { Carousel } from 'carousel/Carousel'; import { Carousel } from 'carousel/Carousel';
import { Gluejar } from '@charliewilco/gluejar' import { Gluejar } from '@charliewilco/gluejar'
export function AddTopic({ contentKey }) { export function AddTopic({ contentKey, strings, menuStyle }) {
const { state, actions } = useAddTopic(contentKey); const { state, actions } = useAddTopic(contentKey);
@ -35,9 +35,9 @@ export function AddTopic({ contentKey }) {
catch (err) { catch (err) {
console.log(err); console.log(err);
modal.error({ modal.error({
title: 'Failed to Post Message', title: <span style={menuStyle}>{strings.operationFailed}</span>,
content: 'Please try again.', content: <span style={menuStyle}>{strings.tryAgain}</span>,
bodyStyle: { padding: 16 }, bodyStyle: { borderRadius: 8, padding: 16, ...menuStyle },
}); });
} }
} }
@ -121,54 +121,68 @@ export function AddTopic({ contentKey }) {
<input type='file' name="asset" accept="video/*" ref={attachVideo} onChange={e => onSelectVideo(e)} style={{display: 'none'}}/> <input type='file' name="asset" accept="video/*" ref={attachVideo} onChange={e => onSelectVideo(e)} style={{display: 'none'}}/>
<input type='file' name="asset" accept="*/*" ref={attachBinary} onChange={e => onSelectBinary(e)} style={{display: 'none'}}/> <input type='file' name="asset" accept="*/*" ref={attachBinary} onChange={e => onSelectBinary(e)} style={{display: 'none'}}/>
{ state.assets.length > 0 && ( { state.assets.length > 0 && (
<div class="assets"> <div className="assets">
<Carousel pad={32} items={state.assets} itemRenderer={renderItem} itemRemove={removeItem} /> <Carousel pad={32} items={state.assets} itemRenderer={renderItem} itemRemove={removeItem} />
</div> </div>
)} )}
<div class="message"> <div className="message">
<Input.TextArea ref={msg} placeholder="New Message" spellCheck="true" autoSize={{ minRows: 2, maxRows: 6 }} <Input.TextArea ref={msg} placeholder={strings.newMessage} spellCheck="true" autoSize={{ minRows: 2, maxRows: 6 }}
enterkeyhint="send" onKeyDown={(e) => keyDown(e)} onChange={(e) => actions.setMessageText(e.target.value)} enterkeyhint="send" onKeyDown={(e) => keyDown(e)} onChange={(e) => actions.setMessageText(e.target.value)}
value={state.messageText} autocapitalize="none" /> value={state.messageText} autocapitalize="none" />
</div> </div>
<div class="buttons"> <div className="buttons">
{ state.enableImage && ( { state.enableImage && (
<div class="button space" onClick={() => attachImage.current.click()}> <Tooltip placement="top" title={strings.attachImage}>
<PictureOutlined /> <div className="button space" onClick={() => attachImage.current.click()}>
</div> <PictureOutlined />
</div>
</Tooltip>
)} )}
{ state.enableVideo && ( { state.enableVideo && (
<div class="button space" onClick={() => attachVideo.current.click()}> <Tooltip placement="top" title={strings.attachVideo}>
<VideoCameraOutlined /> <div className="button space" onClick={() => attachVideo.current.click()}>
</div> <VideoCameraOutlined />
</div>
</Tooltip>
)} )}
{ state.enableAudio && ( { state.enableAudio && (
<div class="button space" onClick={() => attachAudio.current.click()}> <Tooltip placement="top" title={strings.attachAudio}>
<SoundOutlined /> <div className="button space" onClick={() => attachAudio.current.click()}>
</div> <SoundOutlined />
</div>
</Tooltip>
)} )}
<div class="button space" onClick={() => attachBinary.current.click()}> <Tooltip placement="top" title={strings.attachFile}>
<FieldBinaryOutlined /> <div className="button space" onClick={() => attachBinary.current.click()}>
</div> <FieldBinaryOutlined />
<div class="bar space" /> </div>
<div class="button space"> </Tooltip>
<Dropdown overlay={picker} overlayStyle={{ minWidth: 0 }} trigger={['click']} placement="top"> <div className="bar space" />
<FontColorsOutlined /> <div className="button space">
</Dropdown> <Tooltip placement="top" title={strings.fontColor}>
<Dropdown overlay={picker} overlayStyle={{ minWidth: 0 }} trigger={['click']} placement="top">
<FontColorsOutlined />
</Dropdown>
</Tooltip>
</div> </div>
<div class="button space"> <div className="button space">
<Dropdown overlay={sizer} overlayStyle={{ minWidth: 0 }} trigger={['click']} placement="top"> <Tooltip placement="top" title={strings.fontSize}>
<FontSizeOutlined /> <Dropdown overlay={sizer} overlayStyle={{ minWidth: 0 }} trigger={['click']} placement="top">
</Dropdown> <FontSizeOutlined />
</Dropdown>
</Tooltip>
</div> </div>
<div class="end"> <div className="end">
<div class="button" onClick={addTopic}> <Tooltip placement="top" title={strings.postMessage}>
{ state.busy && ( <div className="button" onClick={addTopic}>
<Spin size="small" /> { state.busy && (
)} <Spin size="small" />
{ !state.busy && ( )}
<SendOutlined /> { !state.busy && (
)} <SendOutlined />
</div> )}
</div>
</Tooltip>
</div> </div>
</div> </div>
</AddTopicWrapper> </AddTopicWrapper>

View File

@ -1,10 +1,22 @@
import styled from 'styled-components'; import styled from 'styled-components';
import { Colors } from 'constants/Colors';
export const AddTopicWrapper = styled.div` export const AddTopicWrapper = styled.div`
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: ${props => props.theme.selectedArea};
color: ${props => props.theme.mainText};
textarea {
padding-left: 8px;
background-color: ${props => props.theme.inputArea};
border: 1px solid ${props => props.theme.sectionBorder};
color: ${props => props.theme.mainText};
}
textarea::placeholder {
color: ${props => props.theme.placeholderText};
}
.message { .message {
width: 100%; width: 100%;
@ -30,7 +42,7 @@ export const AddTopicWrapper = styled.div`
align-items: center; align-items: center;
.bar { .bar {
border-left: 1px solid ${Colors.encircle}; border-left: 1px solid ${props => props.theme.sectionBorder};
height: 36px; height: 36px;
padding-right 8px; padding-right 8px;
margin-left: 8px; margin-left: 8px;
@ -44,10 +56,10 @@ export const AddTopicWrapper = styled.div`
width: 36px; width: 36px;
height: 36px; height: 36px;
cursor: pointer; cursor: pointer;
border: 1px solid ${Colors.divider}; border: 1px solid ${props => props.theme.sectionBorder};
background-color: ${Colors.white}; background-color: ${props => props.theme.inputArea};
font-size: 18px; font-size: 18px;
color: ${Colors.enabled}; color: ${props => props.theme.descriptionText};
} }
.space { .space {

View File

@ -1,11 +1,10 @@
import styled from 'styled-components'; import styled from 'styled-components';
import { Colors } from 'constants/Colors';
export const ChannelHeaderWrapper = styled.div` export const ChannelHeaderWrapper = styled.div`
margin-left: 16px; margin-left: 16px;
margin-right: 16px; margin-right: 16px;
height: 48px; height: 48px;
border-bottom: 1px solid ${Colors.profileDivider}; border-bottom: 1px solid ${props => props.theme.headerBorder};
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
@ -22,6 +21,7 @@ export const ChannelHeaderWrapper = styled.div`
min-width: 0; min-width: 0;
.label { .label {
color: ${props => props.theme.mainText};
padding-left: 8px; padding-left: 8px;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -36,7 +36,7 @@ export const ChannelHeaderWrapper = styled.div`
.button { .button {
font-size: 18px; font-size: 18px;
color: ${Colors.grey}; color: ${props => props.theme.hintText};
cursor: pointer; cursor: pointer;
padding-right: 16px; padding-right: 16px;
padding-left: 16px; padding-left: 16px;
@ -44,7 +44,7 @@ export const ChannelHeaderWrapper = 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-left: 8px; padding-left: 8px;
cursor: pointer; cursor: pointer;

View File

@ -9,18 +9,19 @@ import { ExclamationCircleOutlined, DeleteOutlined, EditOutlined, FireOutlined,
import { Carousel } from 'carousel/Carousel'; import { Carousel } from 'carousel/Carousel';
import { useTopicItem } from './useTopicItem.hook'; import { useTopicItem } from './useTopicItem.hook';
export function TopicItem({ host, contentKey, sealed, topic, update, remove }) { export function TopicItem({ host, contentKey, sealed, topic, update, remove, strings, menuStyle }) {
const [ modal, modalContext ] = Modal.useModal(); const [ modal, modalContext ] = Modal.useModal();
const { state, actions } = useTopicItem(topic, contentKey); const { state, actions } = useTopicItem(topic, contentKey);
const removeTopic = () => { const removeTopic = () => {
modal.confirm({ modal.confirm({
title: 'Do you want to delete this message?', title: <span style={menuStyle}>{strings.deleteMessage}</span>,
content: <span style={menuStyle}>{strings.messageHint}</span>,
bodyStyle: { borderRadius: 8, padding: 16, ...menuStyle },
icon: <ExclamationCircleOutlined />, icon: <ExclamationCircleOutlined />,
bodyStyle: { padding: 16 }, okText: strings.remove,
okText: 'Yes, Delete', cancelText: strings.cancel,
cancelText: 'No, Cancel',
onOk: async () => { onOk: async () => {
try { try {
await remove(); await remove();
@ -28,9 +29,9 @@ export function TopicItem({ host, contentKey, sealed, topic, update, remove }) {
catch(err) { catch(err) {
console.log(err); console.log(err);
modal.error({ modal.error({
title: 'Failed to Delete Message', title: <span style={menuStyle}>{strings.operationFailed}</span>,
content: 'Please try again.', content: <span style={menuStyle}>{strings.tryAgain}</span>,
bodyStyle: { padding: 16 }, bodyStyle: { borderRadius: 8, padding: 16, ...menuStyle },
}); });
} }
}, },
@ -45,9 +46,9 @@ export function TopicItem({ host, contentKey, sealed, topic, update, remove }) {
catch(err) { catch(err) {
console.log(err); console.log(err);
modal.error({ modal.error({
title: 'Failed to Update Message', title: <span style={menuStyle}>{strings.operationFailed}</span>,
content: 'Please try again.', content: <span style={menuStyle}>{strings.tryAgain}</span>,
bodyStyle: { padding: 16 }, bodyStyle: { borderRadius: 8, padding: 16, ...menuStyle },
}); });
} }
}; };
@ -71,23 +72,23 @@ export function TopicItem({ host, contentKey, sealed, topic, update, remove }) {
return ( return (
<TopicItemWrapper> <TopicItemWrapper>
{ modalContext } { modalContext }
<div class="topic-header"> <div className="topic-header">
<div class="avatar"> <div className="avatar">
<Logo width={32} height={32} radius={4} url={topic.imageUrl} /> <Logo width={32} height={32} radius={4} url={topic.imageUrl} />
</div> </div>
<div class="info"> <div className="info">
<div class={ topic.nameSet ? 'set' : 'unset' }>{ topic.name }</div> <div className={ topic.nameSet ? 'set' : 'unset' }>{ topic.name }</div>
<div>{ topic.createdStr }</div> <div>{ topic.createdStr }</div>
</div> </div>
<div class="topic-options"> <div className="topic-options">
<div class="buttons"> <div className="buttons">
{ !sealed && topic.creator && ( { !sealed && topic.creator && (
<div class="button edit" onClick={() => actions.setEditing(topic.text)}> <div className="button edit" onClick={() => actions.setEditing(topic.text)}>
<EditOutlined /> <EditOutlined />
</div> </div>
)} )}
{ (host || topic.creator) && ( { (host || topic.creator) && (
<div class="button remove" onClick={removeTopic}> <div className="button remove" onClick={removeTopic}>
<DeleteOutlined /> <DeleteOutlined />
</div> </div>
)} )}
@ -95,7 +96,7 @@ export function TopicItem({ host, contentKey, sealed, topic, update, remove }) {
</div> </div>
</div> </div>
{ topic.status !== 'confirmed' && ( { topic.status !== 'confirmed' && (
<div class="skeleton"> <div className="skeleton">
<Skeleton size={'small'} active={true} title={false} /> <Skeleton size={'small'} active={true} title={false} />
</div> </div>
)} )}
@ -104,36 +105,36 @@ export function TopicItem({ host, contentKey, sealed, topic, update, remove }) {
{ topic.assets?.length && ( { topic.assets?.length && (
<> <>
{ topic.transform === 'error' && ( { topic.transform === 'error' && (
<div class="asset-placeholder"> <div className="asset-placeholder">
<FireOutlined style={{ fontSize: 32, color: '#ff8888' }} /> <FireOutlined style={{ fontSize: 32, color: '#ff8888' }} />
</div> </div>
)} )}
{ topic.transform === 'incomplete' && ( { topic.transform === 'incomplete' && (
<div class="asset-placeholder"> <div className="asset-placeholder">
<PictureOutlined style={{ fontSize: 32 }} /> <PictureOutlined style={{ fontSize: 32 }} />
</div> </div>
)} )}
{ topic.transform === 'complete' && ( { topic.transform === 'complete' && (
<div class="topic-assets"> <div className="topic-assets">
<Carousel pad={40} items={state.assets} itemRenderer={renderAsset} /> <Carousel pad={40} items={state.assets} itemRenderer={renderAsset} />
</div> </div>
)} )}
</> </>
)} )}
{ sealed && ( { sealed && (
<div class="sealed-message">sealed message</div> <div className="sealed-message">sealed message</div>
)} )}
{ !sealed && !state.editing && ( { !sealed && !state.editing && (
<div class="message"> <div className="message">
<div style={{ color: topic.textColor, fontSize: topic.textSize }}>{ topic.clickable }</div> <div style={{ color: topic.textColor, fontSize: topic.textSize }}>{ topic.clickable }</div>
</div> </div>
)} )}
{ state.editing && ( { state.editing && (
<div class="editing"> <div className="editing">
<Input.TextArea defaultValue={state.message} placeholder="message" <Input.TextArea defaultValue={state.message} placeholder="message"
style={{ resize: 'none', color: state.textColor, fontSize: state.textSize }} style={{ resize: 'none', color: state.textColor, fontSize: state.textSize }}
onChange={(e) => actions.setMessage(e.target.value)} rows={3} bordered={false}/> onChange={(e) => actions.setMessage(e.target.value)} rows={3} bordered={false}/>
<div class="controls"> <div className="controls">
<Space> <Space>
<Button onClick={actions.clearEditing}>Cancel</Button> <Button onClick={actions.clearEditing}>Cancel</Button>
<Button type="primary" onClick={updateTopic}>Save</Button> <Button type="primary" onClick={updateTopic}>Save</Button>

View File

@ -1,10 +1,10 @@
import styled from 'styled-components'; import styled from 'styled-components';
import { Colors } from 'constants/Colors';
export const TopicItemWrapper = styled.div` export const TopicItemWrapper = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
color: ${props => props.theme.mainText};
.topic-header { .topic-header {
display: flex; display: flex;
@ -13,7 +13,7 @@ export const TopicItemWrapper = styled.div`
padding-left: 16px; padding-left: 16px;
margin-right: 16px; margin-right: 16px;
padding-top: 8px; padding-top: 8px;
border-top: 1px solid #dddddd; border-top: 1px solid ${props => props.theme.itemBorder};
&:hover .topic-options { &:hover .topic-options {
visibility: visible; visibility: visible;
@ -29,7 +29,7 @@ export const TopicItemWrapper = styled.div`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
border-radius: 4px; border-radius: 4px;
background-color: #eeeeee; background-color: ${props => props.theme.modalArea};
margin-top: 2px; margin-top: 2px;
.button { .button {
@ -40,11 +40,11 @@ export const TopicItemWrapper = styled.div`
} }
.remove { .remove {
color: ${Colors.warn}; color: ${props => props.theme.alertText};
} }
.edit { .edit {
color: ${Colors.primary}; color: ${props => props.theme.linkText};
} }
} }
} }
@ -63,18 +63,18 @@ export const TopicItemWrapper = styled.div`
.comments { .comments {
padding-left: 8px; padding-left: 8px;
cursor: pointer; cursor: pointer;
color: #888888; color: ${props => props.theme.descriptionText};
} }
.set { .set {
font-weight: bold; font-weight: bold;
color: #444444; color: ${props => props.theme.mainText};
padding-right: 8px; padding-right: 8px;
} }
.unset { .unset {
font-weight: bold; font-weight: bold;
font-style: italic; font-style: italic;
color: #888888; color: ${props => props.theme.descriptionText};
padding-right: 8px; padding-right: 8px;
} }
.unknown { .unknown {
@ -87,7 +87,7 @@ export const TopicItemWrapper = styled.div`
.sealed-message { .sealed-message {
font-style: italic; font-style: italic;
color: #aaaaaa; color: ${props => props.theme.placeholderText};
padding-left: 72px; padding-left: 72px;
} }
@ -97,8 +97,8 @@ export const TopicItemWrapper = styled.div`
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background-color: #eeeeee; background-color: ${props => props.theme.frameArea};
color: #888888; color: ${props => props.theme.placeholderText};
margin-left: 72px; margin-left: 72px;
} }
@ -118,18 +118,30 @@ export const TopicItemWrapper = styled.div`
padding-left: 72px; padding-left: 72px;
white-space: pre-line; white-space: pre-line;
min-height: 4px; min-height: 4px;
color: ${props => props.theme.mainText};
} }
.editing { .editing {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
border-radius: 4px; border-radius: 4px;
border: 1px solid #aaaaaa; border: 1px solid ${props => props.theme.sectionBorder};
background-color: ${props => props.theme.inputArea};
margin-top: 8px; margin-top: 8px;
margin-bottom: 8px; margin-bottom: 8px;
margin-right: 16px; margin-right: 16px;
margin-left: 72px; margin-left: 72px;
textarea {
padding-left: 8px;
background-color: ${props => props.theme.inputArea};
color: ${props => props.theme.mainText};
}
textarea::placeholder {
color: ${props => props.theme.placeholderText};
}
.controls { .controls {
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
import { fetchWithTimeout } from 'api/fetchUtil'; import { fetchWithTimeout } from 'api/fetchUtil';
import { decryptBlock } from 'context/sealUtil'; import { decryptBlock } from 'context/sealUtil';
export function useTopicItem(topic, contentKey) { export function useTopicItem(topic, contentKey, strings, menuStyle) {
const [state, setState] = useState({ const [state, setState] = useState({
editing: false, editing: false,

View File

@ -22,6 +22,9 @@ export function useConversation(cardId, channelId) {
sealed: false, sealed: false,
contentKey: null, contentKey: null,
busy: false, busy: false,
colors: {},
strings: {},
menuStyle: {},
}); });
const profile = useContext(ProfileContext); const profile = useContext(ProfileContext);
@ -41,8 +44,9 @@ export function useConversation(cardId, channelId) {
} }
useEffect(() => { useEffect(() => {
updateState({ display: settings.state.display }); const { strings, menuStyle, display, colors } = settings.state;
}, [settings]); updateState({ strings, menuStyle, display, colors });
}, [settings.state]);
useEffect(() => { useEffect(() => {
const { dataType, data } = conversation.state.channel?.data?.channelDetail || {}; const { dataType, data } = conversation.state.channel?.data?.channelDetail || {};
@ -125,7 +129,7 @@ export function useConversation(cardId, channelId) {
syncChannel(); syncChannel();
// eslint-disable-next-line // eslint-disable-next-line
}, [conversation.state, profile.state, card.state]); }, [conversation.state, profile.state, card.state, settings.state]);
useEffect(() => { useEffect(() => {
topics.current = new Map(); topics.current = new Map();
@ -171,13 +175,28 @@ export function useConversation(cardId, channelId) {
const now = new Date(); const now = new Date();
const offset = now.getTime() - date.getTime(); const offset = now.getTime() - date.getTime();
if(offset < 86400000) { if(offset < 86400000) {
item.createdStr = date.toLocaleTimeString([], {hour: 'numeric', minute:'2-digit'}); if (settings.state.timeFormat === '12h') {
item.createdStr = date.toLocaleTimeString("en-US", {hour: 'numeric', minute:'2-digit'});
}
else {
item.createdStr = date.toLocaleTimeString("en-GB", {hour: 'numeric', minute:'2-digit'});
}
} }
else if (offset < 31449600000) { else if (offset < 31449600000) {
item.createdStr = date.toLocaleDateString("en-US", {day: 'numeric', month:'numeric'}); if (settings.state.dateFormat === 'mm/dd') {
item.createdStr = date.toLocaleDateString("en-US", {day: 'numeric', month:'numeric'});
}
else {
item.createdStr = date.toLocaleDateString("en-GB", {day: 'numeric', month:'numeric'});
}
} }
else { else {
item.createdStr = date.toLocaleDateString("en-US"); if (settings.state.dateFormat === 'mm/dd') {
item.createdStr = date.toLocaleDateString("en-US");
}
else {
item.createdStr = date.toLocaleDateString("en-GB");
}
} }
if (detail.guid === identity.guid) { if (detail.guid === identity.guid) {
@ -188,7 +207,7 @@ export function useConversation(cardId, channelId) {
item.nameSet = true; item.nameSet = true;
} }
else { else {
item.name = identity.node ? `${identity.handle}@${identity.node}` : identity.handle ? identity.handle : 'unknown'; item.name = identity.node ? `${identity.handle}/${identity.node}` : identity.handle ? identity.handle : 'unknown';
item.nameSet = false; item.nameSet = false;
} }
} }
@ -202,7 +221,7 @@ export function useConversation(cardId, channelId) {
item.nameSet = true; item.nameSet = true;
} }
else { else {
item.name = contact.node ? `${contact.handle}@${contact.node}` : contact.handle ? contact.handle : 'unknown'; item.name = contact.node ? `${contact.handle}/${contact.node}` : contact.handle ? contact.handle : 'unknown';
item.nameSet = false; item.nameSet = false;
} }
} }
@ -220,7 +239,7 @@ export function useConversation(cardId, channelId) {
item.assets = message.assets; item.assets = message.assets;
item.text = message.text; item.text = message.text;
item.clickable = clickableText(message.text); item.clickable = clickableText(message.text);
item.textColor = message.textColor ? message.textColor : '#444444'; item.textColor = message.textColor ? message.textColor : state.colors.mainText;
item.textSize = message.textSize ? message.textSize : 14; item.textSize = message.textSize ? message.textSize : 14;
} }
if (detail.dataType === 'sealedtopic' && state.contentKey) { if (detail.dataType === 'sealedtopic' && state.contentKey) {
@ -228,7 +247,7 @@ export function useConversation(cardId, channelId) {
item.assets = subject.message.assets; item.assets = subject.message.assets;
item.text = subject.message.text; item.text = subject.message.text;
item.clickable = clickableText(subject.message.text); item.clickable = clickableText(subject.message.text);
item.textColor = subject.message.textColor ? subject.message.textColor : '#444444'; item.textColor = subject.message.textColor ? subject.message.textColor : state.colors.mainText;
item.textSize = subject.message.textSize ? subject.message.textSize : 14; item.textSize = subject.message.textSize ? subject.message.textSize : 14;
} }
} }

5
todo
View File

@ -1,9 +1,4 @@
thread:
- dark style
- translation
- button tool tip
details: details:
- back button - back button
- dark style - dark style