formatting
This commit is contained in:
22
src/App.js
22
src/App.js
@@ -17,8 +17,10 @@ async function loadFromBytebin(id) {
|
||||
const resp = await fetch('https://bytebin.lucko.me/' + id);
|
||||
if (resp.ok) {
|
||||
const content = await resp.text();
|
||||
const type = parseLanguageFromContentType(resp.headers.get('content-type'));
|
||||
|
||||
const type = parseLanguageFromContentType(
|
||||
resp.headers.get('content-type')
|
||||
);
|
||||
|
||||
document.title = 'paste | ' + id;
|
||||
return { ok: true, content, type };
|
||||
} else {
|
||||
@@ -52,7 +54,7 @@ export default function App() {
|
||||
useEffect(() => {
|
||||
if (pasteId && state === INITIAL) {
|
||||
setState(LOADING);
|
||||
setContent('Loading...')
|
||||
setContent('Loading...');
|
||||
loadFromBytebin(pasteId).then(({ ok, content, type }) => {
|
||||
if (ok) {
|
||||
setContent(content);
|
||||
@@ -63,11 +65,17 @@ export default function App() {
|
||||
setContent(get404Message(pasteId));
|
||||
}
|
||||
setState(LOADED);
|
||||
})
|
||||
});
|
||||
}
|
||||
}, [pasteId, state, setContent])
|
||||
}, [pasteId, state, setContent]);
|
||||
|
||||
return <Editor content={content} setContent={setContent} contentType={contentType} />;
|
||||
return (
|
||||
<Editor
|
||||
content={content}
|
||||
setContent={setContent}
|
||||
contentType={contentType}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function get404Message(pasteId) {
|
||||
@@ -82,4 +90,4 @@ function get404Message(pasteId) {
|
||||
not found: '${pasteId}'
|
||||
maybe the paste expired?
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,38 +8,16 @@ import themes from '../style/themes';
|
||||
|
||||
export default function Editor({ content, setContent, contentType }) {
|
||||
const [language, setLanguage] = useState('plain');
|
||||
const [theme, setTheme] = useState(() => {
|
||||
const preference = ls.get('theme');
|
||||
if (preference && themes[preference]) {
|
||||
return preference;
|
||||
} else {
|
||||
return 'dark';
|
||||
}
|
||||
});
|
||||
const [fontSize, setFontSize] = useState(() => {
|
||||
const preference = ls.get('fontsize');
|
||||
if (preference && preference >= 10 && preference <= 22) {
|
||||
return preference;
|
||||
} else {
|
||||
return 16;
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (theme === 'dark') {
|
||||
ls.remove('theme');
|
||||
} else {
|
||||
ls.set('theme', theme);
|
||||
}
|
||||
}, [theme]);
|
||||
|
||||
useEffect(() => {
|
||||
if (fontSize === 16) {
|
||||
ls.remove('fontsize');
|
||||
} else {
|
||||
ls.set('fontsize', fontSize);
|
||||
}
|
||||
}, [fontSize]);
|
||||
const [theme, setTheme] = usePreference(
|
||||
'theme',
|
||||
'dark',
|
||||
pref => !!themes[pref]
|
||||
);
|
||||
const [fontSize, setFontSize, fontSizeCheck] = usePreference(
|
||||
'fontsize',
|
||||
16,
|
||||
pref => pref >= 10 && pref <= 22
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (contentType) {
|
||||
@@ -48,21 +26,53 @@ export default function Editor({ content, setContent, contentType }) {
|
||||
}, [contentType]);
|
||||
|
||||
function zoom(delta) {
|
||||
const result = fontSize + delta;
|
||||
if (result && result >= 10 && result <= 22) {
|
||||
setFontSize(result);
|
||||
const newFontSize = fontSize + delta;
|
||||
if (fontSizeCheck(newFontSize)) {
|
||||
setFontSize(newFontSize);
|
||||
}
|
||||
}
|
||||
|
||||
return <>
|
||||
<ThemeProvider theme={themes[theme]}>
|
||||
<EditorControls
|
||||
code={content} setCode={setContent}
|
||||
language={language} setLanguage={setLanguage}
|
||||
theme={theme} setTheme={setTheme}
|
||||
zoom={zoom}
|
||||
/>
|
||||
<EditorTextArea code={content} setCode={setContent} language={language} fontSize={fontSize} />
|
||||
</ThemeProvider>
|
||||
</>
|
||||
return (
|
||||
<>
|
||||
<ThemeProvider theme={themes[theme]}>
|
||||
<EditorControls
|
||||
code={content}
|
||||
setCode={setContent}
|
||||
language={language}
|
||||
setLanguage={setLanguage}
|
||||
theme={theme}
|
||||
setTheme={setTheme}
|
||||
zoom={zoom}
|
||||
/>
|
||||
<EditorTextArea
|
||||
code={content}
|
||||
setCode={setContent}
|
||||
language={language}
|
||||
fontSize={fontSize}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// hook used to load "preference" settings from local storage, or fall back to a default value.
|
||||
function usePreference(id, defaultValue, valid) {
|
||||
const [value, setValue] = useState(() => {
|
||||
const pref = ls.get(id);
|
||||
if (pref && valid(pref)) {
|
||||
return pref;
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (value === defaultValue) {
|
||||
ls.remove(id);
|
||||
} else {
|
||||
ls.set(id, value);
|
||||
}
|
||||
}, [value, id, defaultValue]);
|
||||
|
||||
return [value, setValue, valid];
|
||||
}
|
||||
|
||||
@@ -8,24 +8,32 @@ import { MenuButton, Button } from './Menu';
|
||||
import { languageIds } from '../highlighting';
|
||||
import themes from '../style/themes';
|
||||
|
||||
export default function EditorControls({ code, setCode, language, setLanguage, theme, setTheme, zoom }) {
|
||||
export default function EditorControls({
|
||||
code,
|
||||
setCode,
|
||||
language,
|
||||
setLanguage,
|
||||
theme,
|
||||
setTheme,
|
||||
zoom,
|
||||
}) {
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [recentlySaved, setRecentlySaved] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setRecentlySaved(false);
|
||||
}, [code, language])
|
||||
}, [code, language]);
|
||||
|
||||
const save = useCallback(() => {
|
||||
if (!code || recentlySaved) {
|
||||
return;
|
||||
}
|
||||
setSaving(true);
|
||||
saveToBytebin(code, language).then((pasteId) => {
|
||||
saveToBytebin(code, language).then(pasteId => {
|
||||
setSaving(false);
|
||||
setRecentlySaved(true);
|
||||
history.replace({
|
||||
pathname: pasteId
|
||||
pathname: pasteId,
|
||||
});
|
||||
copy(window.location.href);
|
||||
document.title = 'paste | ' + pasteId;
|
||||
@@ -33,8 +41,8 @@ export default function EditorControls({ code, setCode, language, setLanguage, t
|
||||
}, [code, language, recentlySaved]);
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (e) => {
|
||||
if ((e.ctrlKey || e.metaKey)) {
|
||||
const listener = e => {
|
||||
if (e.ctrlKey || e.metaKey) {
|
||||
if (e.key === 's' || e.key === 'S') {
|
||||
e.preventDefault();
|
||||
save();
|
||||
@@ -45,8 +53,8 @@ export default function EditorControls({ code, setCode, language, setLanguage, t
|
||||
zoom(e.key === '=' ? 1 : -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', listener);
|
||||
return () => window.removeEventListener('keydown', listener);
|
||||
}, [save, zoom]);
|
||||
@@ -55,7 +63,7 @@ export default function EditorControls({ code, setCode, language, setLanguage, t
|
||||
setCode('');
|
||||
setLanguage('plain');
|
||||
history.replace({
|
||||
pathname: '/'
|
||||
pathname: '/',
|
||||
});
|
||||
document.title = 'paste';
|
||||
}
|
||||
@@ -65,21 +73,36 @@ export default function EditorControls({ code, setCode, language, setLanguage, t
|
||||
<Section>
|
||||
<Button onClick={reset}>[new]</Button>
|
||||
<Button onClick={save}>
|
||||
{recentlySaved
|
||||
? '[link copied!]'
|
||||
: saving ? '[saving...]' : '[save]'
|
||||
}
|
||||
{recentlySaved ? '[link copied!]' : saving ? '[saving...]' : '[save]'}
|
||||
</Button>
|
||||
<MenuButton label="language" value={language} setValue={setLanguage} ids={languageIds} />
|
||||
<MenuButton
|
||||
label="language"
|
||||
value={language}
|
||||
setValue={setLanguage}
|
||||
ids={languageIds}
|
||||
/>
|
||||
</Section>
|
||||
<Section>
|
||||
<Button onClick={() => zoom(1)}>[+ </Button>
|
||||
<Button onClick={() => zoom(-1)}> -]</Button>
|
||||
<MenuButton label="theme" value={theme} setValue={setTheme} ids={Object.keys(themes)} />
|
||||
<Button className="optional" as="a" href="https://github.com/lucko/paste" target="_blank" rel="noreferrer">[about]</Button>
|
||||
<MenuButton
|
||||
label="theme"
|
||||
value={theme}
|
||||
setValue={setTheme}
|
||||
ids={Object.keys(themes)}
|
||||
/>
|
||||
<Button
|
||||
className="optional"
|
||||
as="a"
|
||||
href="https://github.com/lucko/paste"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
[about]
|
||||
</Button>
|
||||
</Section>
|
||||
</Header>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const Header = styled.header`
|
||||
@@ -123,9 +146,9 @@ async function saveToBytebin(code, language) {
|
||||
headers: {
|
||||
'Content-Type': contentType,
|
||||
'Content-Encoding': 'gzip',
|
||||
'Accept': 'application/json'
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: compressed
|
||||
body: compressed,
|
||||
});
|
||||
|
||||
if (resp.ok) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
export default function EditorPrismStyle({ children }) {
|
||||
return <Main>{children}</Main>
|
||||
return <Main>{children}</Main>;
|
||||
}
|
||||
|
||||
const Main = styled.main`
|
||||
@@ -9,8 +9,8 @@ const Main = styled.main`
|
||||
color: ${props => props.theme.editor.primary};
|
||||
background: ${props => props.theme.editor.background};
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
code[class*='language-'],
|
||||
pre[class*='language-'] {
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
font-size: 1em;
|
||||
@@ -31,29 +31,33 @@ const Main = styled.main`
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
|
||||
pre[class*='language-']::-moz-selection,
|
||||
pre[class*='language-'] ::-moz-selection,
|
||||
code[class*='language-']::-moz-selection,
|
||||
code[class*='language-'] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: ${props => props.theme.editor.selection};
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection, code[class*="language-"] ::selection {
|
||||
pre[class*='language-']::selection,
|
||||
pre[class*='language-'] ::selection,
|
||||
code[class*='language-']::selection,
|
||||
code[class*='language-'] ::selection {
|
||||
text-shadow: none;
|
||||
background: ${props => props.theme.editor.selection};
|
||||
}
|
||||
|
||||
@media print {
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
code[class*='language-'],
|
||||
pre[class*='language-'] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
pre[class*='language-'] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
margin: 0.5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -84,7 +88,7 @@ const Main = styled.main`
|
||||
.token.boolean {
|
||||
color: ${props => props.theme.editor.keyword};
|
||||
}
|
||||
|
||||
|
||||
.token.constant {
|
||||
color: ${props => props.theme.editor.constant};
|
||||
}
|
||||
@@ -152,4 +156,4 @@ const Main = styled.main`
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -29,12 +29,12 @@ export default function EditorTextArea({ code, setCode, language, fontSize }) {
|
||||
placeholder={'Paste (or type) some code...'}
|
||||
padding={10}
|
||||
size={fontSize}
|
||||
textareaId='code-area'
|
||||
textareaId="code-area"
|
||||
autoFocus={true}
|
||||
onKeyDown={keydown}
|
||||
/>
|
||||
</EditorPrismStyle>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const StyledReactEditor = styled(ReactEditor)`
|
||||
@@ -101,29 +101,43 @@ function handleKeydown(e, editor) {
|
||||
if (pair) {
|
||||
e.preventDefault();
|
||||
editor._applyEdits({
|
||||
value: value.substring(0, selectionStart) + pair[0] + pair[1] + value.substring(selectionEnd),
|
||||
value:
|
||||
value.substring(0, selectionStart) +
|
||||
pair[0] +
|
||||
pair[1] +
|
||||
value.substring(selectionEnd),
|
||||
selectionStart: selectionStart + 1,
|
||||
selectionEnd: selectionStart + 1
|
||||
selectionEnd: selectionStart + 1,
|
||||
});
|
||||
}
|
||||
|
||||
// When pressing enter immediately after an open bracket, automatically add a newline plus extra indent
|
||||
if (e.keyCode === KEYCODE_ENTER && selectionEnd !== 0 && value[selectionEnd - 1] === '{') {
|
||||
if (
|
||||
e.keyCode === KEYCODE_ENTER &&
|
||||
selectionEnd !== 0 &&
|
||||
value[selectionEnd - 1] === '{'
|
||||
) {
|
||||
const line = editor._getLines(value, selectionStart).pop();
|
||||
const matches = line.match(/^\s+/);
|
||||
const existingIndent = (matches ? matches[0] : '');
|
||||
const existingIndent = matches ? matches[0] : '';
|
||||
|
||||
const indent = ' ';
|
||||
const updatedValue = value.substring(0, selectionStart) +
|
||||
'\n' + existingIndent + indent +
|
||||
'\n' + existingIndent + value.substring(selectionEnd);
|
||||
const updatedSelection = selectionStart + 1 /* newline */ + existingIndent.length + indent.length;
|
||||
const updatedValue =
|
||||
value.substring(0, selectionStart) +
|
||||
'\n' +
|
||||
existingIndent +
|
||||
indent +
|
||||
'\n' +
|
||||
existingIndent +
|
||||
value.substring(selectionEnd);
|
||||
const updatedSelection =
|
||||
selectionStart + 1 /* newline */ + existingIndent.length + indent.length;
|
||||
|
||||
e.preventDefault();
|
||||
editor._applyEdits({
|
||||
value: updatedValue,
|
||||
selectionStart: updatedSelection,
|
||||
selectionEnd: updatedSelection
|
||||
})
|
||||
selectionEnd: updatedSelection,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ export const Button = styled.div`
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 .25em;
|
||||
padding: 0 0.25em;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
|
||||
@@ -32,7 +32,7 @@ const Menu = styled.ul`
|
||||
overflow: auto;
|
||||
|
||||
> li {
|
||||
padding: .15em .5em;
|
||||
padding: 0.15em 0.5em;
|
||||
}
|
||||
|
||||
> li:hover {
|
||||
@@ -48,7 +48,7 @@ export const MenuButton = ({ label, ids, value, setValue }) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const listener = (e) => setOpen(false);
|
||||
const listener = e => setOpen(false);
|
||||
window.addEventListener('click', listener);
|
||||
return () => window.removeEventListener('click', listener);
|
||||
}, [open, setOpen]);
|
||||
@@ -65,12 +65,17 @@ export const MenuButton = ({ label, ids, value, setValue }) => {
|
||||
|
||||
return (
|
||||
<Button onClick={toggleOpen}>
|
||||
[<span>{label}: </span>{value}]
|
||||
[<span>{label}: </span>
|
||||
{value}]
|
||||
{open && (
|
||||
<Menu>
|
||||
{ids.map(id => <li key={id} onClick={e => select(e, id)}>{id}</li>)}
|
||||
<Menu>
|
||||
{ids.map(id => (
|
||||
<li key={id} onClick={e => select(e, id)}>
|
||||
{id}
|
||||
</li>
|
||||
))}
|
||||
</Menu>
|
||||
)}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -22,8 +22,8 @@ const themes = {
|
||||
keyword: '#07a',
|
||||
function: '#DD4A68',
|
||||
className: '#DD4A68',
|
||||
variable: '#e90'
|
||||
}
|
||||
variable: '#e90',
|
||||
},
|
||||
},
|
||||
dark: {
|
||||
primary: '#022550',
|
||||
@@ -48,9 +48,9 @@ const themes = {
|
||||
keyword: '#1CCBEF',
|
||||
function: '#BCBCBC',
|
||||
className: '#82CF75',
|
||||
variable: '#ee9900'
|
||||
}
|
||||
}
|
||||
variable: '#ee9900',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default themes;
|
||||
export default themes;
|
||||
|
||||
@@ -18,7 +18,7 @@ import 'prismjs/components/prism-javascript';
|
||||
import 'prismjs/components/prism-json';
|
||||
import 'prismjs/components/prism-kotlin';
|
||||
//import 'prismjs/components/prism-log';
|
||||
import './prism/prism-log'; // TODO replace with above once released
|
||||
import '../prism/prism-log'; // TODO replace with above once released
|
||||
import 'prismjs/components/prism-markdown';
|
||||
//import 'prismjs/components/prism-php';
|
||||
import 'prismjs/components/prism-protobuf';
|
||||
@@ -58,10 +58,10 @@ export const languageIds = [
|
||||
'rust',
|
||||
'sql',
|
||||
'toml',
|
||||
'yaml'
|
||||
]
|
||||
'yaml',
|
||||
];
|
||||
|
||||
export function getHighlighter(language) {
|
||||
const grammar = languages[language] || {};
|
||||
return (input) => highlight(input, grammar);
|
||||
return input => highlight(input, grammar);
|
||||
}
|
||||
Reference in New Issue
Block a user