Abstract dynamic button to a separate component;
Move buttons to the JSONViewer;
Move data-saving to a hook;
This commit is contained in:
GneyHabub 2021-03-15 11:04:21 +03:00
parent bab84f5db1
commit f0b1e9c7d9
6 changed files with 133 additions and 133 deletions

View file

@ -36,26 +36,3 @@ $navbar-width: 250px;
.react-datepicker-popper {
z-index: 30 !important;
}
.topic-message-button {
&::after {
content: attr(data-title);
position: absolute;
top: -140%;
z-index: 1;
background: #F5F5F5;
color: rgb(89, 89, 89);
border-radius: 5px;
font-size: 15px;
padding: 5px 10px;
opacity: 0;
pointer-events: none;
transition: .2s opacity;
transition-delay: 0s;
}
&:hover::after {
opacity: 1;
transition-delay: .5s;
}
}

View file

@ -15,72 +15,19 @@ const MessageItem: React.FC<MessageItemProp> = ({
offset,
timestamp,
content,
}) => {
const copyData = () => {
if (navigator.clipboard)
navigator.clipboard.writeText(JSON.stringify(content || {}));
};
const saveFile = () => {
let extension = 'json';
if (typeof content === 'string') {
try {
JSON.parse(content);
} catch (e) {
extension = 'txt';
}
}
const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(
JSON.stringify(content || {})
)}`;
const downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute('href', dataStr);
downloadAnchorNode.setAttribute(
'download',
`topic-message[${timestamp}].${extension}`
);
document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click();
downloadAnchorNode.remove();
};
const buttonStyle = {
height: '30px',
};
const buttonClasses = 'button is-link is-outlined topic-message-button';
return (
<tr>
<td style={{ width: 200 }}>{format(timestamp, 'yyyy-MM-dd HH:mm:ss')}</td>
<td style={{ width: 150 }}>{offset}</td>
<td style={{ width: 100 }}>{partition}</td>
<td style={{ wordBreak: 'break-word' }}>
{content && (
<div>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<button
className={buttonClasses}
data-title="Copy the message to the clipboard"
type="button"
style={{ ...buttonStyle, marginRight: '5px' }}
onClick={copyData}
>
<i className="far fa-clipboard" />
</button>
<button
className={buttonClasses}
data-title="Download the message as a .json/.txt file"
type="button"
style={buttonStyle}
onClick={saveFile}
>
<i className="fas fa-file-download" />
</button>
</div>
<JSONViewer data={content as { [key: string]: string }} />
</div>
)}
</td>
</tr>
);
};
}) => (
<tr>
<td style={{ width: 200 }}>{format(timestamp, 'yyyy-MM-dd HH:mm:ss')}</td>
<td style={{ width: 150 }}>{offset}</td>
<td style={{ width: 100 }}>{partition}</td>
<td style={{ wordBreak: 'break-word' }}>
{content && (
<div>
<JSONViewer data={content as { [key: string]: string }} />
</div>
)}
</td>
</tr>
);
export default MessageItem;

View file

@ -37,46 +37,6 @@ exports[`MessageItem when content is defined matches snapshot 1`] = `
}
>
<div>
<div
style={
Object {
"display": "flex",
"justifyContent": "center",
}
}
>
<button
className="button is-link is-outlined topic-message-button"
data-title="Copy the message to the clipboard"
onClick={[Function]}
style={
Object {
"height": "30px",
"marginRight": "5px",
}
}
type="button"
>
<i
className="far fa-clipboard"
/>
</button>
<button
className="button is-link is-outlined topic-message-button"
data-title="Download the message as a .json/.txt file"
onClick={[Function]}
style={
Object {
"height": "30px",
}
}
type="button"
>
<i
className="fas fa-file-download"
/>
</button>
</div>
<JSONViewer
data={
Object {

View file

@ -0,0 +1,44 @@
import React from 'react';
interface ButtonProps {
callback: () => void;
classes?: string;
title: string;
style?: { [key: string]: string | number };
text: {
default: string;
dynamic: string;
};
}
const DynamicButton: React.FC<ButtonProps> = ({
callback,
classes,
title,
style,
text,
children,
}) => {
const [buttonText, setButtonText] = React.useState(text.default);
let timeout: number;
const clickHandler = () => {
callback();
setButtonText(text.dynamic);
timeout = window.setTimeout(() => setButtonText(text.default), 3000);
};
React.useEffect(() => () => window.clearTimeout(timeout), [callback]);
return (
<button
className={classes}
title={title}
type="button"
style={style}
onClick={clickHandler}
>
{children}
<span>{buttonText}</span>
</button>
);
};
export default DynamicButton;

View file

@ -1,6 +1,8 @@
import React from 'react';
import JSONTree from 'react-json-tree';
import useDataSaver from 'lib/hooks/useDataSaver';
import theme from './themes/google';
import DynamicButton from './DynamicButton';
interface JSONViewerProps {
data: {
@ -8,8 +10,51 @@ interface JSONViewerProps {
};
}
const JSONViewer: React.FC<JSONViewerProps> = ({ data }) => (
<JSONTree data={data} theme={theme} shouldExpandNode={() => true} hideRoot />
);
const JSONViewer: React.FC<JSONViewerProps> = ({ data }) => {
const { copyToClipboard, saveFile } = useDataSaver();
const copyButtonHandler = () => {
copyToClipboard(JSON.stringify(data));
};
const buttonClasses = 'button is-link is-outlined is-small is-centered';
return (
<div>
<div
className="field has-addons"
style={{
justifyContent: 'flex-end',
}}
>
<DynamicButton
callback={copyButtonHandler}
classes={buttonClasses}
title="Copy the message to the clipboard"
style={{ marginRight: '5px' }}
text={{ default: 'Copy', dynamic: 'Copied!' }}
>
<span className="icon">
<i className="far fa-clipboard" />
</span>
</DynamicButton>
<button
className={buttonClasses}
title="Download the message as a .json/.txt file"
type="button"
onClick={() => saveFile(JSON.stringify(data), `topic-message`)}
>
<span className="icon">
<i className="fas fa-file-download" />
</span>
<span>Save</span>
</button>
</div>
<JSONTree
data={data}
theme={theme}
shouldExpandNode={() => true}
hideRoot
/>
</div>
);
};
export default JSONViewer;

View file

@ -0,0 +1,27 @@
const useDataSaver = () => {
const copyToClipboard = (content: string) => {
if (navigator.clipboard) navigator.clipboard.writeText(content);
};
const saveFile = (content: string, fileName: string) => {
let extension = 'json';
try {
JSON.parse(content);
} catch (e) {
extension = 'txt';
}
const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(
content
)}`;
const downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute('href', dataStr);
downloadAnchorNode.setAttribute('download', `${fileName}.${extension}`);
document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click();
downloadAnchorNode.remove();
};
return { copyToClipboard, saveFile };
};
export default useDataSaver;