diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..efe5fdb
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,9 @@
+{
+ "tabWidth": 2,
+ "useTabs": false,
+ "semi": true,
+ "singleQuote": true,
+ "trailingComma": "es5",
+ "arrowParens": "avoid",
+ "quoteProps": "consistent"
+}
\ No newline at end of file
diff --git a/src/App.js b/src/App.js
index a32580a..c3bc33f 100644
--- a/src/App.js
+++ b/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 ;
+ return (
+
+ );
}
function get404Message(pasteId) {
@@ -82,4 +90,4 @@ function get404Message(pasteId) {
not found: '${pasteId}'
maybe the paste expired?
`;
-}
\ No newline at end of file
+}
diff --git a/src/components/Editor.js b/src/components/Editor.js
index c255044..0ea0047 100644
--- a/src/components/Editor.js
+++ b/src/components/Editor.js
@@ -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 <>
-
-
-
-
- >
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
+
+// 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];
}
diff --git a/src/components/EditorControls.js b/src/components/EditorControls.js
index 7c2feb5..9c8d283 100644
--- a/src/components/EditorControls.js
+++ b/src/components/EditorControls.js
@@ -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
-
+
-
-
+
+
- )
+ );
}
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) {
diff --git a/src/components/EditorPrismStyle.js b/src/components/EditorPrismStyle.js
index 39a6e75..6f5e7a0 100644
--- a/src/components/EditorPrismStyle.js
+++ b/src/components/EditorPrismStyle.js
@@ -1,7 +1,7 @@
import styled from 'styled-components';
export default function EditorPrismStyle({ children }) {
- return {children}
+ return {children};
}
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;
}
-`;
\ No newline at end of file
+`;
diff --git a/src/components/EditorTextArea.js b/src/components/EditorTextArea.js
index c7eacd7..2892966 100644
--- a/src/components/EditorTextArea.js
+++ b/src/components/EditorTextArea.js
@@ -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}
/>
- )
+ );
}
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,
+ });
}
}
diff --git a/src/components/Menu.js b/src/components/Menu.js
index 369190c..e8aa365 100644
--- a/src/components/Menu.js
+++ b/src/components/Menu.js
@@ -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 (
- )
-}
\ No newline at end of file
+ );
+};
diff --git a/src/style/themes.js b/src/style/themes.js
index be6fd41..9a811d8 100644
--- a/src/style/themes.js
+++ b/src/style/themes.js
@@ -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;
\ No newline at end of file
+export default themes;
diff --git a/src/highlighting.js b/src/util/highlighting.js
similarity index 93%
rename from src/highlighting.js
rename to src/util/highlighting.js
index 6f96ebc..8e87074 100644
--- a/src/highlighting.js
+++ b/src/util/highlighting.js
@@ -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);
}