mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
adding dark mode and translation to thread component
This commit is contained in:
parent
71d6598556
commit
3629f30029
@ -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',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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)}>
|
||||||
|
@ -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;
|
||||||
|
@ -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>
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user