add code-viewer
This commit is contained in:
parent
1c50b71f14
commit
c622314eff
8 changed files with 140 additions and 48 deletions
|
@ -36,6 +36,7 @@
|
|||
"dependencies": {
|
||||
"bluebird": "^3.5.1",
|
||||
"classnames": "^2.2.5",
|
||||
"codemirror": "^5.39.2",
|
||||
"country-data": "^0.0.31",
|
||||
"dom-scroll-into-view": "^1.2.1",
|
||||
"electron-dl": "^1.11.0",
|
||||
|
|
38
src/renderer/component/viewers/codeViewer.jsx
Normal file
38
src/renderer/component/viewers/codeViewer.jsx
Normal file
|
@ -0,0 +1,38 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import CodeMirror from 'codemirror';
|
||||
|
||||
type Props = {
|
||||
value: string,
|
||||
};
|
||||
|
||||
class CodeViewer extends React.PureComponent<Props> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.codeMirror = null;
|
||||
this.textarea = React.createRef();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.codeMirror = CodeMirror.fromTextArea(this.textarea.current, {
|
||||
mode: 'markdown',
|
||||
readOnly: true,
|
||||
dragDrop: false,
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { value } = this.props;
|
||||
|
||||
return (
|
||||
<div className="document-viewer__content">
|
||||
<textarea ref={this.textarea} disabled="true" value={value} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CodeViewer;
|
|
@ -3,6 +3,7 @@
|
|||
import React from 'react';
|
||||
import fs from 'fs';
|
||||
import LoadingScreen from 'component/common/loading-screen';
|
||||
import CodeViewer from 'component/viewers/codeViewer';
|
||||
import MarkdownPreview from 'component/common/markdown-preview';
|
||||
|
||||
type Props = {
|
||||
|
@ -34,7 +35,7 @@ class DocumentViewer extends React.PureComponent<Props> {
|
|||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
this.setState({ content: data });
|
||||
this.setState({ content: data, loading: false });
|
||||
});
|
||||
|
||||
stream.on('error', error => {
|
||||
|
@ -42,36 +43,34 @@ class DocumentViewer extends React.PureComponent<Props> {
|
|||
});
|
||||
}
|
||||
|
||||
renderDocument(data) {
|
||||
renderDocument() {
|
||||
let viewer = null;
|
||||
const { source } = this.props;
|
||||
const { fileType } = source;
|
||||
const { content, error } = this.state;
|
||||
const isReady = content && !error;
|
||||
const markdownType = ['md', 'markdown'];
|
||||
|
||||
// Match supported documents
|
||||
const docs = {
|
||||
md: content => <MarkdownPreview content={content} promptLinks />,
|
||||
};
|
||||
|
||||
if (docs[fileType]) {
|
||||
// Use custom parser
|
||||
return docs[fileType](data);
|
||||
if (isReady && markdownType.includes(source.fileType)) {
|
||||
// Render markdown
|
||||
viewer = <MarkdownPreview content={content} promptLinks />;
|
||||
} else if (isReady) {
|
||||
// Render plain text
|
||||
viewer = <CodeViewer value={content} />;
|
||||
}
|
||||
// Render plain text
|
||||
this.setState({ loading: false });
|
||||
return <textarea disabled="true" value={data} />;
|
||||
|
||||
return viewer;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { content, error, loading } = this.state;
|
||||
const { error, loading } = this.state;
|
||||
const loadingMessage = __('Rendering document.');
|
||||
const errorMessage = __("Sorry looks like we can't load the document.");
|
||||
|
||||
return (
|
||||
<div className="document-viewer file-render__viewer">
|
||||
<div className="file-render__viewer document-viewer">
|
||||
{loading && !error && <LoadingScreen status={loadingMessage} spinner />}
|
||||
{error && <LoadingScreen status={errorMessage} spinner={false} />}
|
||||
{content && (
|
||||
<div className="document-viewer__content">{content && this.renderDocument(content)}</div>
|
||||
)}
|
||||
{this.renderDocument()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -96,25 +96,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.file-render {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.file-render__viewer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: black;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
|
|
|
@ -9,17 +9,80 @@
|
|||
bottom: 0;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.file-render__viewer {
|
||||
margin: 0;
|
||||
.file-render__viewer {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: black;
|
||||
|
||||
iframe,
|
||||
webview {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: black;
|
||||
|
||||
iframe,
|
||||
webview {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.document-viewer {
|
||||
overflow: auto;
|
||||
background-color: var(--card-bg);
|
||||
}
|
||||
|
||||
.document-viewer .markdown-preview {
|
||||
padding: 32px 16px;
|
||||
}
|
||||
|
||||
.document-viewer .CodeMirror {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
.CodeMirror-code {
|
||||
font-size: calc(var(--font-size-subtext-multiple) * 1em);
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.CodeMirror-linenumber {
|
||||
color: var(--card-text-color);
|
||||
}
|
||||
|
||||
.CodeMirror-line {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
border-right: 1px solid var(--color-divider);
|
||||
background: var(--color-bg-alt);
|
||||
}
|
||||
|
||||
.cm-invalidchar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.document-viewer__content {
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.markdown-preview {
|
||||
padding: 32px 16px;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
textarea {
|
||||
/*
|
||||
resize: none;
|
||||
background: transparent;
|
||||
color: var(--card-text-color);
|
||||
border: 0;
|
||||
outline: none;
|
||||
font-family: monospace;
|
||||
*/
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* Image */
|
||||
img {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
/* Horizontal Rule */
|
||||
hr {
|
||||
border: 1px solid var(--color-divider);
|
||||
|
|
|
@ -3,7 +3,8 @@ import mime from 'mime';
|
|||
const formats = [
|
||||
[/\.(mp4|m4v|webm|flv|f4v|ogv)$/i, 'video'],
|
||||
[/\.(mp3|m4a|aac|wav|flac|ogg|opus)$/i, 'audio'],
|
||||
[/\.(html|htm|xml|pdf|odf|doc|docx|md|markdown|txt|epub|org)$/i, 'document'],
|
||||
[/\.(json|csv|txt|log|md|markdown|rtf|xml|yml|yaml)$/i, 'document'],
|
||||
[/\.(pdf|odf|doc|docx|epub|org)$/i, 'e-book'],
|
||||
[/\.(stl|obj|fbx|gcode)$/i, '3D-file'],
|
||||
];
|
||||
|
||||
|
|
|
@ -1893,6 +1893,10 @@ codemirror@*:
|
|||
version "5.39.0"
|
||||
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.39.0.tgz#4654f7d2f7e525e04a62e72d9482348ccb37dce5"
|
||||
|
||||
codemirror@^5.39.2:
|
||||
version "5.39.2"
|
||||
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.39.2.tgz#778aa13b55ebf280745c309cb1b148e3fc06f698"
|
||||
|
||||
collapse-white-space@^1.0.0, collapse-white-space@^1.0.2:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.4.tgz#ce05cf49e54c3277ae573036a26851ba430a0091"
|
||||
|
|
Loading…
Reference in a new issue