diff options
| -rw-r--r-- | frontend/package.json | 2 | ||||
| -rw-r--r-- | frontend/src/components/Inputs.js | 102 | ||||
| -rw-r--r-- | frontend/src/components/PasteInfo.js | 30 | ||||
| -rw-r--r-- | frontend/src/components/ViewPaste.js | 54 | ||||
| -rw-r--r-- | frontend/src/components/renderers/Code.js | 56 | ||||
| -rw-r--r-- | frontend/src/css/index.css | 30 | ||||
| -rw-r--r-- | package.json | 5 | ||||
| -rw-r--r-- | yarn.lock | 15 |
8 files changed, 211 insertions, 83 deletions
diff --git a/frontend/package.json b/frontend/package.json index 2fbee85..aff8c49 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,8 +13,10 @@ "react-dom": "^16.13.1", "react-dropdown": "^1.7.0", "react-modal": "^3.11.2", + "react-render-html": "^0.6.0", "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", + "react-syntax-highlighter": "^12.2.1", "styled-components": "^5.1.0", "use-clipboard-copy": "^0.1.2" }, diff --git a/frontend/src/components/Inputs.js b/frontend/src/components/Inputs.js index 4bb7b33..b96ceb0 100644 --- a/frontend/src/components/Inputs.js +++ b/frontend/src/components/Inputs.js @@ -3,6 +3,7 @@ import CharLimit from './decorators/CharLimit' import styled from 'styled-components' import FloatingLabel from './decorators/FloatingLabel' import Dropdown from 'react-dropdown'; +import { LANGS, THEMES } from './renderers/Code'; const RelPositioning = styled.div` position: relative; @@ -89,37 +90,35 @@ class PassInput extends React.Component { } } -class ExpiryInput extends React.Component { - +class GenericDropdown extends React.Component { + + constructor(props) { + super(props) + + this._onSelect = this._onSelect.bind(this) + } + _onSelect(option) { - this.callBackRef({target: { - name: 'expiry', - value: option.label - }}); + this.props.onChange({ + target: { + name: this.props.label, + value: option.label + } + }); } render() { - const options = [ - '5 years', - '1 year', - '1 month', - '1 week', - '1 day', - '1 hour', - '10 min', - ]; - return ( <FlexChild> - <Dropdown - options={options} - onChange={this._onSelect} + <Dropdown + options={this.props.options} + onChange={this._onSelect} callBackRef={this.props.onChange} - value={this.props.value} - placeholder="1 week" + value={this.props.value} + placeholder={this.props.placeholder} id={this.props.id} /> <FloatingLabel - label="expiry" + label={this.props.label} id={this.props.id} value={this.props.value} /> </FlexChild> @@ -127,6 +126,63 @@ class ExpiryInput extends React.Component { } } +const ExpiryInput = (props) => { + const options = [ + '5 years', + '1 year', + '1 month', + '1 week', + '1 day', + '1 hour', + '10 min', + ]; + + return ( + <GenericDropdown + {...props} + options={options} + placeholder='1 week' + label='expiry' + /> + ); +} + +const LangInput = (props) => { + const options = Object.entries(LANGS).map((key, _) => { + return { + 'value': key[1], + 'label': key[0] + } + }) + + return ( + <GenericDropdown + {...props} + options={options} + placeholder={LANGS.raw} + label='language' + /> + ); +} + +const ThemeInput = (props) => { + const options = Object.entries(THEMES).map((key, _) => { + return { + 'value': key[1], + 'label': key[0] + } + }) + + return ( + <GenericDropdown + {...props} + options={options} + placeholder={'atom'} + label='theme' + /> + ); +} + class PasteURLInput extends React.Component { render() { return ( @@ -150,4 +206,4 @@ class PasteURLInput extends React.Component { } } -export { TitleInput, PasteInput, PassInput, ExpiryInput, PasteURLInput }
\ No newline at end of file +export { TitleInput, PasteInput, PassInput, ExpiryInput, PasteURLInput, LangInput, ThemeInput }
\ No newline at end of file diff --git a/frontend/src/components/PasteInfo.js b/frontend/src/components/PasteInfo.js index b27cd53..dabbb94 100644 --- a/frontend/src/components/PasteInfo.js +++ b/frontend/src/components/PasteInfo.js @@ -1,27 +1,39 @@ import React from 'react'; import styled from 'styled-components' +import { LangInput, ThemeInput } from './Inputs' const Bold = styled.span` font-weight: 700 ` -const FloatLeft = styled.p` - float: left; +const StyledDiv = styled.div` + margin: 2em 0; display: inline-block; - margin: 0; ` -const FloatRight = styled.p` + +const Flex = styled.div` float: right; - display: inline-block; - margin: 0; - margin-right: -1em; + display: flex; + flex-direction: row; + transform: translateY(0.2em); ` const PasteInfo = (props) => { return ( <div> - <FloatLeft><Bold>mode: </Bold>{props.mode}</FloatLeft> - <FloatRight><Bold>expires: </Bold>{props.expiry}</FloatRight> + <Flex> + <LangInput + value={props.lang} + onChange={props.onChange} + id="langInput" /> + <ThemeInput + value={props.theme} + onChange={props.onChange} + id="themeInput" /> + </Flex> + <StyledDiv> + <Bold>expires: </Bold>{props.expiry} + </StyledDiv> </div> ); } diff --git a/frontend/src/components/ViewPaste.js b/frontend/src/components/ViewPaste.js index 835deaf..491c440 100644 --- a/frontend/src/components/ViewPaste.js +++ b/frontend/src/components/ViewPaste.js @@ -1,16 +1,11 @@ import React from 'react'; import Error from './Err'; -import { TitleInput, PasteInput } from './Inputs'; +import { TitleInput } from './Inputs'; +import CodeRenderer from './renderers/Code' import PasteInfo from './PasteInfo'; import PasswordModal from './modals/PasswordModal' import { FetchPaste, FetchPasswordPaste } from '../helpers/httpHelper' - -const RENDER_MODES = Object.freeze({ - RAW: 'raw text', - MD: 'markdown', - LATEX: 'latex', - CODE: 'code', -}) +import { LANGS } from './renderers/Code' class ViewPaste extends React.Component { @@ -25,31 +20,29 @@ class ViewPaste extends React.Component { expiry: 'no expiry', error: '', passError: '', - mode: RENDER_MODES.RAW, + theme: 'atom', + language: LANGS.raw, }; this.handleChange = this.handleChange.bind(this); + this.typedPass = this.typedPass.bind(this); this.validatePass = this.validatePass.bind(this); this.ErrorLabel = React.createRef(); this.PasswordModal = React.createRef(); } handleChange(event) { - this.setState({ enteredPass: event.target.value }); - } + const target = event.target; + const name = target.name; + console.log(target, name) - drawRightMode() { - switch (this.state.mode) { - // TODO: add other renderers + this.setState({ + [name]: target.value + }); + } - // default render raw - case RENDER_MODES.RAW: - default: - return (<PasteInput - content={this.state.content} - id="pasteInput" - readOnly />); - } + typedPass(event) { + this.setState({ enteredPass: event.target.value }); } validatePass(pass) { @@ -87,18 +80,22 @@ class ViewPaste extends React.Component { hasPass={this.state.hasPass} validPass={this.state.validPass} value={this.state.enteredPass} - onChange={this.handleChange} + onChange={this.typedPass} validateCallback={this.validatePass} /> <TitleInput value={this.state.title} id="titleInput" readOnly /> - - {this.drawRightMode()} - + <CodeRenderer + content={this.state.content} + lang={this.state.language} + theme={this.state.theme} + id="pasteInput" /> <PasteInfo - expiry={this.state.expiry} - mode={this.state.mode} /> + lang={this.state.language} + theme={this.state.theme} + onChange={this.handleChange} + expiry={this.state.expiry} /> <Error ref={this.ErrorLabel} /> </div> ); @@ -111,7 +108,6 @@ class ViewPaste extends React.Component { } setStateFromData(data) { - console.log(data) this.setState({ title: data.title, content: data.content, diff --git a/frontend/src/components/renderers/Code.js b/frontend/src/components/renderers/Code.js new file mode 100644 index 0000000..12efc67 --- /dev/null +++ b/frontend/src/components/renderers/Code.js @@ -0,0 +1,56 @@ +import React from 'react'; +import styled from 'styled-components' +import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'; +import { atomOneLight, ascetic, atomOneDark, dracula, ocean } from 'react-syntax-highlighter/dist/esm/styles/hljs'; + +export const THEMES = Object.freeze({ + 'atom': atomOneLight, + 'atom dark': atomOneDark, + 'plain': ascetic, + 'dracula': dracula, + 'ocean': ocean, +}) + +export const LANGS = Object.freeze({ + 'go': 'go', + 'python': 'python', + 'javascript': 'javascript', + 'html': 'html', + 'css': 'css', + 'c': 'c', + 'c++': 'cpp', + 'c#': 'cs', + 'ruby': 'ruby', + 'docker': 'dockerfile', + 'bash': 'bash', + 'raw': 'text', + 'java': 'java', + 'lisp': 'lisp', + 'haskell': 'haskell', + 'scala': 'scala', + 'markdown': 'markdown', + 'makefile': 'makefile', + 'php': 'php', + 'latex': 'latex', + 'yaml': 'yaml' +}) + +const RelPositioning = styled.div` + position: relative; +` + +const CodeRenderer = (props) => { + return ( + <RelPositioning> + <SyntaxHighlighter + className="codeBlock lt-shadow" + language={props.lang} + style={THEMES[props.theme]} + showLineNumbers > + {props.content} + </SyntaxHighlighter> + </RelPositioning> + ); +}; + +export default CodeRenderer
\ No newline at end of file diff --git a/frontend/src/css/index.css b/frontend/src/css/index.css index 32e4065..c0e669c 100644 --- a/frontend/src/css/index.css +++ b/frontend/src/css/index.css @@ -25,6 +25,31 @@ textarea, input[type=text], input[type=password], .Dropdown-root { margin: 1.7em 0; } +.codeBlock { + width: 100%; + font-size: 0.8em; + padding: calc(0.8em - 1px) !important; + border-radius: 3px; + border: 1px solid #565656; + background: #faf9f5; + outline: none; + margin: 1.7em 0; +} + +.codeBlock code:first-child { + margin-right: 10px; + border-radius: 0; + border-right: 1px solid #11111155; +} + +code, pre { + background: #00000000; + font-family: 'Roboto Mono', monospace; + padding: initial; + border-radius: 3px; + outline: none; +} + .Dropdown-root { cursor: pointer; } @@ -44,7 +69,7 @@ textarea, input[type=text], input[type=password], .Dropdown-root { } .Dropdown-placeholder { - width: 5em; + width: 7em; } .Dropdown-menu { @@ -98,7 +123,8 @@ input[type=submit], button[type=submit] { button[type=button] { font-family: 'Lora', serif; - width: 7em; + font-weight: 700; + width: 8em; padding: calc(0.8em - 1px) 1.5em; border-radius: 3px; color: #111111; diff --git a/package.json b/package.json deleted file mode 100644 index e10893d..0000000 --- a/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "use-clipboard-copy": "^0.1.2" - } -} diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 242ac1d..0000000 --- a/yarn.lock +++ /dev/null @@ -1,15 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -clipboard-copy@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/clipboard-copy/-/clipboard-copy-3.1.0.tgz#4c59030a43d4988990564a664baeafba99f78ca4" - integrity sha512-Xsu1NddBXB89IUauda5BIq3Zq73UWkjkaQlPQbLNvNsd5WBMnTWPNKYR6HGaySOxGYZ+BKxP2E9X4ElnI3yiPA== - -use-clipboard-copy@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/use-clipboard-copy/-/use-clipboard-copy-0.1.2.tgz#83b16292dfa8ea262be714252022a8b4ad1c28c5" - integrity sha512-EkauxqyX+us4+Mfif/f61ew89EAOWIArqFpHR0jSG4SwwuDZzDAOeqO7gkK0vi+DQVADeB1RB3xqU3U0oOO3NQ== - dependencies: - clipboard-copy "^3.0.0" |