mirror of
https://github.com/DarrenOfficial/dpaste.git
synced 2024-12-23 23:23:06 +11:00
Redesign 🚀
This commit is contained in:
parent
54157aeda5
commit
ace0704f45
36 changed files with 2285 additions and 664 deletions
100
client/js/dpaste.js
Normal file
100
client/js/dpaste.js
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*jshint strict:false */
|
||||
|
||||
if (typeof console === "undefined" || typeof console.log === "undefined") {
|
||||
console = {};
|
||||
console.log = function () { };
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Add data-platform to the body tag to show platform related shortcuts
|
||||
// -----------------------------------------------------------------------------
|
||||
const isWindows = navigator.appVersion.indexOf("Win") !== -1;
|
||||
document.body.dataset.platform = isWindows ? 'win' : 'mac';
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Autofocus the content field on the homepage
|
||||
// -----------------------------------------------------------------------------
|
||||
const af = document.querySelector(".autofocus textarea");
|
||||
if (af !== null) {
|
||||
af.focus();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Cmd+Enter or Ctrl+Enter submits the form
|
||||
// -----------------------------------------------------------------------------
|
||||
document.body.onkeydown = function(e) {
|
||||
const metaKey = isWindows ? e.ctrlKey : e.metaKey;
|
||||
const form = document.querySelector(".snippet-form");
|
||||
|
||||
if (form && e.keyCode === 13 && metaKey) {
|
||||
form.submit();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Toggle Wordwrap
|
||||
// -----------------------------------------------------------------------------
|
||||
const wordwrapCheckbox = document.getElementById('wordwrap');
|
||||
const snippetDiv = document.querySelector('.snippet-code');
|
||||
|
||||
function toggleWordwrap() {
|
||||
if (wordwrapCheckbox.checked) {
|
||||
snippetDiv.classList.add('wordwrap');
|
||||
} else {
|
||||
snippetDiv.classList.remove('wordwrap');
|
||||
}
|
||||
}
|
||||
|
||||
if (wordwrapCheckbox && snippetDiv) {
|
||||
toggleWordwrap();
|
||||
wordwrapCheckbox.onchange = toggleWordwrap;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Line Highlighting
|
||||
// -----------------------------------------------------------------------------
|
||||
const curLine = document.location.hash;
|
||||
if (curLine.startsWith('#L')) {
|
||||
const hashlist = curLine.substring(2).split(',');
|
||||
if (hashlist.length > 0 && hashlist[0] !== '') {
|
||||
hashlist.forEach(function(el) {
|
||||
const line = document.getElementById(`l${el}`);
|
||||
if (line) {
|
||||
line.classList.add('marked');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let lines = document.querySelectorAll('.snippet-code li');
|
||||
lines.forEach(function(el) {
|
||||
el.onclick = function() {
|
||||
el.classList.toggle('marked');
|
||||
let hash = 'L';
|
||||
let marked = document.querySelectorAll('.snippet-code li.marked');
|
||||
marked.forEach(function(line) {
|
||||
if (hash !== 'L') {
|
||||
hash += ',';
|
||||
}
|
||||
hash += line.getAttribute('id').substring(1);
|
||||
});
|
||||
window.location.hash = hash;
|
||||
};
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Copy URL to Clipboard
|
||||
// -----------------------------------------------------------------------------
|
||||
const clipboardLink = document.getElementById('copyToClipboard');
|
||||
const copyToClipboardField = document.getElementById('copyToClipboardField');
|
||||
|
||||
if (clipboardLink && copyToClipboardField) {
|
||||
clipboardLink.onclick = function(e) {
|
||||
e.preventDefault();
|
||||
copyToClipboardField.select();
|
||||
document.execCommand("Copy");
|
||||
console.log('Copied URL to clipboard:', copyToClipboardField.value);
|
||||
};
|
||||
}
|
47
client/scss/_globals.scss
Normal file
47
client/scss/_globals.scss
Normal file
|
@ -0,0 +1,47 @@
|
|||
body {
|
||||
min-width: 800px; // FIXME: MOBILE
|
||||
|
||||
background-color: $bgColor;
|
||||
font-family: $baseFont;
|
||||
font-weight: $baseFontRegular;
|
||||
}
|
||||
|
||||
body[data-code-snippet] { background-color: $codeBgColor; }
|
||||
|
||||
body[data-platform=win] .platform-mac { display: none; }
|
||||
body[data-platform=mac] .platform-win { display: none; }
|
||||
|
||||
|
||||
.btn {
|
||||
padding: 6px 0;
|
||||
position: relative;
|
||||
|
||||
display: inline-block;
|
||||
|
||||
color: $btnTextColor;
|
||||
background-color: $btnBgColor;
|
||||
|
||||
border: 1px solid $btnBorderColor;
|
||||
border-radius: 3px;
|
||||
|
||||
font-size: 13px;
|
||||
font-weight: $baseFontDemiBold;
|
||||
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
.sep {
|
||||
@include separator();
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
background-color: darken($btnBgColor, 5%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
top: 1px;
|
||||
}
|
||||
}
|
7
client/scss/_mixins.scss
Normal file
7
client/scss/_mixins.scss
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
// Vertical dotted separtor
|
||||
@mixin separator($color: white, $margin: 4px) {
|
||||
width: 0;
|
||||
border-right: 2px dotted $color;
|
||||
margin: 0 ($margin+2px) 0 $margin;
|
||||
}
|
40
client/scss/_reset.scss
Normal file
40
client/scss/_reset.scss
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* http://meyerweb.com/eric/tools/css/reset/
|
||||
v2.0 | 20110126
|
||||
License: none (public domain)
|
||||
*/
|
||||
|
||||
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline; }
|
||||
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
|
||||
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
|
||||
display: block; }
|
||||
|
||||
body {
|
||||
line-height: 1; }
|
||||
|
||||
ol, ul {
|
||||
list-style: none; }
|
||||
|
||||
blockquote, q {
|
||||
quotes: none; }
|
||||
|
||||
blockquote {
|
||||
&:before, &:after {
|
||||
content: '';
|
||||
content: none; } }
|
||||
|
||||
q {
|
||||
&:before, &:after {
|
||||
content: '';
|
||||
content: none; } }
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0; }
|
42
client/scss/components/_article.scss
Normal file
42
client/scss/components/_article.scss
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
|
||||
Generic Content pages such as about or 404 error pages.
|
||||
|
||||
*/
|
||||
|
||||
article {
|
||||
padding: 40px $boxPadding;
|
||||
|
||||
font-size: 16px;
|
||||
font-weight: $baseFontRegular;
|
||||
line-height: 24px;
|
||||
|
||||
max-width: 520px;
|
||||
|
||||
color: $textColor;
|
||||
|
||||
h2 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
margin: 0 0 30px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
strong, b {
|
||||
font-weight: $baseFontDemiBold;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
color: $linkColor;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: lighten($linkColor, 30%);
|
||||
}
|
||||
|
||||
a:hover, a:active {
|
||||
color: $hoverColor;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,49 @@
|
|||
// -----------------------------------------------------------------------------
|
||||
// Pygments Theme
|
||||
|
||||
.snippet-code {
|
||||
font-family: $codeFont;
|
||||
font-size: 13px;
|
||||
font-weight: 300;
|
||||
line-height: 20px;
|
||||
//overflow: auto;
|
||||
color: $codeTextColor;
|
||||
background-color: $codeBgColor;
|
||||
|
||||
padding: 20px $boxPadding;
|
||||
|
||||
&.wordwrap {
|
||||
overflow: auto;
|
||||
li { white-space: pre-wrap !important; }
|
||||
}
|
||||
|
||||
ol {
|
||||
position: relative;
|
||||
list-style: none;
|
||||
counter-reset: lineNumberCounter;
|
||||
|
||||
li {
|
||||
white-space: pre;
|
||||
padding-left: 50px;
|
||||
|
||||
&:before {
|
||||
color: $codeLineNumberColor;
|
||||
counter-increment: lineNumberCounter;
|
||||
content: counter(lineNumberCounter);
|
||||
text-align: right;
|
||||
|
||||
width: 30px;
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
left: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
li.marked {
|
||||
background-color: $markerBgColor;
|
||||
&:before{ color: $markerLineNumberColor; }
|
||||
}
|
||||
}
|
||||
|
||||
// Pygments
|
||||
.gd { background-color: rgba(226, 12, 19, .3); color: #fff; display: block; }
|
||||
.gi { background-color: rgba(23, 189, 10, .2); color: #fff; display: block; }
|
||||
|
||||
|
@ -67,3 +108,20 @@
|
|||
.il { color: #ae81ff } /* Literal.Number.Integer.Long */
|
||||
|
||||
}
|
||||
|
||||
|
||||
.snippet-text {
|
||||
background: $bgColor;
|
||||
padding: 20px $boxPadding;
|
||||
|
||||
color: $textColor;
|
||||
|
||||
font-family: $textFont;
|
||||
font-weight: $baseFontRegular;
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
|
||||
& > div {
|
||||
max-width: 540px;
|
||||
}
|
||||
}
|
86
client/scss/components/_form.scss
Normal file
86
client/scss/components/_form.scss
Normal file
|
@ -0,0 +1,86 @@
|
|||
@mixin codeTextArea {
|
||||
color: #7D7D7D;
|
||||
font-family: $codeFont;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
|
||||
.snippet-form {
|
||||
background-color: $bgColor;
|
||||
|
||||
select {
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
|
||||
padding: 5px 7px;
|
||||
margin-right: 15px;
|
||||
min-width: 160px;
|
||||
|
||||
color: $selectTextColor;
|
||||
background-color: $selectBgColor;
|
||||
|
||||
border: 1px solid $selectBorderColor;
|
||||
border-radius: 3px;
|
||||
|
||||
font-family: $baseFont;
|
||||
font-weight: $baseFontRegular;
|
||||
font-size: 14px;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
// Triangle
|
||||
background-image:
|
||||
linear-gradient(45deg, transparent 50%, $selectTriangleColor 50%),
|
||||
linear-gradient(135deg, $selectTriangleColor 50%, transparent 50%);
|
||||
background-position:
|
||||
calc(100% - 18px) calc(13px),
|
||||
calc(100% - 13px) calc(13px),
|
||||
calc(100% - 2.5em) 0.5em;
|
||||
background-size: 5px 5px, 5px 5px, 3px 1.5em;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
&:hover {
|
||||
border-color: darken($selectBorderColor, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
padding: 0 $boxPadding;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid $borderColor;
|
||||
|
||||
label { display: none; }
|
||||
|
||||
.action {
|
||||
margin-left: auto;
|
||||
|
||||
.btn {
|
||||
width: auto;
|
||||
padding: 6px 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 20px $boxPadding;
|
||||
|
||||
label { display: none; }
|
||||
|
||||
textarea {
|
||||
padding: 20px;
|
||||
@include codeTextArea;
|
||||
min-height: 390px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
border: 1px solid $borderColor;
|
||||
|
||||
&:active, &:focus {
|
||||
border-color: darken($selectBorderColor, 10%)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
115
client/scss/components/_header.scss
Normal file
115
client/scss/components/_header.scss
Normal file
|
@ -0,0 +1,115 @@
|
|||
header {
|
||||
padding: 0 $boxPadding;
|
||||
height: 60px;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
color: $headerTextColor;
|
||||
background: linear-gradient(to right, $headerBgColor1, $headerBgColor2);
|
||||
|
||||
// Subheadline e.g. Reply Bar
|
||||
&.sub {
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
|
||||
color: $headerTextColor;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-weight: $baseFontBold;
|
||||
|
||||
&:hover { text-decoration: underline; }
|
||||
|
||||
// dpaste home link is a bit larger
|
||||
&.home {
|
||||
font-size: 28px;
|
||||
font-weight: $baseFontHeavy;
|
||||
|
||||
}
|
||||
|
||||
// Nav links have a fixed width to align with grid
|
||||
&.nav-link {
|
||||
width: $columnWidth + $columnGap;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 2 * $columnWidth;
|
||||
margin-left: $columnGap / 2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
position: relative;
|
||||
font-size: 24px;
|
||||
font-weight: $baseFontBold;
|
||||
|
||||
strong {
|
||||
font-size: 28px;
|
||||
font-weight: $baseFontHeavy;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
font-weight: $baseFontBold;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ul#snippetOptions {
|
||||
padding: 0 $boxPadding;
|
||||
height: 40px;
|
||||
|
||||
background-color: $metaBgColor;
|
||||
color: $metaTextColor;
|
||||
|
||||
font-size: 13px;
|
||||
font-weight: $baseFontRegular;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
a:link, a:visited {
|
||||
color: $metaTextColor;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover, a:active {
|
||||
color: $hoverColor;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 0 7px;
|
||||
|
||||
&:first-child{ padding-left: 0; }
|
||||
&:last-child{ padding-right: 0; }
|
||||
}
|
||||
|
||||
li.sep {
|
||||
@include separator($metaTextColor);
|
||||
height: 17px;
|
||||
margin: 0 2px 0 1px;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#copyToClipboardField {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
}
|
||||
|
||||
#copyToClipboard svg {
|
||||
height: 30px;
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -40px;
|
||||
|
||||
&:active {
|
||||
top: -7px;
|
||||
}
|
||||
}
|
33
client/scss/components/_history.scss
Normal file
33
client/scss/components/_history.scss
Normal file
|
@ -0,0 +1,33 @@
|
|||
|
||||
|
||||
|
||||
.history-header {
|
||||
padding: 15px $boxPadding;
|
||||
color: $textColor;
|
||||
font-size: 14px;
|
||||
background-color: $borderColor;
|
||||
|
||||
a:link, a:visited {
|
||||
font-weight: $baseFontDemiBold;
|
||||
color: $textColor;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover, a:active {
|
||||
color: $hoverColor;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.sep {
|
||||
@include separator($metaTextColor, 10px);
|
||||
height: 17px;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.history-empty {
|
||||
padding: 40px $boxPadding;
|
||||
color: $codeTextColor;
|
||||
}
|
||||
|
||||
|
93
client/scss/dpaste.scss
Executable file
93
client/scss/dpaste.scss
Executable file
|
@ -0,0 +1,93 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
Palette
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
// General
|
||||
$bgColor: white; // Regular background color for non-code snippets.
|
||||
|
||||
$textColor: #7D7D7D; // General text color
|
||||
$linkColor: #4A90E2; // Link color in text and content pages
|
||||
$hoverColor: #72B4E4;
|
||||
|
||||
$borderColor: #EDEDED; // Used for separators, select borders, etc.
|
||||
|
||||
// Header
|
||||
$headerTextColor: white; // Header text color
|
||||
$headerBgColor1: #4A90E2; // Header gradient background left
|
||||
$headerBgColor2: #72B4E4; // Header gradient background right
|
||||
|
||||
$btnBgColor: #4A90E2; // Buttons (Header, Meta)
|
||||
$btnBorderColor: #33639C;
|
||||
$btnTextColor: white;
|
||||
|
||||
// Meta Options
|
||||
$metaBgColor: #F9F9F9; // Meta options of snippet
|
||||
$metaTextColor: #BABABA; // Meta text and link color
|
||||
|
||||
$selectBorderColor: #DDDDDD; // Select dropdowns
|
||||
$selectBgColor: white;
|
||||
$selectTextColor: #858585;
|
||||
$selectTriangleColor: $linkColor;
|
||||
|
||||
$confirmTextColor: #6D6D6D; // Yellow confirmation popup
|
||||
$confirmBgColor: #FFF9A8;
|
||||
|
||||
// Snippet
|
||||
$messageTextColor: white; // One time message color
|
||||
$messageBgColor: #F5A623;
|
||||
|
||||
$codeTextColor: #dadad4; // Regular code color (not specified by pygments)
|
||||
$codeBgColor: #222829; // bg color of code views
|
||||
$codeDiffBgColor: #2A3335; // bg color of diff views
|
||||
$codeLineNumberColor: #636363; // Color of code line numbers
|
||||
|
||||
$markerLineNumberColor: gold; // Marked lines number color
|
||||
$markerBgColor: rgba(255, 255, 255, .05);
|
||||
|
||||
// Mobile Burger Menu
|
||||
$burgerBgColor: #3D3D3D; // Burger Menu background
|
||||
$burgerTextColor: #C0C0C0; // (muted) Text color of burger buttons
|
||||
|
||||
$burgerBtnTextColor: #C0C0C0; // Buttons and select items in Burger Menu
|
||||
$burgerBtnBorderColor: #575757;
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Fonts
|
||||
----------------------------------------------------------------------------- */
|
||||
$baseFont: "Avenir Next";
|
||||
$codeFont: "SF Mono", "Fira Mono", Monaco, Menlo, Consolas, monospace;
|
||||
$textFont: "Apple SD Gothic Neo";
|
||||
|
||||
$baseFontLight: 300;
|
||||
$baseFontRegular: 400;
|
||||
$baseFontDemiBold: 500;
|
||||
$baseFontBold: 600;
|
||||
$baseFontHeavy: 700;
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Grid
|
||||
----------------------------------------------------------------------------- */
|
||||
$columnWidth: 60px;
|
||||
$columnGap: 20px;
|
||||
|
||||
$boxPadding: 30px; // Left/Right padding of all views
|
||||
$mobileBoxPadding: 20px;
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Imports
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
// Globals.
|
||||
@import 'reset';
|
||||
@import 'mixins';
|
||||
@import 'globals';
|
||||
|
||||
// Components.
|
||||
@import 'components/header';
|
||||
@import 'components/form';
|
||||
@import 'components/code';
|
||||
@import 'components/article';
|
||||
@import 'components/history';
|
|
@ -1,13 +0,0 @@
|
|||
// -----------------------------------------------------------------------------
|
||||
// About Page
|
||||
|
||||
.page {
|
||||
padding: $desktopBoxPadding;
|
||||
background-color: white;
|
||||
|
||||
color: #444;
|
||||
|
||||
table th {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
// -----------------------------------------------------------------------------
|
||||
// Snippet Details
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Options
|
||||
.snippet-options {
|
||||
padding: $desktopBoxPadding;
|
||||
font-size: .9rem;
|
||||
|
||||
a:link,
|
||||
a:visited {
|
||||
margin: 0 .2em;
|
||||
}
|
||||
a:hover,
|
||||
a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Reply Form
|
||||
|
||||
.snippet-reply {
|
||||
h2 {
|
||||
background-color: white;
|
||||
padding: $desktopBoxPadding;
|
||||
padding-bottom: 0;
|
||||
margin: 0;
|
||||
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.snippet-reply[data-hidden=yes] {
|
||||
opacity: 0.3;
|
||||
cursor: pointer;
|
||||
|
||||
* {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Text lexer
|
||||
|
||||
.snippet-text {
|
||||
color: #666;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
max-width: 620px;
|
||||
font-family: Helvetica, FreeSerif, serif;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Code Lexer
|
||||
|
||||
$codeColor: #f8f8f2;
|
||||
$codeLineColor: #aaa;
|
||||
$codeBackgroundColor: #232829;
|
||||
$markerColor: rgb(244,244,9);
|
||||
$markerBackgroundColor: rgba(244,244,9,.2);
|
||||
|
||||
.snippet-code {
|
||||
|
||||
background: $codeBackgroundColor;
|
||||
color: $codeColor;
|
||||
font-family: $codeFont;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 300;
|
||||
line-height: 1.1rem;
|
||||
padding: 1rem 0;
|
||||
|
||||
&.wordwrap {
|
||||
overflow: auto;
|
||||
|
||||
li { white-space: pre-wrap !important; }
|
||||
}
|
||||
|
||||
ol {
|
||||
margin: 0 0 0 2rem;
|
||||
|
||||
li {
|
||||
color: $codeLineColor;
|
||||
cursor: pointer;
|
||||
white-space: pre;
|
||||
|
||||
&.marked {
|
||||
color: $markerColor;
|
||||
background-color: $markerBackgroundColor;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
// -----------------------------------------------------------------------------
|
||||
// Snippet Form
|
||||
|
||||
.snippet-form {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// The main form textarea
|
||||
|
||||
.form-content {
|
||||
background-color: white;
|
||||
padding: 1rem 1rem;
|
||||
|
||||
textarea {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 25rem;
|
||||
font-family: $codeFont;
|
||||
font-size: .8rem;
|
||||
border: 1px solid #bbb;
|
||||
padding: 1rem;
|
||||
transition: border .5s linear;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: #3fca6e;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Additional options; lexer and expiration
|
||||
|
||||
.form-options {
|
||||
padding: $desktopBoxPadding;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: .9rem;
|
||||
|
||||
.form-options-lexer {
|
||||
}
|
||||
.form-options-expire {
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Submit line
|
||||
|
||||
.form-actions {
|
||||
padding: $desktopBoxPadding;
|
||||
background-color: white;
|
||||
|
||||
.shortcut {
|
||||
font-size: .9rem;
|
||||
color: #888;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
input[type=submit] {
|
||||
color: white;
|
||||
background-color: rgb(109, 163, 217);
|
||||
border: none;
|
||||
padding: .6em 1em;
|
||||
font-weight: 500;
|
||||
font-family: "SF Mono", "Fira Mono", monospace;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: rgb(96, 139, 192);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
// -----------------------------------------------------------------------------
|
||||
// Header
|
||||
|
||||
header {
|
||||
background: $headerColor2;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
padding: $desktopBoxPadding;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
color: white;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
header h1 input {
|
||||
font-size: 1em;
|
||||
font-family: $codeFont;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
color: white;
|
||||
min-width: 25em;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
header nav {
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
header nav a:link,
|
||||
header nav a:visited {
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
margin: 0 .2em;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
header nav a:last-child {
|
||||
border: 1px solid white;
|
||||
border-radius: 5px;
|
||||
padding: .3em .5em;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
background-color: lighten($headerColor1, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// -----------------------------------------------------------------------------
|
||||
// Snippet History List
|
||||
|
||||
.snippet-list {
|
||||
padding: $desktopBoxPadding;
|
||||
|
||||
dt:not(:first-child) {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
dt:last-child {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
dd {
|
||||
font-family: $codeFont;
|
||||
font-size: .9rem;
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -1,67 +0,0 @@
|
|||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// dpaste example stylesheet
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Color Palette
|
||||
$backgroundColor: #F7F8F9;
|
||||
$headerColor1: #394c78;
|
||||
$headerColor2: #426ca1;
|
||||
$headerTextColor: #fff;
|
||||
$textColor: #888;
|
||||
|
||||
$linkColor: rgb(109, 163, 217);
|
||||
$hoverColor: rgb(109, 163, 217);
|
||||
|
||||
// The general font for the website
|
||||
$siteFont: "SF Mono", "Fira Mono", monospace;
|
||||
|
||||
// Font used for "Text" lexer
|
||||
$textFont: Helvetica;
|
||||
|
||||
// Font used for the code snippet display
|
||||
$codeFont: "SF Mono", "Fira Mono", Monaco, Menlo, Consolas, "Courier New", monospace;
|
||||
|
||||
$desktopBoxPadding: 1rem 2rem;
|
||||
$mobileBoxPadding: 1rem;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
body {
|
||||
color: $textColor;
|
||||
background: $backgroundColor;
|
||||
font-family: $siteFont;
|
||||
font-size: 1em;
|
||||
font-weight: 300;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a:link,
|
||||
a:visited {
|
||||
color: $linkColor;
|
||||
font-family: $siteFont;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:visited {
|
||||
color: $hoverColor;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
select, input {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Imports
|
||||
|
||||
@import 'header';
|
||||
@import 'form';
|
||||
@import 'details';
|
||||
@import 'history';
|
||||
@import 'about';
|
||||
@import 'pygments';
|
|
@ -1,8 +1,14 @@
|
|||
{% extends "dpaste/base.html" %}
|
||||
|
||||
{% block title %}404 Not found{% endblock %}
|
||||
{% block headline %}404 Not found{% endblock %}
|
||||
{% block title %}404 Snippet not found{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
<p>Snippet you have searched is not available (anymore).</p>
|
||||
<article>
|
||||
<h2>404 Snippet not found</h2>
|
||||
|
||||
<p>
|
||||
This snippet no longer exists. Snippets are automatically
|
||||
deleted when they reach their expiration date.
|
||||
</p>
|
||||
</article>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
{% extends "dpaste/base.html" %}
|
||||
|
||||
{% block title %}500 Internal Server Error{% endblock %}
|
||||
{% block headline %}500 Internal Server Error{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
<p>Sorry, there was an error with your request. The server notified the admin via email.</p>
|
||||
<article>
|
||||
<h2>500 Internal Server Error</h2>
|
||||
<p>There was an issue with your request.</p>
|
||||
</article>
|
||||
{% endblock %}
|
||||
|
|
|
@ -3,91 +3,28 @@
|
|||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "About" %}{% endblock %}
|
||||
{% block headline %}{% trans "About" %}{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
<article>
|
||||
|
||||
<div class="page">
|
||||
<h2>{% trans "About dpaste" %}</h2>
|
||||
|
||||
<p>
|
||||
This site is powered by dpaste, which is open source. You can
|
||||
find the source, contribute to it and leave ideas on Github:
|
||||
<a href="https://github.com/bartTC/dpaste">github.com/bartTC/dpaste</a>
|
||||
</p>
|
||||
<p>
|
||||
{% blocktrans %}
|
||||
This site is powered by dpaste, an <strong>open source</strong>
|
||||
<a href="https://en.wikipedia.org/wiki/Pastebin">pastebin</a> application.
|
||||
You can find the source code, contribute to it or leave feedback
|
||||
<a href="https://github.com/bartTC/dpaste">on Github</a>.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
<form action="/i18n/setlang/" method="post">
|
||||
Change the language:
|
||||
{% csrf_token %}
|
||||
<input name="next" type="hidden" value="{{ redirect_to }}" />
|
||||
<select name="language">
|
||||
{% get_language_info_list for LANGUAGES as languages %}
|
||||
{% for language in languages %}
|
||||
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
|
||||
{{ language.name_local }} ({{ language.code }})
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
<p>
|
||||
{% blocktrans %}
|
||||
dpaste provides an <strong>API</strong> to easily paste snippets out of your shell or editor.
|
||||
See the <a href="https://github.com/bartTC/dpaste/wiki">dpaste wiki</a>
|
||||
for the API documentation and a list of available plugins.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
<h3>API</h3>
|
||||
|
||||
<p>dpaste provides a simple API documented in detail <a href="http://dpaste.readthedocs.org/en/latest/api.html">
|
||||
on this page</a>. For a quick start here is a code example (Python 2.x):</p>
|
||||
|
||||
{# Just put the script in dpaste and copy the source node #}
|
||||
<div class="code python"><ol><li id="1"><span class="c">#!/usr/bin/env python</span></li><li id="2"> </li><li id="3"><span class="kn">from</span> <span class="nn">urllib</span> <span class="kn">import</span> <span class="n">urlencode</span></li><li id="4"><span class="kn">from</span> <span class="nn">urllib2</span> <span class="kn">import</span> <span class="n">Request</span><span class="p">,</span> <span class="n">urlopen</span></li><li id="5"><span class="kn">from</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="n">stdin</span></li><li id="6"> </li><li id="7"><span class="k">def</span> <span class="nf">paste_code</span><span class="p">():</span></li><li id="8"> <span class="n">request</span> <span class="o">=</span> <span class="n">Request</span><span class="p">(</span><span class="s">'{{ site_url }}/api/'</span><span class="p">,</span> <span class="n">urlencode</span><span class="p">({</span></li><li id="9"> <span class="s">'content'</span><span class="p">:</span> <span class="n">stdin</span><span class="o">.</span><span class="n">read</span><span class="p">(),</span></li><li id="10"> <span class="s">'lexer'</span><span class="p">:</span> <span class="s">'python'</span><span class="p">,</span></li><li id="11"> <span class="s">'format'</span><span class="p">:</span> <span class="s">'url'</span><span class="p">,</span></li><li id="12"> <span class="p">}))</span></li><li id="13"> <span class="k">print</span> <span class="n">urlopen</span><span class="p">(</span><span class="n">request</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span></li><li id="14"> </li><li id="15"><span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span></li><li id="16"> <span class="n">paste_code</span><span class="p">()</span></li></ol></div>
|
||||
<br/>
|
||||
|
||||
<p>Save this script in <code>/usr/local/bin/dpaste</code> and give it the executable bit: <code>chmod +x /usr/local/bin/dpaste</code>.</p>
|
||||
<p>Usage: <code>cat foo.txt | dpaste</code></p>
|
||||
|
||||
<p>An alternative would be to just use <code>curl</code>:
|
||||
<code>alias dpaste="curl -F 'content=<-' {{ site_url }}/api/"</code></p>
|
||||
|
||||
|
||||
<h3>Applications using the API:</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/bartTC/dpasteGUI/wiki">dpasteGUI</a>, a OS X interface</li>
|
||||
<li><a href="https://github.com/bartTC/SubDpaste">a dpaste Sublime 2 plugin</a></li>
|
||||
<li><a href="http://marmalade-repo.org/packages/dpaste_de">Marmalade</a>, a Emacs plugin</li>
|
||||
<li><a href="https://atom.io/packages/atom-dpaste">atom-dpaste</a>, a Atom editor plugin</li>
|
||||
</ul>
|
||||
|
||||
<h3>{% trans "Statistics" %}</h3>
|
||||
|
||||
<p>{% blocktrans %}There are {{ total }} snippets in the database. The most popular languages are:{% endblocktrans %}</p>
|
||||
<table class="table" style="width: 40%">
|
||||
{% for s in stats %}
|
||||
<tr>
|
||||
<th>{{ s.lexer|upper }}</th>
|
||||
<td>{{ s.count }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<h3>Delete a snippet</h3>
|
||||
|
||||
<p>
|
||||
If you created a snippet with the API you can't delete it on the webpage
|
||||
since it's not in your history. You can delete a snippet here. Actually
|
||||
you can delete any snippet of anybody, as long as you know the short code.
|
||||
</p>
|
||||
<p>
|
||||
If you deleted a snippet because of legal issues, please let me know
|
||||
that, I want to keep track of such things and try to avoid in future.
|
||||
</p>
|
||||
<p>
|
||||
Type the 4 letter code of your snippet in the field and submit.
|
||||
Like this yellow one here: <tt>{{ site_url }}/<strong>SiZrT</strong></tt>
|
||||
</p>
|
||||
|
||||
<form method="POST" action="{% url "snippet_delete" %}">
|
||||
{% csrf_token %}
|
||||
<input name="snippet_id"> <input type="Submit" value="Submit"/>
|
||||
</form>
|
||||
|
||||
{{ DPASTE_ABOUT_EXTRA }}
|
||||
</div>
|
||||
</article>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,48 +1,29 @@
|
|||
{% load i18n %}
|
||||
{% load staticfiles %}
|
||||
{% load dpaste_tags %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="{% static "dpaste/dpaste.css" %}"/>
|
||||
{% block extrahead %}{% endblock %}
|
||||
<style type="text/css">{% inlinestatic "dpaste.css" %}</style>
|
||||
</head>
|
||||
<body>
|
||||
<body {% block body_type %}{%endblock %}>
|
||||
|
||||
|
||||
<header class="box">
|
||||
<h1>{% block headline %}{% endblock %}</h1>
|
||||
<header>
|
||||
<h1>{% block headline %}<a class="home" href="{% url "snippet_new" %}">dpaste</a>{% endblock %}</h1>
|
||||
<nav>
|
||||
<a href="{% url "dpaste_about" %}">{% trans "About" %}</a>
|
||||
<a href="{% url "snippet_history" %}">{% trans "History" %}</a>
|
||||
<a href="{% url "snippet_new" %}">{% trans "New snippet" %} →</a></li>
|
||||
<a class="nav-link" href="{% url "dpaste_about" %}">{% trans "About" %}</a>
|
||||
<a class="nav-link" href="{% url "snippet_history" %}">{% trans "History" %}</a>
|
||||
{%block nav_new %}<a class="btn" href="{% url "snippet_new" %}">{% trans "New snippet" %}</a>{% endblock %}
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
{% block page %}
|
||||
PAGE MISSING
|
||||
{% endblock %}
|
||||
{% block options %}{% endblock %}
|
||||
|
||||
{% block script_footer %}
|
||||
<script>
|
||||
let af = document.querySelector(".autofocus textarea");
|
||||
if (af !== null)
|
||||
af.focus();
|
||||
|
||||
let se = document.querySelector(".superenter textarea");
|
||||
if (se !== null) {
|
||||
se.onkeydown = function (e) {
|
||||
let metaKey = navigator.appVersion.indexOf("Win") !== -1 ? e.ctrlKey : e.metaKey;
|
||||
if (e.keyCode === 13 && metaKey) {
|
||||
document.querySelector(".snippet-form").submit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
<main>{% block page %}{% endblock %}</main>
|
||||
|
||||
<script>{% inlinestatic "dpaste.js" %}</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
83
dpaste/templates/dpaste/details.html
Normal file
83
dpaste/templates/dpaste/details.html
Normal file
|
@ -0,0 +1,83 @@
|
|||
{% extends "dpaste/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}dpaste/{{ snippet.secret_id }} ({{ snippet.lexer }}){% endblock %}
|
||||
|
||||
{% block body_type %}
|
||||
{% if snippet.lexer == 'text' %}data-text-snippet{% else %}data-code-snippet{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block headline %}
|
||||
<a href="{{ request.build_absolute_uri }}">{{ request.build_absolute_uri }}</a>
|
||||
|
||||
<a href="#" id="copyToClipboard" title="{% trans "Copy URL to clipboard" %}">
|
||||
<svg fill="#FFF" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M40.965 6c5.137 0 9.273 3.988 9.8 9h1.188c3.14 0 5.809 2.125 6.68 5h2.309c4.39 0 7.988 3.766 7.988 8.188V55h15.98-.004a1.99 1.99 0 0 1 1.574.652c.356.39.543.91.516 1.441A1.995 1.995 0 0 1 84.906 59h-15.98v26.812c0 4.422-3.598 8.188-7.988 8.188h-39.95C16.598 94 13 90.234 13 85.812V28.186C13 23.765 16.598 20 20.99 20h2.308c.871-2.875 3.54-5 6.68-5h1.187c.528-5.012 4.66-9 9.801-9zm0 4a5.968 5.968 0 0 0-5.992 6v1a2 2 0 0 1-2 2h-2.996c-1.696 0-2.996 1.305-2.996 3s1.3 3 2.996 3H51.95c1.695 0 2.996-1.305 2.996-3s-1.301-3-2.996-3h-2.996a1.998 1.998 0 0 1-1.996-2v-1c0-3.336-2.66-6-5.993-6zm19.973 14h-2.309c-.87 2.875-3.539 5-6.68 5H29.978c-3.14 0-5.809-2.125-6.68-5h-2.309c-1.968 0-3.996 2.05-3.996 4.188v57.624c0 2.137 2.024 4.188 3.996 4.188h39.95c1.968 0 3.996-2.05 3.996-4.188v-26.81H46.176l6.117 5.5c.828.742.894 2.015.156 2.843a2.01 2.01 0 0 1-2.84.157l-9.988-9a2 2 0 0 1 0-3l9.988-9a2.005 2.005 0 0 1 1.465-.532 2.002 2.002 0 0 1 1.219 3.532L46.175 55h18.758V28.189c0-2.137-2.027-4.188-3.996-4.188z"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<input type="text" id="copyToClipboardField" value="{{ request.build_absolute_uri }}"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block options %}
|
||||
<ul id="snippetOptions">
|
||||
<li>
|
||||
{% if snippet.expire_type == 1 %}
|
||||
{% blocktrans with date=snippet.expires|timeuntil %}Expires in: {{ date }}{% endblocktrans %}
|
||||
{% elif snippet.expire_type == 2 %}
|
||||
{% trans "Snippet never expires" %}
|
||||
{% elif snippet.expire_type == 3 %}
|
||||
{% trans "One-Time snippet" %}
|
||||
{% endif %}
|
||||
</li>
|
||||
<li class="sep"></li>
|
||||
<li>
|
||||
<a href="{% url "snippet_delete" snippet.secret_id %}"
|
||||
onclick="return confirm('{% trans "Are you sure you want to delete this snippet?" %}');">{% trans "Delete Now" %}</a>
|
||||
</li>
|
||||
<!--
|
||||
{% if snippet.parent %}
|
||||
<li><a href="#snippet-diff">{% trans "Compare with previous Snippet" %}</a></li>
|
||||
{% endif %}
|
||||
-->
|
||||
|
||||
{% if snippet.expire_type != 3 %}
|
||||
<li><a href="{% url "snippet_details_raw" snippet.secret_id %}">{% trans "View Raw" %}</a></li>
|
||||
{% endif %}
|
||||
{% if snippet.lexer != 'text' %}
|
||||
<li>
|
||||
<label for="wordwrap">
|
||||
<input type="checkbox" id="wordwrap"{% if wordwrap %} checked{% endif %}> Wordwrap
|
||||
</label>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
{% if snippet.expire_type == 3 %}
|
||||
<p class="snippet-message">
|
||||
{% trans "This is a one-time snippet." %}
|
||||
{% if snippet.remaining_views > 1 %}
|
||||
{% blocktrans with remaining=snippet.remaining_views %}It is automatically removed after {{ remaining }} further views.{% endblocktrans %}
|
||||
{% elif snippet.remaining_views == 1 %}
|
||||
{% trans "It is automatically removed after the next view." %}
|
||||
{% else %}
|
||||
{% trans "It cannot be viewed again." %}
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if snippet.lexer == 'text' %}
|
||||
<div class="snippet-text">{% include "dpaste/highlight/text.html" %}</div>
|
||||
{% else %}
|
||||
<div class="snippet-code">{% include "dpaste/highlight/code.html" %}</div>
|
||||
{% endif %}
|
||||
|
||||
<header class="sub">
|
||||
<h2>{% trans "Edit this Snippet" %}</h2>
|
||||
</header>
|
||||
|
||||
{% include "dpaste/includes/form.html" %}
|
||||
{% endblock %}
|
|
@ -1 +1 @@
|
|||
<ol>{% for line in highlighted %}<li id="l{{ forloop.counter }}">{{ line|safe|default:" " }}</li>{% endfor %}</ol>
|
||||
<ol>{% for line in snippet.highlight_lines %}<li id="l{{ forloop.counter }}">{{ line|safe|default:" " }}</li>{% endfor %}</ol>
|
||||
|
|
|
@ -1 +1 @@
|
|||
{{ snippet.content|linebreaksbr }}
|
||||
<div>{{ snippet.content|linebreaksbr }}</div>
|
||||
|
|
49
dpaste/templates/dpaste/history.html
Normal file
49
dpaste/templates/dpaste/history.html
Normal file
|
@ -0,0 +1,49 @@
|
|||
{% extends "dpaste/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Snippet History" %}{% endblock %}
|
||||
|
||||
{% block body_type %}data-code-snippet{% endblock %}
|
||||
|
||||
{% block options %}
|
||||
<ul id="snippetOptions">
|
||||
<li>{% trans "Snippet History" %}</li>
|
||||
{% if snippet_list %}
|
||||
<li class="sep"></li>
|
||||
<li>
|
||||
<a href="?delete-all"
|
||||
onclick="return confirm('{% trans "Are you sure you want to delete all snippets?" %}');">{% trans "Delete all Snippets" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<label for="wordwrap">
|
||||
{# Wordwrap is enabled by default for all lexer in the history #}
|
||||
<input type="checkbox" id="wordwrap" checked> Wordwrap
|
||||
</label>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
{% for snippet in snippet_list %}
|
||||
<h3 class="history-header">
|
||||
<a href="{{ snippet.get_absolute_url }}">{% blocktrans with snippet.lexer_name as type %}{{ type }} Snippet{% endblocktrans %}</a>
|
||||
<span class="sep"></span>
|
||||
{% blocktrans with snippet.published|timesince as since %}{{ since }} ago{% endblocktrans %}
|
||||
</h3>
|
||||
|
||||
{% if snippet.lexer == 'text' %}
|
||||
<div class="snippet-text">{% include "dpaste/highlight/text.html" %}</div>
|
||||
{% else %}
|
||||
<div class="snippet-code">{% include "dpaste/highlight/code.html" %}</div>
|
||||
{% endif %}
|
||||
|
||||
{% empty %}
|
||||
<p class="history-empty">
|
||||
{% trans "No snippets saved. Either all your snippets are expired or your cookie has changed." %}</p>
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
35
dpaste/templates/dpaste/includes/form.html
Normal file
35
dpaste/templates/dpaste/includes/form.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
{% load i18n %}
|
||||
|
||||
<form method="post" action="" class="snippet-form {% if new %}is-new{% endif %}">
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors }}
|
||||
|
||||
|
||||
<fieldset class="options">
|
||||
<p style="display: none;">{{ form.title }}</p> {# Honeypot field #}
|
||||
|
||||
<p class="options-lexer">
|
||||
<label for="{{ form.lexer.auto_id }}">{% trans "Syntax" %}</label>
|
||||
{{ form.lexer }}
|
||||
</p>
|
||||
|
||||
<p class="options-expire">
|
||||
<label for="{{ form.expires.auto_id }}">{% trans "Expires" %}</label>
|
||||
{{ form.expires }}
|
||||
</p>
|
||||
|
||||
<p class="action">
|
||||
<button class="btn" type="submit">
|
||||
{% trans "Paste Snippet" %}
|
||||
<span class="sep"></span>
|
||||
<span class="platform-mac">{% trans "⌘+⏎" %}</span>
|
||||
<span class="platform-win">{% trans "Ctrl+⏎" %}</span>
|
||||
</button>
|
||||
</p>
|
||||
</fieldset>
|
||||
|
||||
<p class="content superenter {% if not object %}autofocus{% endif %} {% if form.content.errors %}error{% endif %}">
|
||||
<label for="{{ form.content.auto_id }}">{% trans "Content" %}</label>
|
||||
{{ form.content }}
|
||||
</p>
|
||||
</form>
|
11
dpaste/templates/dpaste/new.html
Normal file
11
dpaste/templates/dpaste/new.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
{% extends "dpaste/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block nav_new %}{% endblock %}
|
||||
|
||||
{% block title %}{% trans "dpaste" %}{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
{% include "dpaste/includes/form.html" %}
|
||||
{% endblock %}
|
|
@ -1,116 +0,0 @@
|
|||
{% extends "dpaste/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}dpaste{% endblock %}
|
||||
{% block headline %}
|
||||
<input type="text" value="{{ request.build_absolute_uri }}"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
|
||||
<!-- ======================================================================
|
||||
Snippet Options
|
||||
======================================================================= -->
|
||||
<div class="snippet-options">
|
||||
<span>
|
||||
{% if snippet.expire_type == 1 %}
|
||||
{% blocktrans with date=snippet.expires|timeuntil %}Expires in: {{ date }}{% endblocktrans %}
|
||||
{% elif snippet.expire_type == 2 %}
|
||||
{% trans "Snippet never expires" %}
|
||||
{% elif snippet.expire_type == 3 %}
|
||||
{% trans "One-Time snippet" %}
|
||||
{% endif %}
|
||||
</span>
|
||||
|
||||
<a href="{% url "snippet_delete" snippet.secret_id %}"
|
||||
onclick="return confirm('{% trans "Really delete this snippet?" %}');">{% trans "Delete Now" %}</a>
|
||||
|
||||
{% if snippet.parent %}
|
||||
<a href="#snippet-diff">{% trans "Compare with previous Snippet" %}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if snippet.expire_type != 3 %}
|
||||
<a href="{% url "snippet_details_raw" snippet.secret_id %}">{% trans "View Raw" %}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if snippet.lexer != 'text' %}
|
||||
<a href="#" id="toggleWordwrap">Wordwrap</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
{% if snippet.expire_type == 3 %}
|
||||
<p class="message">
|
||||
{% trans "This is a one-time snippet." %}
|
||||
{% if snippet.remaining_views > 1 %}
|
||||
{% blocktrans with remaining=snippet.remaining_views %}It is automatically removed after {{ remaining }} further views.{% endblocktrans %}
|
||||
{% elif snippet.remaining_views == 1 %}
|
||||
{% trans "It is automatically removed after the next view." %}
|
||||
{% else %}
|
||||
{% trans "It cannot be viewed again." %}
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<!-- ======================================================================
|
||||
Snippet
|
||||
======================================================================= -->
|
||||
{% if snippet.lexer == 'text' %}
|
||||
<div class="snippet-text">{% include "dpaste/highlight/text.html" %}</div>
|
||||
{% else %}
|
||||
<div class="snippet-code">{% include "dpaste/highlight/code.html" %}</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- ======================================================================
|
||||
Snippet Reply
|
||||
======================================================================= -->
|
||||
<div class="snippet-reply" data-hidden="yes">
|
||||
<h2 class="box">{% trans "Reply to this snippet" %} →</h2>
|
||||
{% include "dpaste/snippet_form.html" %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block script_footer %}
|
||||
{{ block.super }}
|
||||
<script>
|
||||
let reply = document.querySelector('.snippet-reply');
|
||||
reply.onclick = function(e) {
|
||||
this.dataset.hidden = "no";
|
||||
};
|
||||
|
||||
document.getElementById('toggleWordwrap').onclick = function(e) {
|
||||
e.preventDefault();
|
||||
document.querySelector('.snippet-code').classList.toggle('wordwrap');
|
||||
};
|
||||
|
||||
// Line Highlighting
|
||||
let curLine = document.location.hash;
|
||||
if (curLine.startsWith('#L')) {
|
||||
hashlist = curLine.substring(2).split(',');
|
||||
if (hashlist.length > 0 && hashlist[0] !== '') {
|
||||
hashlist.forEach(function(el) {
|
||||
let line = document.getElementById(`l${el}`);
|
||||
if (line)
|
||||
line.classList.add('marked');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let lines = document.querySelectorAll('.snippet-code li');
|
||||
lines.forEach(function(el){
|
||||
el.onclick = function(e) {
|
||||
el.classList.toggle('marked');
|
||||
let hash = 'L';
|
||||
let marked = document.querySelectorAll('.snippet-code li.marked');
|
||||
marked.forEach(function(line){
|
||||
if (hash !== 'L')
|
||||
hash += ',';
|
||||
hash += line.getAttribute('id').substring(1);
|
||||
});
|
||||
window.location.hash = hash;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,29 +0,0 @@
|
|||
{% load i18n %}
|
||||
|
||||
<form method="post" action="" class="snippet-form">
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors }}
|
||||
|
||||
<div style="display: none;">{{ form.title }}</div> {# Honeypot field #}
|
||||
|
||||
<div class="form-content superenter {% if not object %}autofocus{% endif %} {% if form.content.errors %}error{% endif %}">
|
||||
{{ form.content }}
|
||||
</div>
|
||||
|
||||
<div class="form-options">
|
||||
<div class="form-options-lexer">
|
||||
<label for="id_lexer">{% trans "Syntax" %}</label>
|
||||
{{ form.lexer }}
|
||||
</div>
|
||||
|
||||
<div class="form-options-expire">
|
||||
<label for="id_expires">{% trans "Expires in" %}</label>
|
||||
{{ form.expires }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<input type="submit" value="{% trans "Paste it" %}">
|
||||
<span class="shortcut">⌘+⏎ {% trans "or" %} Ctrl+⏎</span>
|
||||
</div>
|
||||
</form>
|
|
@ -1,28 +0,0 @@
|
|||
{% extends "dpaste/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Snippet History" %}{% endblock %}
|
||||
{% block headline %}{% trans "Snippet History" %}{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
<dl class="snippet-list">
|
||||
{% for snippet in snippet_list %}
|
||||
<dt>
|
||||
<a title="{{ snippet.published|date:_("DATETIME_FORMAT") }}"
|
||||
href="{{ snippet.get_absolute_url }}">
|
||||
{% blocktrans with snippet.published|timesince as since %}{{ since }}
|
||||
ago{% endblocktrans %}
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
{{ snippet.excerpt }}
|
||||
</dd>
|
||||
{% empty %}
|
||||
<dt>{% trans "No snippets saved. Either all your snippets are expired or your cookie has changed." %}</dt>
|
||||
{% endfor %}
|
||||
<dt><a href="?delete-all">{% trans "Delete all your snippets" %}</a>
|
||||
</dt>
|
||||
</dl>
|
||||
|
||||
{% endblock %}
|
|
@ -1,12 +0,0 @@
|
|||
{% extends "dpaste/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}dpaste{% endblock %}
|
||||
{% block headline %}dpaste{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
<div class="snippet-new">
|
||||
{% include "dpaste/snippet_form.html" %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -21,10 +21,9 @@ from django.views.generic.detail import DetailView
|
|||
from pygments.lexers import get_lexer_for_filename
|
||||
from pygments.util import ClassNotFound
|
||||
|
||||
from .forms import EXPIRE_CHOICES, SnippetForm, get_expire_values
|
||||
from .highlight import LEXER_DEFAULT, LEXER_KEYS, LEXER_LIST, LEXER_WORDWRAP, \
|
||||
PLAIN_CODE, pygmentize
|
||||
from .models import ONETIME_LIMIT, Snippet
|
||||
from dpaste import highlight
|
||||
from dpaste.forms import EXPIRE_CHOICES, SnippetForm, get_expire_values
|
||||
from dpaste.models import ONETIME_LIMIT, Snippet
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
@ -36,7 +35,7 @@ class SnippetView(FormView):
|
|||
Create a new snippet.
|
||||
"""
|
||||
form_class = SnippetForm
|
||||
template_name = 'dpaste/snippet_new.html'
|
||||
template_name = 'dpaste/new.html'
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(SnippetView, self).get_form_kwargs()
|
||||
|
@ -48,7 +47,7 @@ class SnippetView(FormView):
|
|||
def get_context_data(self, **kwargs):
|
||||
ctx = super(SnippetView, self).get_context_data(**kwargs)
|
||||
ctx.update({
|
||||
'lexer_list': LEXER_LIST,
|
||||
'lexer_list': highlight.LEXER_LIST,
|
||||
})
|
||||
return ctx
|
||||
|
||||
|
@ -63,7 +62,7 @@ class SnippetDetailView(SnippetView, DetailView):
|
|||
tree/diff view.
|
||||
"""
|
||||
queryset = Snippet.objects.all()
|
||||
template_name = 'dpaste/snippet_details.html'
|
||||
template_name = 'dpaste/details.html'
|
||||
slug_url_kwarg = 'snippet_id'
|
||||
slug_field = 'secret_id'
|
||||
|
||||
|
@ -98,18 +97,10 @@ class SnippetDetailView(SnippetView, DetailView):
|
|||
|
||||
ctx = super(SnippetDetailView, self).get_context_data(**kwargs)
|
||||
ctx.update({
|
||||
'highlighted': self.highlight_snippet().splitlines(),
|
||||
'wordwrap': snippet.lexer in LEXER_WORDWRAP and 'True' or 'False',
|
||||
'wordwrap': snippet.lexer in highlight.LEXER_WORDWRAP,
|
||||
})
|
||||
return ctx
|
||||
|
||||
def highlight_snippet(self):
|
||||
snippet = self.get_object()
|
||||
h = pygmentize(snippet.content, snippet.lexer)
|
||||
h = h.replace(u'\t', ' ')
|
||||
return h
|
||||
|
||||
|
||||
class SnippetRawView(SnippetDetailView):
|
||||
"""
|
||||
Display the raw content of a snippet
|
||||
|
@ -143,7 +134,7 @@ class SnippetHistory(TemplateView):
|
|||
Display the last `n` snippets created by this user (and saved in his
|
||||
session).
|
||||
"""
|
||||
template_name = 'dpaste/snippet_list.html'
|
||||
template_name = 'dpaste/history.html'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
snippet_id_list = request.session.get('snippet_list', [])
|
||||
|
@ -167,7 +158,7 @@ class SnippetDiffView(TemplateView):
|
|||
"""
|
||||
Display a diff between two given snippet secret ids.
|
||||
"""
|
||||
template_name = 'dpaste/snippet_diff.html'
|
||||
template_name = 'dpaste/includes/diff.html'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
"""
|
||||
|
@ -209,8 +200,7 @@ class SnippetDiffView(TemplateView):
|
|||
return diff
|
||||
|
||||
def highlight_snippet(self, content):
|
||||
h = pygmentize(content, 'diff')
|
||||
h = h.replace(u' ', u' ')
|
||||
h = highlight.pygmentize(content, 'diff')
|
||||
h = h.replace(u'\t', ' ')
|
||||
return h
|
||||
|
||||
|
@ -284,7 +274,7 @@ class APIView(View):
|
|||
"""
|
||||
def post(self, request, *args, **kwargs):
|
||||
content = request.POST.get('content', '')
|
||||
lexer = request.POST.get('lexer', LEXER_DEFAULT).strip()
|
||||
lexer = request.POST.get('lexer', highlight.LEXER_DEFAULT).strip()
|
||||
filename = request.POST.get('filename', '').strip()
|
||||
expires = request.POST.get('expires', '').strip()
|
||||
format = request.POST.get('format', 'default').strip()
|
||||
|
@ -295,12 +285,12 @@ class APIView(View):
|
|||
# We need at least a lexer or a filename
|
||||
if not lexer and not filename:
|
||||
return HttpResponseBadRequest('No lexer or filename given. Unable to '
|
||||
'determine a highlight. Valid lexers are: %s' % ', '.join(LEXER_KEYS))
|
||||
'determine a highlight. Valid lexers are: %s' % ', '.join(highlight.LEXER_LIST))
|
||||
|
||||
# A lexer is given, check if its valid at all
|
||||
if lexer and lexer not in LEXER_KEYS:
|
||||
if lexer and lexer not in highlight.LEXER_KEYS:
|
||||
return HttpResponseBadRequest('Invalid lexer "%s" given. Valid lexers are: %s' % (
|
||||
lexer, ', '.join(LEXER_KEYS)))
|
||||
lexer, ', '.join(highlight.LEXER_KEYS)))
|
||||
|
||||
# No lexer is given, but we have a filename, try to get the lexer out of it.
|
||||
# In case Pygments cannot determine the lexer of the filename, we fallback
|
||||
|
@ -310,7 +300,7 @@ class APIView(View):
|
|||
lexer_cls = get_lexer_for_filename(filename)
|
||||
lexer = lexer_cls.aliases[0]
|
||||
except (ClassNotFound, IndexError):
|
||||
lexer = PLAIN_CODE
|
||||
lexer = highlight.PLAIN_CODE
|
||||
|
||||
if expires:
|
||||
expire_options = [str(i) for i in dict(EXPIRE_CHOICES).keys()]
|
||||
|
|
1412
package-lock.json
generated
Normal file
1412
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
13
package.json
Normal file
13
package.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "dpaste",
|
||||
"version": "3.0.0",
|
||||
"scripts": {
|
||||
"build": "node-sass --output-style compressed -o build client/scss/dpaste.scss && uglifyjs -o build/dpaste.js client/js/dpaste.js",
|
||||
"watch-css": "npm run build && node-sass --source-map true -o build/ --watch client/scss/dpaste.scss ",
|
||||
"postinstall": "npm build"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-sass": "^4.7.2",
|
||||
"uglify-es": "^3.3.9"
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
node-sass --output-style compressed --output dpaste/static/dpaste/ dpaste/static/dpaste/dpaste.scss $1
|
Loading…
Reference in a new issue