Add footer
parent
0de342a5f2
commit
a8be0af2a9
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
[NoPaste](https://nopaste.ml/) is a client-side paste service which works with **no database**, and **no back-end code**
|
[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...)
|
**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...)
|
||||||
|
|
||||||
|
|
|
||||||
28
index.html
28
index.html
|
|
@ -7,7 +7,7 @@
|
||||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
|
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" />
|
<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/
|
<script src="https://cdn.jsdelivr.net/combine/
|
||||||
npm/lzma@2.3.2/src/lzma.min.js,
|
npm/lzma@2.3.2/src/lzma.min.js,
|
||||||
npm/slim-select@1.25.0/dist/slimselect.min.js,
|
npm/slim-select@1.25.0/dist/slimselect.min.js,
|
||||||
|
|
@ -33,9 +33,13 @@ npm/codemirror@5.52.0/theme/dracula.min.css
|
||||||
/>
|
/>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
<link href="favicon.ico" rel="icon" type="image/x-icon" />
|
<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>
|
</head>
|
||||||
<body class="m-0">
|
<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="row my-1">
|
||||||
<div class="col my-1">
|
<div class="col my-1">
|
||||||
<input
|
<input
|
||||||
|
|
@ -59,7 +63,7 @@ npm/codemirror@5.52.0/theme/dracula.min.css
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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="row align-items-center justify-content-end my-1">
|
||||||
<div class="col mb-1">
|
<div class="col mb-1">
|
||||||
<h1 class="title my-0">{ NoPaste }</h1>
|
<h1 class="title my-0">{ NoPaste }</h1>
|
||||||
|
|
@ -78,6 +82,24 @@ npm/codemirror@5.52.0/theme/dracula.min.css
|
||||||
</div>
|
</div>
|
||||||
<div id="progress"></div>
|
<div id="progress"></div>
|
||||||
<div id="editor"></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>
|
</body>
|
||||||
|
|
||||||
<script src="index.js"></script>
|
<script src="index.js"></script>
|
||||||
|
|
|
||||||
13
index.js
13
index.js
|
|
@ -4,6 +4,7 @@ const lzma = new LZMA(window.URL.createObjectURL(blob));
|
||||||
let editor = null;
|
let editor = null;
|
||||||
let select = null;
|
let select = null;
|
||||||
let clipboard = null;
|
let clipboard = null;
|
||||||
|
let statsEl = null;
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
initCodeEditor();
|
initCodeEditor();
|
||||||
|
|
@ -24,6 +25,11 @@ const initCodeEditor = () => {
|
||||||
if (readOnly) {
|
if (readOnly) {
|
||||||
document.body.classList.add('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 = () => {
|
const initLangSelector = () => {
|
||||||
|
|
@ -67,12 +73,17 @@ const initClipboard = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateLink = (mode) => {
|
const generateLink = (mode) => {
|
||||||
compress(editor.getValue(), (base64, err) => {
|
const data = editor.getValue();
|
||||||
|
compress(data, (base64, err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
alert('Failed to compress data: ' + err);
|
alert('Failed to compress data: ' + err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const url = buildUrl(base64, mode);
|
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);
|
showCopyBar(url);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
55
style.css
55
style.css
|
|
@ -4,6 +4,8 @@ body {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
color: #fff;
|
||||||
|
font: normal 14px Roboto, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
#editor {
|
#editor {
|
||||||
|
|
@ -13,10 +15,11 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
#controls,
|
#controls,
|
||||||
#copy {
|
#copy,
|
||||||
|
#description,
|
||||||
|
footer {
|
||||||
background-color: #3b3b47;
|
background-color: #3b3b47;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
box-shadow: rgba(0, 0, 0, 0.15) 0 3px 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#progress {
|
#progress {
|
||||||
|
|
@ -28,8 +31,7 @@ body {
|
||||||
|
|
||||||
#copy:not(.hidden) + #controls,
|
#copy:not(.hidden) + #controls,
|
||||||
.hidden,
|
.hidden,
|
||||||
.readonly #controls,
|
.readonly .hide-readonly {
|
||||||
.readonly #copy {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,23 +40,57 @@ body {
|
||||||
width: 100%;
|
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 {
|
.CodeMirror {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-size: 14px;
|
|
||||||
font-family: JetBrainsMono, sans-serif;
|
font-family: JetBrainsMono, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
color: #fff;
|
|
||||||
font: normal 24px JetBrainsMono, sans-serif;
|
font: normal 24px JetBrainsMono, sans-serif;
|
||||||
white-space: nowrap;
|
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 */
|
/* Form elements */
|
||||||
|
|
||||||
#controls .ss-main {
|
#controls .ss-main {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ss-main .ss-single-selected,
|
.ss-main .ss-single-selected,
|
||||||
|
|
@ -65,8 +101,7 @@ input[type='search'] {
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
border-radius: 2px !important;
|
border-radius: 2px !important;
|
||||||
border: 1px solid #ccc !important;
|
border: 1px solid #ccc !important;
|
||||||
font-size: 14px !important;
|
font: normal 14px Roboto, sans-serif;
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
height: 26px !important;
|
height: 26px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue