2021-03-26 22:00:12 +00:00
|
|
|
import { useState, useEffect } from 'react';
|
2021-03-27 11:49:46 +00:00
|
|
|
import styled from 'styled-components';
|
2021-03-26 22:00:12 +00:00
|
|
|
import { gzip } from 'pako';
|
|
|
|
|
import history from 'history/browser';
|
|
|
|
|
import copy from 'copy-to-clipboard';
|
|
|
|
|
|
2021-03-27 13:51:48 +00:00
|
|
|
import { MenuButton, Button } from './Menu';
|
2021-03-27 11:49:46 +00:00
|
|
|
import { languageIds } from '../highlighting';
|
|
|
|
|
import themes from '../style/themes';
|
|
|
|
|
|
2021-03-27 11:59:56 +00:00
|
|
|
export default function EditorControls({ code, setCode, language, setLanguage, theme, setTheme }) {
|
2021-03-26 22:00:12 +00:00
|
|
|
const [saving, setSaving] = useState(false);
|
|
|
|
|
const [recentlySaved, setRecentlySaved] = useState(false);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
setRecentlySaved(false);
|
|
|
|
|
}, [code, language])
|
|
|
|
|
|
2021-03-27 12:16:04 +00:00
|
|
|
useEffect(() => {
|
|
|
|
|
const listener = (e) => {
|
|
|
|
|
if ((e.ctrlKey || e.metaKey)) {
|
|
|
|
|
if (e.key === 's' || e.key === 'S') {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
save();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.addEventListener('keydown', listener);
|
|
|
|
|
return () => window.removeEventListener('keydown', listener);
|
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
}, []);
|
|
|
|
|
|
2021-03-26 22:00:12 +00:00
|
|
|
function save() {
|
|
|
|
|
if (!code || recentlySaved) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
setSaving(true);
|
|
|
|
|
saveToBytebin(code, language).then((pasteId) => {
|
|
|
|
|
setSaving(false);
|
|
|
|
|
setRecentlySaved(true);
|
|
|
|
|
history.replace({
|
2021-03-27 11:59:56 +00:00
|
|
|
pathname: pasteId
|
2021-03-26 22:00:12 +00:00
|
|
|
});
|
|
|
|
|
copy(window.location.href);
|
|
|
|
|
document.title = 'paste | ' + pasteId;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-27 11:59:56 +00:00
|
|
|
function reset() {
|
|
|
|
|
setCode('');
|
|
|
|
|
setLanguage('plain');
|
|
|
|
|
history.replace({
|
|
|
|
|
pathname: '/'
|
|
|
|
|
});
|
|
|
|
|
document.title = 'paste';
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-27 11:49:46 +00:00
|
|
|
return (
|
|
|
|
|
<Header>
|
|
|
|
|
<Section>
|
2021-03-27 11:59:56 +00:00
|
|
|
<Button onClick={reset}>[new]</Button>
|
2021-03-27 11:49:46 +00:00
|
|
|
<Button onClick={save}>
|
|
|
|
|
{recentlySaved
|
|
|
|
|
? '[link copied!]'
|
|
|
|
|
: saving ? '[saving...]' : '[save]'
|
|
|
|
|
}
|
|
|
|
|
</Button>
|
|
|
|
|
<MenuButton label="language" value={language} setValue={setLanguage} ids={languageIds} />
|
|
|
|
|
</Section>
|
|
|
|
|
<Section>
|
|
|
|
|
<MenuButton label="theme" value={theme} setValue={setTheme} ids={Object.keys(themes)} />
|
|
|
|
|
<Button as="a" href="https://github.com/lucko/paste" target="_blank" rel="noreferrer">[about]</Button>
|
|
|
|
|
</Section>
|
|
|
|
|
</Header>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Header = styled.header`
|
|
|
|
|
position: fixed;
|
|
|
|
|
z-index: 2;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 2em;
|
|
|
|
|
color: ${props => props.theme.primary};
|
|
|
|
|
background: ${props => props.theme.secondary};
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const Section = styled.div`
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
`;
|
|
|
|
|
|
2021-03-27 13:09:03 +00:00
|
|
|
function langaugeToContentType(language) {
|
|
|
|
|
if (language === 'json') {
|
|
|
|
|
return 'application/json';
|
|
|
|
|
} else {
|
|
|
|
|
return 'text/' + language;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-26 22:00:12 +00:00
|
|
|
async function saveToBytebin(code, language) {
|
|
|
|
|
try {
|
|
|
|
|
const compressed = gzip(code);
|
2021-03-27 13:09:03 +00:00
|
|
|
const contentType = langaugeToContentType(language);
|
2021-03-26 22:00:12 +00:00
|
|
|
|
|
|
|
|
const resp = await fetch('https://bytebin.lucko.me/post', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': contentType,
|
|
|
|
|
'Content-Encoding': 'gzip',
|
|
|
|
|
'Accept': 'application/json'
|
|
|
|
|
},
|
|
|
|
|
body: compressed
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (resp.ok) {
|
|
|
|
|
const json = await resp.json();
|
|
|
|
|
return json.key;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.log(e);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|