aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components')
-rw-r--r--frontend/src/components/PasteInfo.js6
-rw-r--r--frontend/src/components/hooks/shared.js74
-rw-r--r--frontend/src/components/hooks/useFetchPaste.js67
-rw-r--r--frontend/src/components/modals/PasteModal.js8
-rw-r--r--frontend/src/components/pages/NewPaste.js150
-rw-r--r--frontend/src/components/pages/Raw.js16
-rw-r--r--frontend/src/components/pages/ViewPaste.js65
-rw-r--r--frontend/src/components/renderers/Code.js2
-rw-r--r--frontend/src/components/renderers/InlineCode.js2
9 files changed, 9 insertions, 381 deletions
diff --git a/frontend/src/components/PasteInfo.js b/frontend/src/components/PasteInfo.js
index 6ab5b19..2f912fb 100644
--- a/frontend/src/components/PasteInfo.js
+++ b/frontend/src/components/PasteInfo.js
@@ -1,8 +1,8 @@
import React from 'react';
import styled from 'styled-components'
-import { useHistory } from 'react-router-dom';
import { Theme } from './Inputs'
import {Button} from "./Common/Button";
+import {useRouter} from "next/router";
const Bold = styled.span`
font-weight: 700
@@ -28,10 +28,10 @@ const Flex = styled.div`
`
const PasteInfo = (props) => {
- const history = useHistory();
+ const router = useRouter()
const redirRaw = () => {
const redirUrl = `/raw/${props.hash}`
- history.push(redirUrl);
+ router.push(redirUrl);
}
const renderable = () => {
diff --git a/frontend/src/components/hooks/shared.js b/frontend/src/components/hooks/shared.js
deleted file mode 100644
index 00d41e9..0000000
--- a/frontend/src/components/hooks/shared.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import axios from 'axios';
-
-// uncomment for local dev
-// const base = `http://localhost:8080/api`
-const base = `https://api.ctrl-v.app/api`
-export function fetchPaste(hash, pass = "") {
- const serverURL = `${base}/${hash}`
-
- if (pass === "") {
- return axios.get(serverURL)
- } else {
- const bodyFormData = new FormData();
- bodyFormData.set('password', pass);
- return axios({
- method: 'post',
- url: `${base}/${hash}`,
- data: bodyFormData,
- headers: { 'Content-Type': 'multipart/form-data' },
- })
- }
-}
-
-export function newPaste(paste) {
- const {title, content, language, pass, expiry} = paste
- const bodyFormData = new FormData();
- bodyFormData.set('title', title);
- bodyFormData.set('content', content);
- bodyFormData.set('language', language);
- bodyFormData.set('password', pass);
- bodyFormData.set('expiry', parseExpiry(expiry));
-
- return axios({
- method: 'post',
- url: base,
- data: bodyFormData,
- headers: { 'Content-Type': 'multipart/form-data' },
- })
-}
-
-export function parseExpiry(e) {
- var cur = new Date();
- var inSeconds = 0
- switch (e) {
- case '5 years':
- inSeconds = 600 * 6 * 24 * 7 * 4 * 12 * 5
- break;
- case '1 year':
- inSeconds = 600 * 6 * 24 * 7 * 4 * 12
- break;
- case '1 month':
- inSeconds = 600 * 6 * 24 * 7 * 4
- break;
- case '1 day':
- inSeconds = 600 * 6 * 24
- break;
- case '1 hour':
- inSeconds = 600 * 6
- break;
- case '10 min':
- inSeconds = 600
- break;
- case '1 week':
- default:
- inSeconds = 600 * 6 * 24 * 7
- break;
- }
- return new Date(cur.getTime() + inSeconds * 1000).toISOString();
-}
-
-export function fmtDateStr(dateString) {
- const d = new Date(dateString)
- const options = { hour: '2-digit', minute: '2-digit', year: 'numeric', month: 'long', day: 'numeric' }
- return d.toLocaleDateString("en-US", options).toLocaleLowerCase()
-} \ No newline at end of file
diff --git a/frontend/src/components/hooks/useFetchPaste.js b/frontend/src/components/hooks/useFetchPaste.js
deleted file mode 100644
index c394f5b..0000000
--- a/frontend/src/components/hooks/useFetchPaste.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import {useEffect, useState} from 'react'
-import {fetchPaste, fmtDateStr} from './shared'
-import {LANGS} from "../renderers/Code";
-
-export default (id) => {
- const [loading, setLoading] = useState(true)
- const [err, setErr] = useState()
- const [requiresAuth, setRequiresAuth] = useState(false)
- const [validPass, setValidPass] = useState(false)
- const [result, setResult] = useState({
- title: 'fetching paste...',
- content: '',
- language: LANGS.detect,
- expiry: '',
- })
-
- const handleErr = error => {
- const resp = error.response
-
- // network err
- if (!resp) {
- setErr(error.toString())
- return
- }
-
- // password protected
- if (resp.status === 401) {
- setRequiresAuth(true)
- return
- }
-
- // catch all
- const errTxt = `${resp.status}: ${resp.data}`
- setErr(errTxt)
- }
-
- // callback to try verifying with password
- const getWithPassword = (password, errorCallback) => {
- fetchPaste(id, password)
- .then(resp => {
- setValidPass(true)
- setStateFromData(resp.data)
- })
- .catch(e => errorCallback(e.response.data))
- }
-
-
- const setStateFromData = (data) => {
- document.title = data.title
- setResult({
- title: data.title,
- content: data.content,
- language: data.language,
- expiry: fmtDateStr(data.expiry)
- })
- }
-
- // initial fetch
- useEffect(() => {
- fetchPaste(id)
- .then(resp => setStateFromData(resp.data))
- .catch(handleErr)
- .finally(() => setLoading(false))
- }, [id])
-
- return { loading, err, requiresAuth, validPass, getWithPassword, result }
-} \ No newline at end of file
diff --git a/frontend/src/components/modals/PasteModal.js b/frontend/src/components/modals/PasteModal.js
index e7dbed2..a0fd309 100644
--- a/frontend/src/components/modals/PasteModal.js
+++ b/frontend/src/components/modals/PasteModal.js
@@ -1,21 +1,21 @@
import React from 'react';
import Modal from 'react-modal';
import {Form, ModalHeader, modalStyles} from './shared'
-import { useHistory } from 'react-router-dom';
+import { useRouter } from 'next/router'
import { Text } from '../Inputs'
import { useClipboard } from 'use-clipboard-copy';
import {Button} from "../Common/Button";
const PasteModal = (props) => {
- const history = useHistory();
- const fullURL = `${window.location.origin}/${props.hash}`;
+ const fullURL = `https://ctrl-v.app/${props.hash}`;
const clipboard = useClipboard({ copiedTimeout: 3000 });
Modal.setAppElement('body');
+ const router = useRouter()
const redir = (e) => {
e.preventDefault();
const redirUrl = `/${props.hash}`
- history.push(redirUrl);
+ router.push(redirUrl);
}
return (
diff --git a/frontend/src/components/pages/NewPaste.js b/frontend/src/components/pages/NewPaste.js
deleted file mode 100644
index 19161da..0000000
--- a/frontend/src/components/pages/NewPaste.js
+++ /dev/null
@@ -1,150 +0,0 @@
-import React, { useEffect, useState, useRef } from 'react';
-import { Text, Code } from '../Inputs'
-import OptionsContainer from '../Options'
-import Error from '../Err'
-import PasteModal from '../modals/PasteModal'
-import styled from 'styled-components'
-import CodeRenderer from '../renderers/Code'
-import Latex from '../renderers/Latex'
-import Markdown from '../renderers/Markdown'
-import {Button, SubmitButton} from "../Common/Button";
-import {newPaste} from "../hooks/shared";
-
-const Flex = styled.div`
- display: flex;
- flex-direction: row;
-`
-
-const FlexLeft = styled.div`
- flex: 0 0 calc(50% - 1em - 2px);
-`
-
-const FlexRight = styled.div`
- flex: 0 0 50%;
- max-width: calc(50% - 1em + 2px);
- margin-left: 2em;
-`
-
-const PreviewWrapper = styled.div`
- margin: 2em;
-`
-
-const NewPaste = () => {
- const [title, setTitle] = useState('');
- const [content, setContent] = useState('');
- const [pass, setPass] = useState('');
- const [language, setLanguage] = useState('detect');
- const [expiry, setExpiry] = useState('');
- const [hash, setHash] = useState('');
- const [isPreview, setIsPreview] = useState(false);
- const ErrorLabel = useRef(null);
-
- useEffect(() => {
- document.title = title === "" ? `ctrl-v` : `ctrl-v | ${title}`;
- }, [title])
-
- function handleSubmit(e) {
- e.preventDefault();
-
- // prevent resubmission
- if (!hash) {
- newPaste({title, content, language, pass, expiry})
- .then(resp => {setHash(resp.data.hash)})
- .catch((error) => {
- const resp = error.response
-
- // some weird err (e.g. network)
- if (!resp) {
- ErrorLabel.current.showMessage(error)
- return
- }
-
- // some weird err
- const errTxt = `${resp.status}: ${resp.data}`
- ErrorLabel.current.showMessage(errTxt)
- });
- }
- }
-
- function renderPreview() {
- const pasteInput = <Code
- setContentCallback={setContent}
- content={content}
- maxLength="100000" />
-
- if (isPreview) {
- var preview
- switch (language) {
- case 'latex':
- preview =
- <PreviewWrapper>
- <Latex
- content={content} />
- </PreviewWrapper>
- break
- case 'markdown':
- preview =
- <PreviewWrapper className='md' >
- <Markdown
- content={content} />
- </PreviewWrapper>
- break
- default:
- preview =
- <CodeRenderer
- lang={language}
- theme='atom'
- content={content} />
- }
-
- return (
- <Flex>
- <FlexLeft>
- {pasteInput}
- </FlexLeft>
- <FlexRight className='preview' >
- {preview}
- </FlexRight>
- </Flex>
- );
- } else {
- return (
- pasteInput
- );
- }
- }
-
- return (
- <form onSubmit={handleSubmit}>
- <PasteModal hash={hash} />
- <Text
- label="title"
- onChange={(e) => {setTitle(e.target.value)}}
- value={title}
- autoFocus
- maxLength="100"
- id="titleInput" />
- {renderPreview()}
- <OptionsContainer
- pass={pass}
- expiry={expiry}
- lang={language}
- onPassChange={(e) => { setPass(e.target.value) }}
- onLangChange={(e) => { setLanguage(e.target.value) }}
- onExpiryChange={(e) => { setExpiry(e.target.value) }} />
- <div>
- <SubmitButton type="submit" value="new paste" />
- {language !== 'detect' && <Button
- secondary
- type="button"
- onClick={() => setIsPreview(!isPreview)}>
- preview
- </Button>}
- </div>
- <br />
- <Error ref={ErrorLabel} />
- </form>
- );
-}
-
-export default NewPaste \ No newline at end of file
diff --git a/frontend/src/components/pages/Raw.js b/frontend/src/components/pages/Raw.js
deleted file mode 100644
index 23ef6bf..0000000
--- a/frontend/src/components/pages/Raw.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react';
-import styled from 'styled-components'
-import {CodeLike} from "../Common/mixins";
-import useFetchPaste from "../hooks/useFetchPaste";
-
-const RawText = styled.pre`
- ${CodeLike}
- padding: 0 1em;
-`
-
-const Raw = ({hash}) => {
- const { err, result } = useFetchPaste(hash)
- return <RawText>{result?.content || err}</RawText>
-}
-
-export default Raw \ No newline at end of file
diff --git a/frontend/src/components/pages/ViewPaste.js b/frontend/src/components/pages/ViewPaste.js
deleted file mode 100644
index bc61314..0000000
--- a/frontend/src/components/pages/ViewPaste.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import React, { useEffect, useState, useRef } from 'react';
-import Error from '../Err';
-import { Text } from '../Inputs';
-import CodeRenderer from '../renderers/Code'
-import PasteInfo from '../PasteInfo';
-import PasswordModal from '../modals/PasswordModal'
-import RenderDispatch from '../renderers/RenderDispatch'
-import useFetchPaste from "../hooks/useFetchPaste";
-
-const ViewPaste = (props) => {
- const { err, requiresAuth, validPass, getWithPassword, result } = useFetchPaste(props.hash)
- const {content, language, expiry, title} = result ?? {}
- const [theme, setTheme] = useState('atom');
- const [isRenderMode, setIsRenderMode] = useState(false);
- const [enteredPass, setEnteredPass] = useState('');
- const ErrorLabelRef = useRef(null);
-
- if (err) {
- ErrorLabelRef.current.showMessage(err, -1)
- }
-
- useEffect(() => {
- setIsRenderMode(language === 'latex' || language === 'markdown')
- }, [language])
-
- function getDisplay() {
- return isRenderMode ? <RenderDispatch
- language={language}
- content={content}
- /> : <CodeRenderer
- content={content}
- lang={language}
- theme={theme}
- id="pasteInput" />
- }
-
- return (
- <div>
- <PasswordModal
- hasPass={requiresAuth}
- validPass={validPass}
- value={enteredPass}
- onChange={(e) => setEnteredPass(e.target.value)}
- validateCallback={getWithPassword} />
- <Text
- label="title"
- value={title}
- id="titleInput"
- readOnly />
- {getDisplay()}
- <PasteInfo
- hash={props.hash}
- lang={language}
- theme={theme}
- expiry={expiry}
- toggleRenderCallback={() => setIsRenderMode(!isRenderMode)}
- isRenderMode={isRenderMode}
- onChange={(e) => setTheme(e.target.value)}
- err={<Error ref={ErrorLabelRef} />}
- />
- </div>
- );
-}
-
-export default ViewPaste \ No newline at end of file
diff --git a/frontend/src/components/renderers/Code.js b/frontend/src/components/renderers/Code.js
index 29531fc..85fd5ab 100644
--- a/frontend/src/components/renderers/Code.js
+++ b/frontend/src/components/renderers/Code.js
@@ -1,7 +1,7 @@
import React from 'react';
import SyntaxHighlighter from 'react-syntax-highlighter';
import virtualizedRenderer from 'react-syntax-highlighter-virtualized-renderer';
-import { atomOneLight, ascetic, atomOneDark, dracula, ocean } from 'react-syntax-highlighter/dist/esm/styles/hljs';
+import { atomOneLight, ascetic, atomOneDark, dracula, ocean } from 'react-syntax-highlighter/dist/cjs/styles/hljs';
import styled from 'styled-components'
import {Border, CodeLike, DropShadow, Rounded} from "../Common/mixins";
diff --git a/frontend/src/components/renderers/InlineCode.js b/frontend/src/components/renderers/InlineCode.js
index 44a3f58..2156503 100644
--- a/frontend/src/components/renderers/InlineCode.js
+++ b/frontend/src/components/renderers/InlineCode.js
@@ -1,6 +1,6 @@
import React from 'react';
import SyntaxHighlighter from 'react-syntax-highlighter';
-import { atomOneDark } from 'react-syntax-highlighter/dist/esm/styles/hljs';
+import { atomOneDark } from 'react-syntax-highlighter/dist/cjs/styles/hljs';
import { LANGS } from './Code'
const MarkdownCodeRenderer = ({language, value}) => {