Add footer
Boris Kubiak kubiakboris@gmail.com
Fri, 24 Apr 2020 15:30:20 +0200
4 files changed,
84 insertions(+),
16 deletions(-)
M
README.md
→
README.md
@@ -2,9 +2,9 @@ [![Intro](https://github.com/bokub/nopaste/raw/images/intro.png)][intro-img]
[NoPaste](https://nopaste.ml/) is a client-side paste service which works with **no database**, and **no back-end code** -Instead, the pasted data is **compressed** then **stored** into a unique URL that can be decoded later. For example, [this is the CSS code used by NoPaste][example] +Instead, the data is **compressed** then **stored** into a unique URL that can be decoded later. For example, [this is the CSS code used by NoPaste][example] -As a result, there is no risk of data being lost, censored or deleted. The whole data is **in the link** and nowhere else 🤯 +As a result, there is no risk of data being lost, censored or deleted. The whole data stored is **in the link** and nowhere else! 🤯 **Note:** This project is a fork of [Topaz's paste service][topaz-example], with a reworked design and a few additional features (syntax highlighting, line numbers, embedding...)
M
index.html
→
index.html
@@ -7,7 +7,7 @@ name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> - <title>NoPaste - Client-side paste service</title> + <title>NoPaste - No-database paste service</title> <script src="https://cdn.jsdelivr.net/combine/ npm/lzma@2.3.2/src/lzma.min.js, npm/slim-select@1.25.0/dist/slimselect.min.js,@@ -33,9 +33,13 @@ "
/> <link rel="stylesheet" href="style.css" /> <link href="favicon.ico" rel="icon" type="image/x-icon" /> + <meta + name="description" + content="NoPaste is a client-side paste service which works with no database, and no back-end code. The whole data is stored in shareable links and nowhere else!" + /> </head> <body class="m-0"> - <div id="copy" class="container-fluid hidden"> + <div id="copy" class="container-fluid hidden shadow-bottom hide-readonly"> <div class="row my-1"> <div class="col my-1"> <input@@ -59,7 +63,7 @@ <button class="py-1 px-2 mx-1" onclick="hideCopyBar(false)" type="button">Cancel</button>
</div> </div> </div> - <div id="controls" class="container-fluid"> + <div id="controls" class="container-fluid shadow-bottom hide-readonly"> <div class="row align-items-center justify-content-end my-1"> <div class="col mb-1"> <h1 class="title my-0">{ NoPaste }</h1>@@ -78,6 +82,24 @@ </div>
</div> <div id="progress"></div> <div id="editor"></div> + <footer class="shadow-top container-fluid"> + <div class="row my-1"> + <div class="col mono" id="stats"></div> + <div class="col-auto"> + <a href="javascript:void(0)" class="description-trigger">What is NoPaste?</a> + <div id="description" class="hidden shadow-bottom p-3"> + NoPaste is a client-side paste service which works with <b>no database</b>, and + <b>no back-end code</b>.<br /><br /> + Instead, the data is <b>compressed</b> then <b>stored</b> into a unique URL that can be decoded + later.<br /><br /> + As a result, there is no risk of data being lost, censored or deleted. The whole data is stored + <b>in the link</b> and nowhere else! + </div> + <div class="overlay hidden"></div> + </div> + <div class="col-auto"><a href="https://github.com/bokub/nopaste" target="_blank">Github</a></div> + </div> + </footer> </body> <script src="index.js"></script>
M
index.js
→
index.js
@@ -4,6 +4,7 @@
let editor = null; let select = null; let clipboard = null; +let statsEl = null; const init = () => { initCodeEditor();@@ -24,6 +25,11 @@ });
if (readOnly) { document.body.classList.add('readonly'); } + + statsEl = document.getElementById('stats'); + editor.on('change', () => { + statsEl.innerHTML = `Length: ${editor.getValue().length} | Lines: ${editor['doc'].size}`; + }); }; const initLangSelector = () => {@@ -67,12 +73,17 @@ });
}; const generateLink = (mode) => { - compress(editor.getValue(), (base64, err) => { + const data = editor.getValue(); + compress(data, (base64, err) => { if (err) { alert('Failed to compress data: ' + err); return; } const url = buildUrl(base64, mode); + statsEl.innerHTML = `Data length: ${data.length} | Link length: ${ + url.length + } | Compression ratio: ${Math.round((100 * url.length) / data.length)}%`; + showCopyBar(url); }); };
M
style.css
→
style.css
@@ -4,6 +4,8 @@ body {
display: flex; flex-flow: column; height: 100vh; + color: #fff; + font: normal 14px Roboto, sans-serif; } #editor {@@ -13,10 +15,11 @@ overflow: auto;
} #controls, -#copy { +#copy, +#description, +footer { background-color: #3b3b47; z-index: 10; - box-shadow: rgba(0, 0, 0, 0.15) 0 3px 10px; } #progress {@@ -28,8 +31,7 @@ }
#copy:not(.hidden) + #controls, .hidden, -.readonly #controls, -.readonly #copy { +.readonly .hide-readonly { display: none; }@@ -38,23 +40,57 @@ font-family: JetBrainsMono, sans-serif;
width: 100%; } +/* Styling */ +.shadow-bottom { + box-shadow: rgba(0, 0, 0, 0.15) 0 3px 10px; +} +.shadow-top { + box-shadow: rgba(0, 0, 0, 0.15) 0 -3px 10px; +} +a, +a:hover, +a:active { + color: #fff; +} .CodeMirror { height: 100%; - font-size: 14px; font-family: JetBrainsMono, sans-serif; } - .title { - color: #fff; font: normal 24px JetBrainsMono, sans-serif; white-space: nowrap; } +.mono { + font-family: JetBrainsMono, sans-serif; +} +.description-trigger:hover + #description { + display: block; + position: fixed; + bottom: 20px; + margin: 40px; + right: 0; + max-width: 350px; +} +.description-trigger:hover + #description + .overlay { + /* Used to un-hover on mobile */ + display: block; + position: fixed; + background: transparent; + right: 0; + top: 0; + left: 0; + bottom: 25px; +} + +#description b { + font-weight: normal; + color: #ff79c6; +} /* Form elements */ #controls .ss-main { width: 180px; - font-family: Roboto, sans-serif; } .ss-main .ss-single-selected,@@ -65,8 +101,7 @@ background-color: #3b3b47 !important;
color: #fff !important; border-radius: 2px !important; border: 1px solid #ccc !important; - font-size: 14px !important; - font-family: Roboto, sans-serif; + font: normal 14px Roboto, sans-serif; height: 26px !important; }