Change app layout

master
Boris Kubiak 2020-04-22 18:50:44 +02:00
parent a162b8001a
commit d13021baec
4 changed files with 60 additions and 33 deletions

View File

@ -10,14 +10,12 @@ As a result, there is no risk of data being lost or deleted. Nobody will ever be
> **Note:** This project is a clone of [Topaz's paste service][topaz-example], with a reworked design and additional features such as syntax highlighting, line numbers, and more > **Note:** This project is a clone of [Topaz's paste service][topaz-example], with a reworked design and additional features such as syntax highlighting, line numbers, and more
## How it works ## How it works
When you click on "Generate Link", the whole text is compressed using the [LZMA algorithm](https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Markov_chain_algorithm), encoded in [Base64](https://en.wikipedia.org/wiki/Base64), and put in the optional fragment at the end of the URL: `bokub.github.io/paste/#<data is here>` When you click on "Generate Link", the whole text is compressed using the [LZMA algorithm](https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Markov_chain_algorithm), encoded in [Base64](https://en.wikipedia.org/wiki/Base64), and put in the optional fragment at the end of the URL: `bokub.github.io/paste/#<data is here>`
When you open a link which contains data, the fragment is decoded, decompressed, and displayed in the editor When you open a link which contains data, the fragment is decoded, decompressed, and displayed in the editor
## Embedded Paste snippets ## Embedded Paste snippets
You can include code snippets into your own website by clicking the _Embed_ button and using the generated HTML code You can include code snippets into your own website by clicking the _Embed_ button and using the generated HTML code

View File

@ -34,17 +34,18 @@ npm/codemirror@5.52.0/theme/dracula.min.css
<link href="favicon.ico" rel="icon" type="image/x-icon" /> <link href="favicon.ico" rel="icon" type="image/x-icon" />
</head> </head>
<body> <body>
<div id="progress"></div> <div id="controls">
<div id="editor"></div> <div class="title">{ Paste }</div>
<div id="footer">
<label for="language"></label
><select id="language"></select>
<span class="grow"></span> <span class="grow"></span>
<select id="language"></select>
<button onclick="generateLink('url')" type="button">Generate link</button> <button onclick="generateLink('url')" type="button">Generate link</button>
<button onclick="generateLink('markdown')" type="button">Generate markdown</button> <button onclick="generateLink('markdown')" type="button">Generate markdown</button>
<button onclick="generateLink('iframe')" type="button">Embed</button> <button onclick="generateLink('iframe')" type="button">Embed</button>
</div> </div>
<div id="copy" style="display: none"> <div id="progress"></div>
<div id="editor"></div>
<div id="copy" style="display: none;">
<input <input
type="text" type="text"
value="copy me" value="copy me"

View File

@ -19,7 +19,7 @@ const initCodeEditor = () => {
lineNumbers: true, lineNumbers: true,
theme: 'dracula', theme: 'dracula',
readOnly: readOnly, readOnly: readOnly,
scrollbarStyle: 'simple' scrollbarStyle: 'simple',
}); });
if (readOnly) { if (readOnly) {
document.body.classList.add('readonly'); document.body.classList.add('readonly');
@ -29,17 +29,17 @@ const initCodeEditor = () => {
const initLangSelector = () => { const initLangSelector = () => {
select = new SlimSelect({ select = new SlimSelect({
select: '#language', select: '#language',
data: CodeMirror.modeInfo.map(e => ({ data: CodeMirror.modeInfo.map((e) => ({
text: e.name, text: e.name,
value: slugify(e.name), value: slugify(e.name),
data: { mime: e.mime, mode: e.mode } data: { mime: e.mime, mode: e.mode },
})), })),
showContent: 'up', showContent: 'down',
onChange: e => { onChange: (e) => {
const language = e.data || { mime: null, mode: null }; const language = e.data || { mime: null, mode: null };
editor.setOption('mode', language.mime); editor.setOption('mode', language.mime);
CodeMirror.autoLoadMode(editor, language.mode); CodeMirror.autoLoadMode(editor, language.mode);
} },
}); });
select.set(decodeURIComponent(new URLSearchParams(window.location.search).get('lang') || 'plain-text')); select.set(decodeURIComponent(new URLSearchParams(window.location.search).get('lang') || 'plain-text'));
@ -66,7 +66,7 @@ const initClipboard = () => {
}); });
}; };
const generateLink = mode => { const generateLink = (mode) => {
compress(editor.getValue(), (base64, err) => { compress(editor.getValue(), (base64, err) => {
if (err) { if (err) {
alert('Failed to compress data: ' + err); alert('Failed to compress data: ' + err);
@ -78,7 +78,7 @@ const generateLink = mode => {
}; };
// Open the "Copy" bar and select the content // Open the "Copy" bar and select the content
const showCopyBar = dataToCopy => { const showCopyBar = (dataToCopy) => {
const linkInput = document.getElementById('copy-link'); const linkInput = document.getElementById('copy-link');
linkInput.value = dataToCopy; linkInput.value = dataToCopy;
linkInput.setSelectionRange(0, dataToCopy.length); linkInput.setSelectionRange(0, dataToCopy.length);
@ -86,7 +86,7 @@ const showCopyBar = dataToCopy => {
}; };
// Close the "Copy" bar // Close the "Copy" bar
const hideCopyBar = success => { const hideCopyBar = (success) => {
const copyButton = document.getElementById('copy-btn'); const copyButton = document.getElementById('copy-btn');
const copyBar = document.getElementById('copy'); const copyBar = document.getElementById('copy');
if (!success) { if (!success) {
@ -124,14 +124,14 @@ const decompress = (base64, cb) => {
const req = new XMLHttpRequest(); const req = new XMLHttpRequest();
req.open('GET', 'data:application/octet;base64,' + base64); req.open('GET', 'data:application/octet;base64,' + base64);
req.responseType = 'arraybuffer'; req.responseType = 'arraybuffer';
req.onload = e => { req.onload = (e) => {
lzma.decompress( lzma.decompress(
new Uint8Array(e.target.response), new Uint8Array(e.target.response),
(result, err) => { (result, err) => {
progressBar.style.width = '0'; progressBar.style.width = '0';
cb(result, err); cb(result, err);
}, },
progress => { (progress) => {
progressBar.style.width = 100 * progress + '%'; progressBar.style.width = 100 * progress + '%';
} }
); );
@ -159,13 +159,13 @@ const compress = (str, cb) => {
}; };
reader.readAsDataURL(new Blob([new Uint8Array(compressed)])); reader.readAsDataURL(new Blob([new Uint8Array(compressed)]));
}, },
progress => { (progress) => {
progressBar.style.width = 100 * progress + '%'; progressBar.style.width = 100 * progress + '%';
} }
); );
}; };
const slugify = str => const slugify = (str) =>
str str
.toString() .toString()
.toLowerCase() .toLowerCase()

View File

@ -1,7 +1,7 @@
/* App layout */ /* App layout */
#editor, #editor,
#footer, #controls,
#copy, #copy,
#progress { #progress {
position: absolute; position: absolute;
@ -10,11 +10,21 @@
} }
#editor { #editor {
top: 0; top: 44px;
bottom: 46px; bottom: 0;
} }
.readonly #editor { .readonly #editor {
bottom: 0; top: 0;
}
#controls {
box-shadow: rgba(0, 0, 0, 0.15) 0 3px 10px;
}
#controls .title {
color: #fff;
font-family: JetBrainsMono, sans-serif;
font-size: 24px;
line-height: 30px;
} }
.CodeMirror { .CodeMirror {
@ -23,21 +33,22 @@
font-family: JetBrainsMono, sans-serif; font-family: JetBrainsMono, sans-serif;
} }
#footer, #controls,
#copy { #copy {
bottom: 0; top: 0;
height: 38px; height: 36px;
padding: 8px 8px 0; padding: 8px 8px 0;
background-color: #3b3b47; background-color: #3b3b47;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
z-index: 10;
} }
#footer > *, #controls > *,
#copy > * { #copy > * {
margin: 0 6px; margin: 0 6px;
} }
.readonly #footer { .readonly #controls {
display: none; display: none;
} }
@ -59,10 +70,11 @@
/* Form elements */ /* Form elements */
.ss-main { #controls .ss-main {
max-width: 300px; max-width: 230px;
width: calc(100% - 150px); width: calc(100% - 150px);
font-family: sans-serif; font-family: Roboto, sans-serif;
margin-right: 30px;
} }
.ss-main .ss-single-selected, .ss-main .ss-single-selected,
@ -75,12 +87,17 @@ input[type='search'] {
border-radius: 2px !important; border-radius: 2px !important;
border: 1px solid #ccc !important; border: 1px solid #ccc !important;
font-size: 14px !important; font-size: 14px !important;
font-family: Roboto, sans-serif;
} }
input[type='text'], input[type='text'],
input[type='search'] { input[type='search'] {
height: 26px !important; height: 26px !important;
padding: 0 5px; padding: 0 5px;
} }
input::-webkit-search-cancel-button {
display: none;
}
input::-moz-selection { input::-moz-selection {
background-color: rgba(90, 95, 128, 0.99); background-color: rgba(90, 95, 128, 0.99);
} }
@ -113,3 +130,14 @@ button:hover {
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
} }
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-display: swap;
src: local('Roboto'), local('Roboto-Regular'),
url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu4mxK.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC,
U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}