diff options
| author | jackyzha0 <[email protected]> | 2021-03-05 22:17:18 -0800 |
|---|---|---|
| committer | jackyzha0 <[email protected]> | 2021-03-05 22:17:18 -0800 |
| commit | 3e8500d466b641ef34c24f8b0de8163a44ba7a9e (patch) | |
| tree | ebb3411d636912b12f9fee14ecd494601cd796fc /frontend/src/components | |
| parent | remove extra langs (diff) | |
| download | ctrl-v-3e8500d466b641ef34c24f8b0de8163a44ba7a9e.tar.xz ctrl-v-3e8500d466b641ef34c24f8b0de8163a44ba7a9e.zip | |
refactoring css
Diffstat (limited to 'frontend/src/components')
21 files changed, 288 insertions, 312 deletions
diff --git a/frontend/src/components/App.js b/frontend/src/components/App.js deleted file mode 100644 index f28a220..0000000 --- a/frontend/src/components/App.js +++ /dev/null @@ -1,76 +0,0 @@ -import React from 'react'; -import NewPaste from './NewPaste' -import ViewPaste from './ViewPaste' -import Footer from './Footer' -import styled from 'styled-components' -import { - BrowserRouter as Router, - Switch, - Route, - useParams -} from "react-router-dom"; -import Raw from './renderers/Raw' - -const Logo = styled.div` - position: absolute; - bottom: 1.5em; - left: 2em; - opacity: 0.3; - - & h1 { - font-size: 3rem; - } -` - -const Main = styled.main` - margin-top: 10vh; -` - -const GetPasteWithParam = () => { - let { hash } = useParams(); - return <ViewPaste hash = {hash} />; -} - -const GetRawWithParam = () => { - let { hash } = useParams(); - return <Raw hash={hash} />; -} - -const App = () => { - return ( - <Router> - <Switch> - <Route path="/raw/:hash" - children={<GetRawWithParam />} - /> - <Route> - <div className="lt-content-column"> - <Logo> - <nav> - <h1 className="mainLogo"> - <a href="https://github.com/jackyzha0/ctrl-v">ctrl-v</a> - </h1> - </nav> - </Logo> - - <Main id="appElement"> - <Switch> - <Route path="/:hash" - children={<GetPasteWithParam />} - /> - <Route path="/"> - <NewPaste /> - </Route> - </Switch> - </Main> - - <Footer /> - </div> - </Route> - </Switch> - </Router> - ); -} - - -export default App; diff --git a/frontend/src/components/Footer.js b/frontend/src/components/Footer.js index 3186a42..1074fcb 100644 --- a/frontend/src/components/Footer.js +++ b/frontend/src/components/Footer.js @@ -3,6 +3,9 @@ import styled from 'styled-components' const SpacedFooter = styled.div` margin: 2em 0; + & a { + color: ${p => p.theme.colors.text}; + } ` const Link = (props) => { @@ -14,7 +17,7 @@ const Link = (props) => { const Footer = () => { return ( <SpacedFooter> - (c) 2020 — <Link link="https://jzhao.xyz/" name="jacky" />, <Link link="https://ryanmehri.tech/" name="ryan" /> + <p>(c) 2020 — <Link link="https://jzhao.xyz/" name="jacky" />, <Link link="https://ryanmehri.tech/" name="ryan" /></p> </SpacedFooter> ); } diff --git a/frontend/src/components/Form/Button.js b/frontend/src/components/Form/Button.js new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/frontend/src/components/Form/Button.js diff --git a/frontend/src/components/Form/Input.js b/frontend/src/components/Form/Input.js new file mode 100644 index 0000000..86af7d1 --- /dev/null +++ b/frontend/src/components/Form/Input.js @@ -0,0 +1,3 @@ +import {RelPositioning} from "../Inputs/shared"; +import React from "react"; + diff --git a/frontend/src/components/Form/index.js b/frontend/src/components/Form/index.js new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/frontend/src/components/Form/index.js diff --git a/frontend/src/components/Form/mixins.js b/frontend/src/components/Form/mixins.js new file mode 100644 index 0000000..dd26f7e --- /dev/null +++ b/frontend/src/components/Form/mixins.js @@ -0,0 +1,33 @@ +import {css} from 'styled-components'; + +export const Dropshadow = css` + box-shadow: 0 14px 28px rgba(27, 33, 48,0.06), 0 10px 10px rgba(27, 33, 48,0.02); +` + +export const InputLike = css` + width: 100%; + font-family: 'JetBrains Mono', monospace; + font-size: 0.8em; + padding: calc(0.8em - 1px); + border-radius: 3px; + border: 1px solid ${p => p.theme.colors.border}; + outline: none; + margin: 1.7em 0; +` + +export const ButtonLike = css` + font-family: 'JetBrains Mono', serif; + font-weight: 700; + padding: 0.8em 2em; + margin: 2em 0; + outline: 0; + + ${p => p.primary ? ` + color: #faf9f5; + background-color: #111111; + ` : ` + color: #faf9f5; + background-color: #111111; + `} + +`
\ No newline at end of file diff --git a/frontend/src/components/Inputs.js b/frontend/src/components/Inputs.js deleted file mode 100644 index e18133d..0000000 --- a/frontend/src/components/Inputs.js +++ /dev/null @@ -1,200 +0,0 @@ -import React, {useEffect, useRef} from 'react'; -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'; -import * as indentation from 'indent-textarea'; - -const RelPositioning = styled.div` - position: relative; - height: calc(100% - 4em); -` - -const FlexChild = styled.div` - display: block; - margin-left: 2em; -` - -const TitleInput = (props) => { - return ( - <RelPositioning> - <FloatingLabel - label="title" - id={props.id} - value={props.value} /> - <input - name="title" - readOnly={props.readOnly} - className="lt-shadow" - placeholder="Title" - id={props.id} - type="text" - autoFocus - autoComplete="off" - onChange={props.onChange} - value={props.value} /> - <CharLimit - content={props.value} - maxLength={props.maxLength} /> - </RelPositioning> - ); -} - -const PasteInput = ({content, ...props}) => { - const textInput = useRef(null); - - useEffect(() => { - indentation.watch(textInput.current); - }, [textInput]) - - return ( - <RelPositioning> - <FloatingLabel - label="content" - id={props.id} - value={content} /> - <textarea - name="content" - readOnly={props.readOnly} - placeholder="Paste your text here" - value={content} - id={props.id} - ref={textInput} - required - onChange={props.onChange} - className="lt-shadow" /> - <CharLimit - content={content} - maxLength={props.maxLength} /> - </RelPositioning> - ); -} - -const PassInput = (props) => { - return ( - <FlexChild> - <RelPositioning> - <FloatingLabel - label="password" - id={props.id} - value={props.value} /> - <input - name="pass" - className="lt-shadow" - placeholder="password" - type="password" - autoComplete="off" - onChange={props.onChange} - value={props.value} - id={props.id} /> - </RelPositioning> - </FlexChild> - ); -} - -const GenericDropdown = (props) => { - function _onSelect(option) { - props.onChange({ - target: { - name: props.label, - value: option.label - } - }); - } - - return ( - <FlexChild> - <Dropdown - options={props.options} - onChange={_onSelect} - value={props.value} - placeholder={props.placeholder} - id={props.id} /> - <FloatingLabel - label={props.label} - id={props.id} - value={props.value} /> - </FlexChild> - ); -} - -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.auto} - 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' - /> - ); -} - -const PasteURLInput = ({id, fullURL}) => { - return ( - <FlexChild> - <RelPositioning> - <FloatingLabel - label="url" - id={id} - value={id} /> - <input - name="paste_url" - className="lt-shadow" - type="text" - readOnly - autoFocus - id={id} - value={fullURL} /> - </RelPositioning> - </FlexChild> - ); -} - -export { TitleInput, PasteInput, PassInput, ExpiryInput, PasteURLInput, LangInput, ThemeInput }
\ No newline at end of file diff --git a/frontend/src/components/Inputs/Code.js b/frontend/src/components/Inputs/Code.js new file mode 100644 index 0000000..1353d95 --- /dev/null +++ b/frontend/src/components/Inputs/Code.js @@ -0,0 +1,35 @@ +import React, {useEffect, useRef} from "react"; +import * as indentation from "indent-textarea"; +import FloatingLabel from "../decorators/FloatingLabel"; +import CharLimit from "../decorators/CharLimit"; +import {RelPositioning} from "./shared"; + +export const Code = ({content, ...props}) => { + const textInput = useRef(null); + + useEffect(() => { + indentation.watch(textInput.current); + }, [textInput]) + + return ( + <RelPositioning> + <FloatingLabel + label="content" + id={props.id} + value={content} /> + <textarea + name="content" + readOnly={props.readOnly} + placeholder="Paste your text here" + value={content} + id={props.id} + ref={textInput} + required + onChange={props.onChange} + className="lt-shadow" /> + <CharLimit + content={content} + maxLength={props.maxLength} /> + </RelPositioning> + ); +}
\ No newline at end of file diff --git a/frontend/src/components/Inputs/Dropdown.js b/frontend/src/components/Inputs/Dropdown.js new file mode 100644 index 0000000..c467408 --- /dev/null +++ b/frontend/src/components/Inputs/Dropdown.js @@ -0,0 +1,84 @@ +import Dropdown from "react-dropdown"; +import FloatingLabel from "../decorators/FloatingLabel"; +import React from "react"; +import {LANGS, THEMES} from "../renderers/Code"; +import {FlexChild} from "./shared"; + +const GenericDropdown = (props) => { + function _onSelect(option) { + props.onChange({ + target: { + name: props.label, + value: option.label + } + }); + } + + return ( + <FlexChild> + <Dropdown + options={props.options} + onChange={_onSelect} + value={props.value} + placeholder={props.placeholder} + id={props.id} /> + <FloatingLabel + label={props.label} + id={props.id} + value={props.value} /> + </FlexChild> + ); +} + +export const Expiry = (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' + /> + ); +} + +export const Language = (props) => { + const options = Object.entries(LANGS).map((key, _) => ({ + 'value': key[1], + 'label': key[0] + })) + + return ( + <GenericDropdown + {...props} + options={options} + placeholder={LANGS.auto} + label='language' + /> + ); +} + +export const Theme = (props) => { + const options = Object.entries(THEMES).map((key) => ({ + 'value': key[1], + 'label': key[0] + })) + + return ( + <GenericDropdown + {...props} + options={options} + placeholder={'atom'} + label='theme' + /> + ); +}
\ No newline at end of file diff --git a/frontend/src/components/Inputs/Password.js b/frontend/src/components/Inputs/Password.js new file mode 100644 index 0000000..7311832 --- /dev/null +++ b/frontend/src/components/Inputs/Password.js @@ -0,0 +1,14 @@ +import React from "react"; +import {Labelled} from "./shared"; + +export const Password = (props) => <Labelled label="password"> + <input + name="pass" + className="lt-shadow" + placeholder="password" + type="password" + autoComplete="off" + onChange={props.onChange} + value={props.value} + id={props.id} /> +</Labelled>
\ No newline at end of file diff --git a/frontend/src/components/Inputs/Text.js b/frontend/src/components/Inputs/Text.js new file mode 100644 index 0000000..866da91 --- /dev/null +++ b/frontend/src/components/Inputs/Text.js @@ -0,0 +1,25 @@ +import CharLimit from "../decorators/CharLimit"; +import React from "react"; +import {Labelled} from "./shared"; + +export const Text = React.forwardRef(({label, id, readOnly, onChange, value, maxLength, autoFocus}, ref) => { + return ( + <Labelled label={label} value={value}> + <input + ref={ref} + name={label} + readOnly={readOnly} + className="lt-shadow" + placeholder="Title" + id={id} + type="text" + autoFocus={autoFocus} + autoComplete="off" + onChange={onChange} + value={value} /> + <CharLimit + content={value} + maxLength={maxLength} /> + </Labelled> + ); +})
\ No newline at end of file diff --git a/frontend/src/components/Inputs/index.js b/frontend/src/components/Inputs/index.js new file mode 100644 index 0000000..b16deb3 --- /dev/null +++ b/frontend/src/components/Inputs/index.js @@ -0,0 +1,6 @@ +import {Code} from './Code'; +import {Expiry, Language, Theme} from "./Dropdown"; +import {Password} from "./Password"; +import {Text} from "./Text"; + +export {Code, Expiry, Language, Theme, Password, Text};
\ No newline at end of file diff --git a/frontend/src/components/Inputs/shared.js b/frontend/src/components/Inputs/shared.js new file mode 100644 index 0000000..18ba164 --- /dev/null +++ b/frontend/src/components/Inputs/shared.js @@ -0,0 +1,25 @@ +import styled from "styled-components"; +import React from "react"; +import FloatingLabel from "../decorators/FloatingLabel"; + +export const RelPositioning = styled.div` + position: relative; + height: calc(100% - 4em); +` + +export const FlexChild = styled.div` + display: block; + margin-left: 2em; +` + +export const Labelled = ({label, value, children}) => { + console.log(children) + return (<FlexChild> + <RelPositioning> + <FloatingLabel label={label} value={value} > + <span>{label}</span> + {children} + </FloatingLabel> + </RelPositioning> + </FlexChild>) +}
\ No newline at end of file diff --git a/frontend/src/components/NewPaste.js b/frontend/src/components/NewPaste.js index a8405b8..9447611 100644 --- a/frontend/src/components/NewPaste.js +++ b/frontend/src/components/NewPaste.js @@ -1,5 +1,5 @@ import React, { useEffect, useState, useRef } from 'react'; -import { TitleInput, PasteInput } from './Inputs' +import { Text, Code } from './Inputs' import OptionsContainer from './Options' import Error from './Err' import { PostNewPaste } from '../helpers/httpHelper' @@ -78,7 +78,7 @@ const NewPaste = () => { } function renderPreview() { - const pasteInput = <PasteInput + const pasteInput = <Code onChange={(e) => { setContent(e.target.value) }} content={content} maxLength="100000" @@ -129,7 +129,8 @@ const NewPaste = () => { return ( <form onSubmit={handleSubmit}> <PasteModal hash={hash} /> - <TitleInput + <Text + label="title" onChange={(e) => {setTitle(e.target.value)}} value={title} maxLength="100" diff --git a/frontend/src/components/Options.js b/frontend/src/components/Options.js index 09f92f3..fb7e88c 100644 --- a/frontend/src/components/Options.js +++ b/frontend/src/components/Options.js @@ -1,6 +1,6 @@ import React from 'react'; import styled from 'styled-components' -import { PassInput, ExpiryInput, LangInput } from './Inputs' +import { Password, Expiry, Language } from './Inputs' const Flex = styled.div` float: right; @@ -17,15 +17,15 @@ const Flex = styled.div` const OptionsContainer = ({pass, lang, expiry, onPassChange, onLangChange, onExpiryChange}) => { return ( <Flex> - <PassInput + <Password value={pass} onChange={onPassChange} id="passwordInput" /> - <LangInput + <Language value={lang} onChange={onLangChange} id="langInput" /> - <ExpiryInput + <Expiry value={expiry} onChange={onExpiryChange} id="expiryInput" /> diff --git a/frontend/src/components/PasteInfo.js b/frontend/src/components/PasteInfo.js index bab7e23..114d0e1 100644 --- a/frontend/src/components/PasteInfo.js +++ b/frontend/src/components/PasteInfo.js @@ -1,7 +1,7 @@ import React from 'react'; import styled from 'styled-components' import { useHistory } from 'react-router-dom'; -import { ThemeInput } from './Inputs' +import { Theme } from './Inputs' import { exportComponentAsPNG } from "react-component-export-image"; const Bold = styled.span` @@ -68,7 +68,7 @@ const PasteInfo = (props) => { save png </Button> {renderable()} - <ThemeInput + <Theme value={props.theme} onChange={props.onChange} id="themeInput" /> diff --git a/frontend/src/components/ViewPaste.js b/frontend/src/components/ViewPaste.js index a4f1844..165fa6e 100644 --- a/frontend/src/components/ViewPaste.js +++ b/frontend/src/components/ViewPaste.js @@ -1,6 +1,6 @@ import React, { useEffect, useState, useRef } from 'react'; import Error from './Err'; -import { TitleInput } from './Inputs'; +import { Text } from './Inputs'; import CodeRenderer from './renderers/Code' import PasteInfo from './PasteInfo'; import PasswordModal from './modals/PasswordModal' @@ -130,7 +130,8 @@ const ViewPaste = (props) => { value={enteredPass} onChange={(e) => setEnteredPass(e.target.value)} validateCallback={validatePass} /> - <TitleInput + <Text + label="title" value={title} id="titleInput" readOnly /> diff --git a/frontend/src/components/Watermark.js b/frontend/src/components/Watermark.js new file mode 100644 index 0000000..027aeb6 --- /dev/null +++ b/frontend/src/components/Watermark.js @@ -0,0 +1,26 @@ +import styled from "styled-components"; +import React from "react"; + +const Logo = styled.h1` + position: absolute; + bottom: 0.75em; + left: 1em; + opacity: 0.3; + font-size: 50px; + margin: 0 0; + transition: opacity 0.5s cubic-bezier(.25,.8,.25,1); + + & > a { + text-decoration: none; + position: relative; + color: ${p => p.theme.colors.text}; + + } + + &:hover { + opacity: 1; + } +` +export const Watermark = () => <Logo> + <a href="https://github.com/jackyzha0/ctrl-v">ctrl-v</a> +</Logo>
\ No newline at end of file diff --git a/frontend/src/components/decorators/FloatingLabel.js b/frontend/src/components/decorators/FloatingLabel.js index ef56b44..1e5a427 100644 --- a/frontend/src/components/decorators/FloatingLabel.js +++ b/frontend/src/components/decorators/FloatingLabel.js @@ -2,19 +2,20 @@ import React from 'react'; import styled, { css } from 'styled-components' const StyledLabel = styled.label` - position: absolute; - top: 0.5em; - font-weight: 700; - font-size: 1em; - opacity: 0; - transition: all 0.5s cubic-bezier(.25,.8,.25,1); - - ${props => - (props.value.length > 0) && - css` - top: -0.1em; - opacity: 1 - `}; + & > span { + position: absolute; + top: 0.5em; + font-weight: 700; + font-size: 1em; + opacity: 0.5; + transition: all 0.5s cubic-bezier(.25,.8,.25,1); + + ${props => + (props.value?.length > 0) && + css` + opacity: 1 + `}; + } ` const FloatingLabel = (props) => { @@ -22,9 +23,8 @@ const FloatingLabel = (props) => { <StyledLabel label={props.label} value={props.value} - className={props.id} - htmlFor={props.id}> - {props.label} + > + {props.children} </StyledLabel> ); } diff --git a/frontend/src/components/modals/PasswordModal.js b/frontend/src/components/modals/PasswordModal.js index bf373cc..bf25eeb 100644 --- a/frontend/src/components/modals/PasswordModal.js +++ b/frontend/src/components/modals/PasswordModal.js @@ -1,6 +1,6 @@ import React, { useRef } from 'react'; import Modal from 'react-modal'; -import { PassInput } from '../Inputs' +import { Password } from '../Inputs' import { RightPad, LeftPad, ModalHeader, Padding } from './shared' import Error from '../Err'; @@ -36,7 +36,7 @@ const PasswordModal = (props) => { <ModalHeader><span role="img" aria-label="warning">🚧 </span>err: password protected</ModalHeader> </LeftPad> <RightPad> - <PassInput + <Password value={props.value} onChange={props.onChange} /> </RightPad> diff --git a/frontend/src/components/modals/PasteModal.js b/frontend/src/components/modals/PasteModal.js index 7b28abb..6c74e19 100644 --- a/frontend/src/components/modals/PasteModal.js +++ b/frontend/src/components/modals/PasteModal.js @@ -2,7 +2,7 @@ import React from 'react'; import Modal from 'react-modal'; import { LeftPad, ModalHeader, RightPad } from './shared' import { useHistory } from 'react-router-dom'; -import { PasteURLInput } from '../Inputs' +import { Text } from '../Inputs' import { useClipboard } from 'use-clipboard-copy'; const modalStyles = { @@ -39,11 +39,7 @@ const PasteModal = (props) => { <ModalHeader><span role="img" aria-label="success">📎 </span>paste created</ModalHeader> </LeftPad> <RightPad> - <PasteURLInput - id="paste_modal" - fullURL={fullURL} /> - <input - hidden + <Text type="text" value={fullURL} readOnly |