Added spoiler extension to the marked.js markdown preview

This commit is contained in:
Michael House 2022-06-05 15:56:11 -05:00
commit 03aa2ca48e
22 changed files with 300 additions and 487 deletions

View file

@ -3,8 +3,13 @@
:root {
--primary: #1a6187;
--bright: #2384b8;
--very-bright: #78c0e6;
--primary-dark1: #165476;
--primary-dark2: #134662;
--primary-light1: #2280B3;
--primary-light2: #2F9CD7;
--dark: #c7c7c7;
--secondary: #c7c7c7;
--gray: #c7c7c7;
@ -31,16 +36,16 @@
a { color: var(--primary); }
.btn-primary { color: var(--primary); }
.btn-primary:hover { color: var(--bright); }
.btn-primary:hover { color: var(--primary-light1); }
.btn-secondary { color: var(--primary); }
.btn-secondary:hover { color: var(--bright); }
.btn-secondary:hover { color: var(--primary-light1); }
.btn-success { color: var(--primary); }
.btn-success:hover { color: var(--bright); }
.btn-success:hover { color: var(--primary-light1); }
.btn-danger { color: var(--primary); }
.btn-danger:hover { color: var(--bright); }
.btn-danger:hover { color: var(--primary-light1); }
.btn-primary.disabled, .btn-primary:disabled,
.btn-secondary.disabled, .btn-secondary:disabled,
@ -49,9 +54,19 @@ a { color: var(--primary); }
color: var(--muted);
}
.comment-write .comment-format .format {
color: var(--primary);
}
.comment-write .comment-format .format:hover {
color: var(--primary-light1);
}
.format .fa-bold:hover, .format .fa-italic:hover, .format .fa-quote-right:hover, .format .fa-link:hover, .format .fa-image:hover {
color: var(--primary-light1);
}
.custom-control-input:checked ~ .custom-control-label::before {
opacity: 1;
background-color: var(--very-bright) !important;
background-color: var(--primary-light2) !important;
border: var(--primary) solid 0.1px;
}
@ -65,7 +80,7 @@ a { color: var(--primary); }
}
.form-control:focus {
border-color: var(--bright) !important;
border-color: var(--primary-light1) !important;
}
.btn {
@ -105,17 +120,76 @@ pre {
blockquote {
color: var(--gray-400);
}
#account-menu {
left: -6px;
}
#main-navigation {
max-width: 2000px;
margin-left: auto;
margin-right: auto;
}
#profilestuff > * {
color: var(--gray-400) !important;
}
#profilestuff a {
color: var(--primary-light2) !important;
}
#profilestuff h1 {
color: var(--primary-light1) !important;
}
div.deleted {
background-color: var(--gray-400) !important;
}
div.deleted.banned {
background-color: var(--gray) !important;
}
.comment-body > .comment-anchor {
padding: 10px;
}
.comment-anchor:target, .unread {
background: #00000055 !important;
}
#frontpage .post-title a:visited, .visited {
color: #7a7a7a !important;
#frontpage .posts .card, #userpage .posts .card, #search .posts .card {
border: none;
}
#search .post-info,
#userpage .post-info,
#frontpage .post-info {
display:flex;
}
#search .post-actions,
#userpage .post-actions,
#frontpage .post-actions {
margin-left:auto;
}
#search .post-actions .list-inline,
#userpage .post-actions .list-inline,
#frontpage .post-actions .list-inline {
align-items: center;
height:100%;
}
#search .post-title a:hover,
#userpage .post-title a:hover,
#frontpage .post-title a:hover {
text-decoration: underline;
}
a::not(.visited),
#frontpage .post-title a:not(:visited),
#userpage .post-title a:not(:visited),
#search .post-title a:not(:visited) {
color: var(--primary-light1);
}
a.visited,
#frontpage .post-title a:visited,
#userpage .post-title a:visited,
#search .post-title a:visited {
color: var(--primary-dark1);
}
.comment .comment-collapse-desktop {
border-left: 2px solid var(--primary-dark1) !important;
}
.comment .comment-collapse-desktop:hover {
border-left: 2px solid var(--primary-light2) !important;
}
.usernote-link {

View file

@ -283,7 +283,7 @@ mark, .mark {
}
code {
font-size: 87.5%;
color: #e83e8c;
color: var(--primary-dark1);
word-wrap: break-word;
}
a > code {
@ -584,7 +584,7 @@ a.btn.disabled, fieldset:disabled a.btn {
border-color: var(--primary);
}
.btn-primary:hover {
color: var;
color: #fff;
background-color: var(--primary);
border-color: #0062cc;
}
@ -2151,9 +2151,18 @@ a.bg-light:hover, a.bg-light:focus, button.bg-light:hover, button.bg-light:focus
}
.shadow-sm {
box-shadow: 0 0.1px 3px 0 rgba(0, 0, 0, 0.05), 0 0.1px 2px 0 rgba(0, 0, 0, 0.03) !important;
-webkit-box-shadow: 0 0.1px 3px 0 rgba(0, 0, 0, 0.05), 0 0.1px 2px 0 rgba(0, 0, 0, 0.03) !important;
-moz-box-shadow: 0 0.1px 3px 0 rgba(0, 0, 0, 0.05), 0 0.1px 2px 0 rgba(0, 0, 0, 0.03) !important;
}
.shadow-lg {
box-shadow: -20px 20px 28px -20px rgba(0,0,0,0.51);
-webkit-box-shadow: -20px 20px 28px -20px rgba(0,0,0,0.51);
-moz-box-shadow: -20px 20px 28px -20px rgba(0,0,0,0.51);
}
.shadow {
box-shadow: 0 0.1px 3px rgba(190, 113, 113, 0.05), 0 0 0 0.1px rgba(0, 0, 0, 0.05) !important;
-webkit-box-shadow: 0 0.1px 3px rgba(190, 113, 113, 0.05), 0 0 0 0.1px rgba(0, 0, 0, 0.05) !important;
-moz-box-shadow: 0 0.1px 3px rgba(190, 113, 113, 0.05), 0 0 0 0.1px rgba(0, 0, 0, 0.05) !important;
}
.shadow-none {
box-shadow: none !important;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 870 B

After

Width:  |  Height:  |  Size: 3.7 KiB

Before After
Before After

View file

@ -243,6 +243,11 @@ function post_comment(fullname){
commentForm=document.getElementById('comment-form-space-'+fullname);
commentForm.innerHTML = data["comment"].replace(/data-src/g, 'src').replace(/data-cfsrc/g, 'src').replace(/style="display:none;visibility:hidden;"/g, '');
bs_trigger(commentForm);
let placeholder = document.getElementById("placeholder-comment");
if(placeholder){
placeholder.parentNode.removeChild(placeholder);
}
}
else {
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];

View file

@ -1,214 +1,55 @@
function appendToken(parentElement, childToken) {
var childElement = tokenToHTMLElement(childToken);
if (typeof childElement === 'string') {
parentElement.textContent += childElement;
} else if (childElement !== null) {
parentElement.appendChild(childElement)
}
}
function appentTextOrElement(parentElement, textOrElement) {
if (typeof textOrElement === 'string') {
parentElement.textContent += textOrElement;
} else {
parentElement.appendChild(textOrElement);
}
}
function motteSpecialMarkdown(text) {
if (typeof text !== 'string') {
return '';
}
var spoilerMatch = text.match(/^(.*?)\|\|(.*?)\|\|(.*)$/);
if (spoilerMatch) {
var left = spoilerMatch[1];
var mid = spoilerMatch[2];
var right = spoilerMatch[3];
var parentSpan = document.createElement('span');
var leftSpan = document.createElement('span');
var spoilerSpan = document.createElement('span');
var rightSpan = document.createElement('span');
spoilerSpan.textContent = mid;
spoilerSpan.classList.add('spoiler');
appentTextOrElement(leftSpan, motteSpecialMarkdown(left));
appentTextOrElement(rightSpan, motteSpecialMarkdown(right));
parentSpan.appendChild(leftSpan);
parentSpan.appendChild(spoilerSpan);
parentSpan.appendChild(rightSpan);
return parentSpan;
} else {
return text;
}
}
function tokenToHTMLElement(token) {
var element = null;
if (token.type === 'space') {
element = document.createElement('span');
element.textContent = ' ';
return element;
} else if (typeof token.type === 'undefined' || token.type === 'text') {
element = document.createElement('span');
appentTextOrElement(element, motteSpecialMarkdown(token.text));
return element;
} else if (token.type === 'hr') {
return document.createElement('hr');
} else if (token.type === 'br') {
return document.createElement('br');
} else if (token.type === 'heading') {
element = document.createElement('h' + Math.floor(Math.max(1, Math.min(6, token.depth))));
} else if (token.type === 'code') {
element = document.createElement('pre');
element.setAttribute('data-lang', token.lang);
} else if (token.type === 'list_item') {
element = document.createElement('li');
} else if (token.type === 'blockquote') {
element = document.createElement('blockquote');
} else if (token.type === 'list') {
if (token.ordered) {
element = document.createElement('ol');
} else {
element = document.createElement('ul');
}
} else if (token.type === 'table') {
var table, thead, tbody, tr, th, td;
table = document.createElement('table');
table.classList.add('table');
thead = document.createElement('thead');
tbody = document.createElement('thead');
tr = document.createElement('tr');
for (var x = 0; x < token.header.length; x++) {
th = document.createElement('th');
appendToken(th, token.header[x]);
tr.appendChild(th);
}
thead.appendChild(tr);
table.appendChild(thead);
for (var y = 0; y < token.rows.length; y++) {
row = token.rows[y];
tr = document.createElement('tr');
for (var x = 0; x < row.length; x++) {
td = document.createElement('td');
appendToken(td, row[x]);
tr.appendChild(td);
marked.use({
extensions: [
{
name: 'spoiler',
level: 'block',
start: function(src){
const match = src.match(/\|\|/);
return match != null ? match.index : -1;
},
tokenizer: function(src) {
const rule = /^\|\|([\s\S]*?)\|\|/;
const match = rule.exec(src);
if(match){
const token = { // Token to generate
type: 'spoiler', // Should match "name" above
raw: match[0], // Text to consume from the source
text: match[0].trim(), // Additional custom properties
tokens: [] // Array where child inline tokens will be generated
};
this.lexer.inline(
token.text.slice(2,-2),
token.tokens
);
return token;
}
},
renderer(token) {
const content = this.parser.parseInline(token.tokens);
return `<span class="spoiler">${content}</span>`;
}
tbody.appendChild(tr);
}
table.appendChild(tbody);
return table;
} else if (token.type === 'paragraph') {
element = document.createElement('p');
} else if (token.type === 'div') {
element = document.createElement('div');
} else if (token.type === 'em') {
element = document.createElement('i');
} else if (token.type === 'strong') {
element = document.createElement('b');
} else if (token.type === 'del') {
element = document.createElement('del');
} else if (token.type === 'codespan') {
element = document.createElement('code');
element.textContent = token.text;
return element;
} else if (token.type === 'escape') {
} else if (token.type === 'link') {
element = document.createElement('a');
element.setAttribute('href', token.href);
element.textContent = token.text;
return element;
} else if (token.type === 'image') {
element = document.createElement('img');
element.setAttribute('src', token.href);
element.setAttribute('alt', token.text);
return element;
} else {
console.log(token);
element = document.createElement('div');
}
var children = (token.tokens || token.items || []);
if (element !== null && children.length > 0) {
for (var i = 0; i < children.length; i++) {
var childElement = tokenToHTMLElement(children[i]);
if (childElement.outerHTML.match(/"spoiler"/g)) {
console.log(element, token, childElement, children[i]);
}
appendToken(element, children[i]);
}
} else if (element.children.length === 0 && element.textContent === '') {
element.textContent += token.text;
}
return element;
}
function safeMarkdown(input) {
// var seenTokens = [];
// var outputToken = {"type": "div", "raw": input, "text": "", "tokens": []};
// function seeRecursive(token) {
// seenTokens.push(token);
// var children = (
// token.tokens
// || token.items
// || (token.header||[]).concat(token.rows||[])
// || []
// );
// if (token.header) {
// children = children.concat(token.header);
// }
// for (var y = 0; y < (token.rows||[]).length; y++) {
// children = children.concat(token.rows[y]);
// }
// for (var i = 0; i < children.length; i++) {
// seeRecursive(children[i]);
// }
// }
// marked.use({
// walkTokens: function(token) {
// if (!seenTokens.includes(token)) {
// outputToken.tokens.push(token);
// seeRecursive(token);
// }
// },
// });
// marked(input);
// marked.use({
// walkTokens: false,
// tokenizer: false,
// });
// [ 'escape', 'del', ];
// return tokenToHTMLElement(outputToken);
const html = marked.parse(input);
return DOMPurify.sanitize(html);
}
setTimeout(() => markdown('post-text','preview'), 200);
]
});
function markdown(first, second) {
var input = document.getElementById(first).value;
var input = document.getElementById(first);
var dest = document.getElementById(second);
for (var i = 0; i < dest.children.length; i++) {
dest.removeChild(dest.children[i]);
if(dest && input && input.value.trim() !== ''){
for (var i = 0; i < dest.children.length; i++) {
dest.removeChild(dest.children[i]);
}
const html = marked.parse(input.value);
dest.innerHTML = DOMPurify.sanitize(html);
}
document.getElementById(second).innerHTML = safeMarkdown(input);
}
function charLimit(form, text) {
var input = document.getElementById(form);
var text = document.getElementById(text);
var length = input.value.length;
var maxLength = input.getAttribute("maxlength");
function charLimit(form, content) {
let input = document.getElementById(form);
let text = document.getElementById(content);
let length = input.value.length;
let maxLength = input.getAttribute("maxlength");
if (length >= maxLength) {
text.style.color = "#E53E3E";
@ -219,6 +60,7 @@ function charLimit(form, text) {
else {
text.style.color = "#A0AEC0";
}
text.innerText = length + ' / ' + maxLength;
}
setTimeout(() => markdown('post-text','preview'), 200);

View file

@ -392,8 +392,6 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, ccmode="false"
@app.get("/changelog")
@auth_required
def changelog(v):
try: page = max(int(request.values.get("page", 1)), 1)
except: page = 1

View file

@ -287,10 +287,14 @@ def contact(v):
@auth_required
def submit_contact(v):
body = request.values.get("message")
email = request.values.get("email")
if not body: abort(400)
if not email: email = None
body = f'This message has been sent automatically to all admins via [/contact](/contact)\n\nMessage:\n\n' + body
body_html = sanitize(body)
header = "This message has been sent automatically to all admins via [/contact](/contact)\n"
email = f"<strong>Email</strong>: {email}\n"
message = f"<strong>Message</strong>:\n{body}\n\n"
html = sanitize(f"{header}\n{email}\n{message}")
if request.files.get("file") and request.headers.get("cf-ipcountry") != "T1":
file=request.files["file"]
@ -298,7 +302,7 @@ def submit_contact(v):
name = f'/images/{time.time()}'.replace('.','') + '.webp'
file.save(name)
url = process_image(name)
body_html += f'<img data-bs-target="#expandImageModal" data-bs-toggle="modal" onclick="expandDesktopImage(this.src)" class="img" src="{url}" loading="lazy">'
html += f'<img data-bs-target="#expandImageModal" data-bs-toggle="modal" onclick="expandDesktopImage(this.src)" class="img" src="{url}" loading="lazy">'
elif file.content_type.startswith('video/'):
file.save("video.mp4")
with open("video.mp4", 'rb') as f:
@ -310,15 +314,13 @@ def submit_contact(v):
if error == 'File exceeds max duration': error += ' (60 seconds)'
return {"error": error}, 400
if url.endswith('.'): url += 'mp4'
body_html += f"<p>{url}</p>"
html += f"<p>{url}</p>"
else: return {"error": "Image/Video files only"}, 400
new_comment = Comment(author_id=v.id,
parent_submission=None,
level=1,
body_html=body_html,
body_html=html,
sentto=2
)
g.db.add(new_comment)

View file

@ -275,7 +275,7 @@ def upvoters(v, username):
pos = (pos+1, users[pos][1])
except: pos = (len(users)+1, 0)
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Up', name2=f'@{username} biggest simps')
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Up', name2=f'Who upvotes @{username}')
@ -301,7 +301,7 @@ def downvoters(v, username):
pos = (pos+1, users[pos][1])
except: pos = (len(users)+1, 0)
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Down', name2=f'@{username} biggest haters')
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Down', name2=f'Who downvotes @{username}')
@app.get("/@<username>/upvoting")
@auth_required
@ -325,7 +325,7 @@ def upvoting(v, username):
pos = (pos+1, users[pos][1])
except: pos = (len(users)+1, 0)
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Up', name2=f'Who @{username} simps for')
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Up', name2=f'Who @{username} upvotes')
@app.get("/@<username>/downvoting")
@auth_required
@ -349,7 +349,7 @@ def downvoting(v, username):
pos = (pos+1, users[pos][1])
except: pos = (len(users)+1, 0)
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Down', name2=f'Who @{username} hates')
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Down', name2=f'Who @{username} downvotes')

View file

@ -61,7 +61,7 @@
{% if (c.is_banned or c.deleted_utc or c.is_blocking) and not (v and v.admin_level > 1) and not (v and v.id==c.author_id) %}
<div id="comment-{{c.id}}" class="comment">
<span class="comment-collapse-desktop d-none d-md-block" style="border-left: 2px solid #{{c.author.namecolor}}"onclick="collapse_comment('{{c.id}}', this.parentElement)"></span>
<span class="comment-collapse-desktop d-none d-md-block" onclick="collapse_comment('{{c.id}}', this.parentElement)"></span>
<div class="comment-body">
@ -158,7 +158,7 @@
<div id="comment-{{c.id}}" class="anchor comment {% if standalone and level==1 %} mt-0{% endif %} {% if c.collapse_for_user(v,request.path) %}collapsed{% endif %}" style="{% if isreply %}padding-left:0!important;{% else %}border-left: 2px solid {% if c.ghost %}var(--primary){% else %}#{{c.author.namecolor}};{% endif %}{% endif %}">
{% if not isreply %}
<span class="comment-collapse-desktop d-none d-md-block" style="border-left: 2px solid {% if c.ghost %}var(--primary){% else %}#{{c.author.namecolor}}{% endif %}" onclick="collapse_comment('{{c.id}}', this.parentElement)"></span>
<span class="comment-collapse-desktop d-none d-md-block" onclick="collapse_comment('{{c.id}}', this.parentElement)"></span>
{% endif %}
<div class="comment-body">
@ -202,7 +202,7 @@
{% if not c.author %}
{{c.print()}}
{% endif %}
<a href="/@{{c.author_name}}" class="user-name text-decoration-none" onclick='popclick({{c.author.json_popover(v) | tojson}})' data-bs-placement="bottom" data-bs-toggle="popover" data-bs-trigger="click" data-content-id="popover" role="button" tabindex="0" style="color:#{{c.author.namecolor}}; font-size:12px; font-weight:bold;"><img loading="lazy" src="{{c.author.profile_url}}" class="profile-pic-25 mr-2"><span {% if c.author.patron and not c.distinguish_level %}class="patron" style="background-color:#{{c.author.namecolor}};"{% elif c.distinguish_level %}class="mod"{% endif %}>{{c.author_name}}</span></a>
<a href="/@{{c.author_name}}" class="user-name text-decoration-none" onclick='popclick({{c.author.json_popover(v) | tojson}})' data-bs-placement="bottom" data-bs-toggle="popover" data-bs-trigger="click" data-content-id="popover" role="button" tabindex="0" style="color:var(--primary-light1); font-size:12px; font-weight:bold;"><img loading="lazy" src="{{c.author.profile_url}}" class="profile-pic-25 mr-2"><span {% if c.author.patron and not c.distinguish_level %}class="patron" style="background-color:#{{c.author.namecolor}};"{% elif c.distinguish_level %}class="mod"{% endif %}>{{c.author_name}}</span></a>
{% if v and v.admin_level > 2 %}
<span
class="usernote-link"
@ -551,11 +551,6 @@
&nbsp;
<a class="btn btn-secondary format m-0" role="button" onclick="makeQuote('reply-form-body-{{c.fullname}}')" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Quote"><i class="fas fa-quote-right"></i></a>
&nbsp;
<label class="btn btn-secondary format m-0" for="gif-reply-btn-{{c.fullname}}" onclick="commentForm('reply-form-body-{{c.fullname}}');getGif()" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">
<span id="gif-reply-btn-{{c.fullname}}" class="font-weight-bolder text-uppercase">GIF</span>
</label>
<label class="btn btn-secondary format m-0" for="file-upload-reply-{{c.fullname}}">
<div id="filename-show-reply-{{c.fullname}}"><i class="far fa-image"></i></div>
<input autocomplete="off" id="file-upload-reply-{{c.fullname}}" type="file" multiple="multiple" name="file" accept="image/*, video/*" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} onchange="changename('filename-show-reply-{{c.fullname}}','file-upload-reply-{{c.fullname}}')" hidden>
@ -834,6 +829,7 @@
{% endif %}
{% if v %}
<script src="/assets/js/vendor/purify.min.js?v=251"></script>
<script src="/assets/js/vendor/marked.min.js?v=251"></script>
<script src="/assets/js/marked.custom.js?v=251"></script>
<script src="/assets/js/comments_v.js?v=266"></script>

View file

@ -22,12 +22,13 @@
<h1 class="article-title">Contact {{SITE_NAME}} Admins</h1>
<p>Use this form to contact {{SITE_NAME}} Admins.</p>
<label class="mt-3">Your Email</label>
<input autocomplete="off" class="form-control" value="{{v.email}}" readonly="readonly" disabled>
<form id="contactform" action="/send_admin" method="post" enctype="multipart/form-data">
<label class="mt-3">Your Email</label>
{% if v and v.email %}
<input autocomplete="off" class="form-control" name="email" value="{{v.email}}" placeholder="(optional)">
{% else %}
<input autocomplete="off" class="form-control" name="email" value="" placeholder="(optional)">
{% endif %}
<label for="input-message" class="mt-3">Your message</label>
<input type="hidden" name="formkey" value="{{v.formkey}}">
<textarea autocomplete="off" maxlength="10000" id="input-message" form="contactform" name="message" class="form-control" required></textarea>

View file

@ -1,5 +1,5 @@
<nav class="shadow shadow-md fixed-top">
<nav id="main-navigation" class="shadow shadow-md fixed-top">
<style>
body {padding-top: 60.89px !important}
@media (max-width: 767.98px) {
@ -130,12 +130,12 @@
aria-haspopup="true" aria-expanded="false">
<div class="d-flex">
<div><img alt="your profile picture" loading="lazy" src="{{v.profile_url}}" class="profile-pic-35"></div>
<div class="text-left pl-2">
<div style="color: var(--bright)" class="text-small font-weight-bold {% if v.patron %}patron{% endif %}"><span {% if v.patron %}class="patron" style="background-color:#{{v.namecolor}}"{% endif %}>{{v.username}}</span></div>
<div class="text-left pl-2 d-flex align-items-center">
<div style="color: var(--primary-light1)" class="text-small font-weight-bold {% if v.patron %}patron{% endif %}"><span {% if v.patron %}class="patron" style="background-color:#{{v.namecolor}}"{% endif %}>{{v.username}}</span></div>
</div>
</div>
</a>
<div class="dropdown-menu dropdown-menu-right dropdown-menu-lg-left border-0 shadow fade px-0">
<div id="account-menu" class="dropdown-menu dropdown-menu-right dropdown-menu-lg-left border-0 shadow fade px-0">
<div class="px-2">
<a class="dropdown-item" href="{{v.url}}"><i class="fas fa-user-circle fa-fw mr-3"></i>My
profile</a>
@ -149,8 +149,6 @@
<a class="dropdown-item" rel="nofollow noopener noreferrer" href="https://github.com/themotte/rDrama"><i class="fab fa-github fa-fw mr-3"></i>Source code</a>
<a class="dropdown-item" rel="nofollow noopener noreferrer" href="{{config('GUMROAD_LINK')}}"><i class="fas fa-dollar-sign fa-fw mr-3"></i>Donate</a>
<a class="dropdown-item" href="/contact"><i class="fas fa-file-signature fa-fw mr-3"></i>Contact us</a>
</div>
<div class="px-2">

View file

@ -37,26 +37,7 @@
</a>
</button>
{% endif %}
{% if v %}
<button class="col px-0 btn btn-dead m-0" style="background: None !important; border: None;">
<a href="/chat" class="text-decoration-none" role="button">
<div class="text-center {% if request.path=='/chat' %}text-primary{% else %}text-muted{% endif %}">
<i class="fas fa-messages text-lg"></i>
<div class="text-small">Chat</div>
</div>
</a>
</button>
{% if v and v.admin_level > 1 %}
<button class="col px-0 mr-3 btn btn-dead m-0" style="background: None !important; border: None;">
<a href="/shop" class="text-decoration-none" role="button">
<div class="text-center {% if request.path=='/shop' %}text-primary{% else %}text-muted{% endif %}">
<i class="fas fa-store text-lg"></i>
<div class="text-small">Shop</div>
</div>
</a>
</button>
{% endif %}
{% else %}
{% if not v %}
<button class="col px-0 mr-3 btn btn-dead m-0" style="background: None !important; border: None;">
<a href="/signup" class="text-decoration-none" role="button">
<div class="text-center text-muted">

View file

@ -6,9 +6,9 @@
{% endif %}
{% if not p.ghost or v.id == AEVANN_ID %}<a class="list-inline-item" href="/votes?link={{p.fullname}}"><i class="fas fa-arrows-v"></i>Votes</a>{% endif %}
{# {% if not p.ghost or v.id == AEVANN_ID %}<a class="list-inline-item" href="/votes?link={{p.fullname}}"><i class="fas fa-arrows-v"></i>Votes</a>{% endif %} #}
<a class="list-inline-item copy-link" role="button" data-clipboard-text="{{p.permalink}}"><i class="fas fa-copy"></i>Copy link</a>
{# <a class="list-inline-item copy-link" role="button" data-clipboard-text="{{p.permalink}}"><i class="fas fa-copy"></i>Copy link</a> #}
{% if v %}
<a id="subscribe-{{p.id}}" class="{% if p.id in v.subscribed_idlist() %}d-none{% endif %} list-inline-item" role="button" onclick="post_toast2(this,'/subscribe/{{p.id}}','subscribe-{{p.id}}','unsubscribe-{{p.id}}')"><i class="fas fa-eye"></i>Subscribe</a>
@ -36,20 +36,20 @@
{% if v %}
<a class="list-inline-item" role="button" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-ellipsis-h fa-fw"></i></a>
<ul class="dropdown-menu">
{% if v.admin_level %}
{# {% if v.admin_level %}
<a id="distinguish-{{p.id}}" class="dropdown-item {% if p.distinguish_level %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast2(this,'/distinguish/{{p.id}}','distinguish-{{p.id}}','undistinguish-{{p.id}}')"><i class="fas fa-crown"></i>Distinguish</a>
<a id="undistinguish-{{p.id}}" class="dropdown-item {% if not p.distinguish_level %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast2(this,'/distinguish/{{p.id}}','distinguish-{{p.id}}','undistinguish-{{p.id}}')"><i class="fas fa-crown"></i>Undistinguish</a>
{% endif %}
{% endif %} #}
{% if v.admin_level > 1 %}
<a id="pin-{{p.id}}" class="dropdown-item {% if p.stickied %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast2(this,'/sticky/{{p.id}}','pin-{{p.id}}','unpin-{{p.id}}')"><i class="fas fa-thumbtack fa-rotate--45"></i>Pin</a>
<a id="unpin-{{p.id}}" class="dropdown-item {% if not p.stickied %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast2(this,'/unsticky/{{p.id}}','pin-{{p.id}}','unpin-{{p.id}}')"><i class="fas fa-thumbtack fa-rotate--45"></i>Unpin</a>
{% endif %}
{% if v.admin_level > 1 or v.id == p.author_id %}
{# {% if v.admin_level > 1 or v.id == p.author_id %}
<a id="club-{{p.id}}" class="dropdown-item {% if p.club %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast2(this,'/toggle_club/{{p.id}}','club-{{p.id}}','unclub-{{p.id}}')"><i class="fas fa-eye-slash"></i>Mark club</a>
<a id="unclub-{{p.id}}" class="dropdown-item {% if not p.club %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast2(this,'/toggle_club/{{p.id}}','club-{{p.id}}','unclub-{{p.id}}')"><i class="fas fa-eye"></i>Unmark club</a>
{% endif %}
{% endif %} #}
{% if v.admin_level > 1 %}
{% if "/reported/" in request.path %}

View file

@ -20,10 +20,10 @@
{% if v.id==p.author_id %}
{% if v.admin_level == 1 %}
{# {% if v.admin_level == 1 %}
<button id="distinguish2-{{p.id}}" class="{% if p.distinguish_level %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left" role="button" onclick="post_toast2(this,'/distinguish/{{p.id}}','distinguish2-{{p.id}}','undistinguish2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-crown text-center mr-3"></i>Distinguish</button>
<button id="undistinguish2-{{p.id}}" class="{% if not p.distinguish_level %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left" role="button" onclick="post_toast2(this,'/distinguish/{{p.id}}','distinguish2-{{p.id}}','undistinguish2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-crown text-center mr-3"></i>Undistinguish</button>
{% endif %}
{% endif %} #}
{% if request.path.startswith('/@') %}
<button id="pin-profile2-{{p.id}}" class="{% if p.is_pinned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-muted text-left"role="button" onclick="post_toast2(this,'/pin/{{p.id}}','pin-profile2-{{p.id}}','unpin-profile2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center mr-3"></i>Pin to profile</button>
@ -36,8 +36,8 @@
<button id="delete-{{p.id}}" class="{% if p.deleted_utc %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-danger" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#deletePostModal" onclick="delete_postModal('{{p.id}}')"><i class="far fa-trash-alt mr-3"></i>Delete</button>
<button id="club3-{{p.id}}" class="{% if p.club %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button" onclick="post_toast2(this,'/toggle_club/{{p.id}}','club3-{{p.id}}','unclub3-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-eye-slash mr-3"></i>Mark club</button>
<button id="unclub3-{{p.id}}" class="{% if not p.club %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="post_toast2(this,'/toggle_club/{{p.id}}','club3-{{p.id}}','unclub3-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-eye mr-3"></i>Unmark club</button>
{# <button id="club3-{{p.id}}" class="{% if p.club %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button" onclick="post_toast2(this,'/toggle_club/{{p.id}}','club3-{{p.id}}','unclub3-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-eye-slash mr-3"></i>Mark club</button>
<button id="unclub3-{{p.id}}" class="{% if not p.club %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="post_toast2(this,'/toggle_club/{{p.id}}','club3-{{p.id}}','unclub3-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-eye mr-3"></i>Unmark club</button> #}
<button id="mark3-{{p.id}}" class="{% if p.over_18 %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-danger" onclick="post_toast2(this,'/toggle_post_nsfw/{{p.id}}','mark3-{{p.id}}','unmark3-{{p.id}}')" data-bs-dismiss="modal"><i class="far fa-eye-evil text-center mr-3"></i>Mark +18</button>
<button id="unmark3-{{p.id}}" class="{% if not p.over_18 %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-success" onclick="post_toast2(this,'/toggle_post_nsfw/{{p.id}}','mark3-{{p.id}}','unmark3-{{p.id}}')" data-bs-dismiss="modal"><i class="far fa-eye-evil text-center mr-3"></i>Unmark +18</button>

View file

@ -13,12 +13,11 @@
<button class="nobackground btn btn-link btn-block btn-lg text-left text-muted" data-bs-dismiss="modal" onclick="togglePostEdit('{{p.id}}')"><i class="far fa-edit text-center text-muted mr-3"></i>Edit</button>
{% endif %}
<button id="club2-{{p.id}}" class="{% if p.club %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-info text-left" role="button" onclick="post_toast2(this,'/toggle_club/{{p.id}}','club2-{{p.id}}','unclub2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-eye-slash mr-3"></i>Mark club</button>
{# <button id="club2-{{p.id}}" class="{% if p.club %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-info text-left" role="button" onclick="post_toast2(this,'/toggle_club/{{p.id}}','club2-{{p.id}}','unclub2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-eye-slash mr-3"></i>Mark club</button>
<button id="unclub2-{{p.id}}" class="{% if not p.club %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-info text-left" role="button" onclick="post_toast2(this,'/toggle_club/{{p.id}}','club2-{{p.id}}','unclub2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-eye mr-3"></i>Unmark club</button>
<button id="distinguish2-{{p.id}}" class="{% if p.distinguish_level %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast2(this,'/distinguish/{{p.id}}','distinguish2-{{p.id}}','undistinguish2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-crown text-center text-primary mr-3"></i>Distinguish</button>
<button id="undistinguish2-{{p.id}}" class="{% if not p.distinguish_level %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast2(this,'/distinguish/{{p.id}}','distinguish2-{{p.id}}','undistinguish2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-crown text-center text-primary mr-3"></i>Undistinguish</button>
<button id="undistinguish2-{{p.id}}" class="{% if not p.distinguish_level %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast2(this,'/distinguish/{{p.id}}','distinguish2-{{p.id}}','undistinguish2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-crown text-center text-primary mr-3"></i>Undistinguish</button> #}
<button id="pin2-{{p.id}}" class="{% if p.stickied %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast2(this,'/sticky/{{p.id}}','pin2-{{p.id}}','unpin2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-primary mr-3"></i>Pin</button>

View file

@ -90,43 +90,7 @@
</div>
</div>
<div class="body d-lg-flex border-bottom">
<label class="text-black w-lg-25">Theme Color</label>
<div class="d-flex">
<form action="/settings/themecolor" id="themecolor-form" method="post" class="color-picker" style="line-height: 0">
<input type="hidden" name="formkey" value="{{v.formkey}}">
{% for themecolor in COLORS %}
<input autocomplete="off" type="radio" name="themecolor" id="themecolor-{{themecolor}}" value="{{themecolor}}" {% if v.themecolor == themecolor %}checked{% endif %} onclick="document.getElementById('themecolor-form').submit()">
<label class="color-radio" for="themecolor-{{themecolor}}">
<span style="background-color: #{{themecolor}}">
{% if v.themecolor.lower() == themecolor %}
<i class="fas fa-check text-white"></i>
{% else %}
&nbsp;
{% endif %}
</span>
</label>
{% endfor %}
</form>
</div>
<p class="text-small mb-2">Or type a color code:</p>
<div class="d-flex">
<form action="/settings/themecolor" id="color-code-form" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input class="form-control" type="text" name="themecolor" id="color-code" value="{% if v.themecolor %}{{v.themecolor}}{% endif %}">
<label class="btn btn-secondary text-capitalize mr-2 mt-2 mb-0">Update<input type="text" for="color-code" onclick="form.submit()" hidden=""></label>
</form>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="theme">Website Backgrounds</label>
@ -297,60 +261,7 @@
</form>
</div>
</div>
<div class="body d-lg-flex border-bottom">
<label class="text-black w-lg-25">Profile Anthem</label>
<div class="w-lg-100">
<p>Must be a youtube video link.</p>
<form action="/settings/song_change" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input autocomplete="off" type="text" name="song" class="form-control" value="{% if v.song %}https://youtu.be/{{v.song}}{% endif %}" placeholder='Enter a youtube video link here'>
<br><small>In some browsers, users have to click at least once anywhere in the profile page for the anthem to play.</small>
<div class="d-flex mt-2">
<input autocomplete="off" class="btn btn-primary ml-auto" type="submit" value="Change Profile Anthem">
</div>
</form>
</div>
</div>
<div class="body d-lg-flex border-bottom">
<label class="text-black w-lg-25">Name Color</label>
<div class="d-flex">
<form action="/settings/namecolor" id="color-form" method="post" class="color-picker" style="line-height: 0">
<input type="hidden" name="formkey" value="{{v.formkey}}">
{% for color in COLORS %}
<input autocomplete="off" type="radio" name="color" id="color-{{color}}" value="{{color}}" {% if v.namecolor == color %}checked{% endif %} onclick="document.getElementById('color-form').submit()">
<label class="color-radio" for="color-{{color}}">
<span style="background-color: #{{color}}">
{% if v.namecolor.lower() == color %}
<i class="fas fa-check text-white"></i>
{% else %}
&nbsp;
{% endif %}
</span>
</label>
{% endfor %}
</form>
</div>
<p class="text-small mb-2">Or type a color code:</p>
<div class="d-flex">
<form action="/settings/namecolor" id="color-code-form" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input autocomplete="off" class="form-control" type="text" name="color" id="color-code" maxlength="6" value="{% if v.namecolor %}{{v.namecolor}}{% endif %}">
<label class="btn btn-secondary text-capitalize mr-2 mt-2 mb-0">Update<input autocomplete="off" type="text" for="color-code" onclick="form.submit()" hidden=""></label>
</form>
</div>
</div>
</div>
<div class="body d-lg-flex border-bottom">
@ -509,28 +420,6 @@
</div>
</div>
<div class="body d-lg-flex border-bottom">
<label class="text-black w-lg-25">Enemies</label>
<div class="w-lg-100">
<form id="profile-enemies" action="/settings/profile" method="post" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<div class="input-group mb-2">
<textarea autocomplete="off" id="enemies-text" class="form-control rounded" aria-label="With textarea" placeholder="Enter your enemies on the site..." rows="3" name="enemies" form="profile-enemies" maxlength="1500">{% if v.enemies %}{{v.enemies}}{% endif %}</textarea>
</div>
<pre></pre>
<div class="d-flex">
<small>Limit of 500 characters</small>
<input autocomplete="off" class="btn btn-primary ml-auto" id="enemiesSave" type="submit" value="Save Changes">
</div>
</form>
</div>
</div>
{% if v.patron or v.id == MOOSE_ID %}
<div class="body d-lg-flex border-bottom">

View file

@ -44,14 +44,12 @@
</div>
<div class="footer">
<div class="d-flex">
<a class="btn btn-success" role="button" onclick="post_toast(this,'/settings/gumroad')">Claim paypig rewards</a>
{% if v.email %}
<input autocomplete="off" class="btn btn-primary ml-auto" type="submit" value="Update email">
{% else %}
<input autocomplete="off" class="btn btn-primary ml-auto" type="submit" value="Add email">
{% endif %}
</div>
<span class="text-small-extra text-muted pl-1">Must be same email as gumroad</span>
</div>
</form>
</div>

View file

@ -179,10 +179,10 @@
👻
{% else %}
{% if p.author.verified %}<i class="fas fa-badge-check align-middle ml-1 {% if p.author.verified=='Glowiefied' %}glow{% endif %}" style="color:{% if p.author.verifiedcolor %}#{{p.author.verifiedcolor}}{% else %}#1DA1F2{% endif %}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{p.author.verified}}"></i>
{% if p.author.verified %}<i class="fas fa-badge-check align-middle ml-1 {% if p.author.verified=='Glowiefied' %}glow{% endif %}" style="color:{% if p.author.verifiedcolor %}#{{p.author.verifiedcolor}}{% else %}var(--primary){% endif %}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{p.author.verified}}"></i>
{% endif %}
<a href="/@{{p.author_name}}" class="user-name text-decoration-none" onclick='popclick({{p.author.json_popover(v) | tojson}})' data-bs-placement="bottom" data-bs-toggle="popover" data-bs-trigger="click" data-content-id="popover" role="button" tabindex="0" style="color: #{{p.author.namecolor}}; font-weight: bold"><img loading="lazy" src="{{p.author.profile_url}}" class="profile-pic-25 mr-2"><span {% if p.author.patron and not p.distinguish_level %}class="patron" style="background-color:#{{p.author.namecolor}};"{% elif p.distinguish_level %}class="mod"{% endif %}>{{p.author_name}}</span></a>{% if p.author.customtitle %}&nbsp;<bdi style="color: #{{p.author.titlecolor}}">&nbsp;{{p.author.customtitle | safe}}</bdi>{% endif %}
<a href="/@{{p.author_name}}" class="user-name text-decoration-none" onclick='popclick({{p.author.json_popover(v) | tojson}})' data-bs-placement="bottom" data-bs-toggle="popover" data-bs-trigger="click" data-content-id="popover" role="button" tabindex="0" style="color: var(--primary-light1); font-weight: bold"><img loading="lazy" src="{{p.author.profile_url}}" class="profile-pic-25 mr-2"><span {% if p.author.patron and not p.distinguish_level %}class="patron" style="background-color:#{{p.author.namecolor}};"{% elif p.distinguish_level %}class="mod"{% endif %}>{{p.author_name}}</span></a>{% if p.author.customtitle %}&nbsp;<bdi style="color: #{{p.author.titlecolor}}">&nbsp;{{p.author.customtitle | safe}}</bdi>{% endif %}
{% if v and v.admin_level > 2 %}
<span
class="usernote-link"
@ -488,9 +488,6 @@
&nbsp;
<a class="btn btn-secondary format d-inline-block m-0" role="button"><i class="fas fa-quote-right" onclick="makeQuote('reply-form-body-{{p.fullname}}')" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Quote"></i></a>
&nbsp;
<label class="btn btn-secondary format d-inline-block m-0" for="gif-reply-btn-{{p.fullname}}">
<span id="gif-reply-btn-{{p.fullname}}" class="font-weight-bolder text-uppercase" onclick="commentForm('reply-form-body-{{p.fullname}}');getGif()" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span>
</label>
<label class="format btn btn-secondary m-0 ml-1 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-reply-{{p.fullname}}">
<div id="filename-show-reply-{{p.fullname}}"><i class="far fa-image"></i></div>
<input autocomplete="off" id="file-upload-reply-{{p.fullname}}" type="file" multiple="multiple" name="file" accept="image/*, video/*" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} onchange="changename('filename-show-reply-{{p.fullname}}','file-upload-reply-{{p.fullname}}')" hidden>
@ -563,16 +560,20 @@
{% elif not p.replies and p.deleted_utc == 0 %}
<div class="comment-section text-center py-7">
<span class="fa-stack fa-2x text-muted mb-4">
<i class="fas fa-square text-gray-500 opacity-25 fa-stack-2x"></i>
<i class="fas text-gray-500 fa-ghost fa-stack-1x text-lg"></i>
</span>
<h2 class="h5">Be the first to comment!</h2>
{% if v %}
<p class="text-muted">This comment section is a ghost town...</p>
{% else %}
<p class="text-muted">This comment section is a ghost town. <a href="/login?redirect={{request.path | urlencode}}">Sign in</a></p>
{% endif %}
<div class="row no-gutters" id="placeholder-comment">
<div class="col">
<span class="fa-stack fa-2x text-muted mb-4">
<i class="fas fa-square text-gray-500 opacity-25 fa-stack-2x"></i>
<i class="fas text-gray-500 fa-ghost fa-stack-1x text-lg"></i>
</span>
<h2 class="h5">Be the first to comment!</h2>
{% if v %}
<p class="text-muted">This comment section is a ghost town...</p>
{% else %}
<p class="text-muted">This comment section is a ghost town. <a href="/login?redirect={{request.path | urlencode}}">Sign in</a></p>
{% endif %}
</div>
</div>
</div>
{% endif %}

View file

@ -139,6 +139,13 @@
<div class="card-block text-left x-scroll-parent my-md-auto w-100">
<div class="post-meta text-left x-scroll mb-md-2">
<h5 class="card-title post-title text-left mb-0 pb-0 pb-md-1">
<a id="{{p.id}}-title" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}" class="{% if voted and v.id == AEVANN_ID %}visited{% endif %}">
{% if p.club %}<span class="patron font-weight-bolder mr-1" style="background-color:red; font-size:12px; line-height:2;">{{CC}}</span>{% endif %}
{% if p.flair %}<span class="patron font-weight-bolder mr-1" style="background-color:var(--primary); font-size:12px; line-height:2;">{{p.flair | safe}}</span>{% endif %}
{{p.realtitle(v) | safe}}
</a></h5>
{% if p.sub %}
<a href='/h/{{p.sub}}'>/h/{{p.sub}}</a>&nbsp;&nbsp;
{% endif %}
@ -146,68 +153,83 @@
{% if p.sub and p.author.exiled_from(p.sub) %}
<a role="button"><i class="fas fa-campfire text-danger" data-bs-toggle="tooltip" data-bs-placement="bottom" title="User has been exiled from /h/{{p.sub}}"></i></a>
{% endif %}
{% if p.bannedfor %}
<a role="button"><i class="fas fa-hammer-crash text-danger" data-bs-toggle="tooltip" data-bs-placement="bottom" title="User was banned for this post{% if p.author.banned_by %} by @{{p.author.banned_by.username}}{% endif %}"></i></a>
{% endif %}
{% for a in p.awards|reverse %}
<i class="{{a.class_list}} px-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{a.title}} Award given by @{{a.user.username}}"></i>
{% endfor %}
{% if v and v.admin_level > 1 and p.author.shadowbanned %}
<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Shadowbanned by @{{p.author.shadowbanned}}"></i>
{% endif %}
{% if p.stickied %}
<i id='pinned-{{p.id}}' class="fas fa-thumbtack fa-rotate--45 text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Pinned by @{{p.stickied}}" {% if p.stickied_utc %}onmouseover="pinned_timestamp('pinned-{{p.id}}')" data-timestamp={{p.stickied_utc}} {% endif %}></i>
{% endif %}
{% if p.distinguish_level %}<i class="fas fa-broom text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{SITE_NAME}} Admin, speaking officially"></i>{% endif %}
{% if p.is_pinned and request.path.startswith('/@') %}<i class="fas fa-thumbtack fa-rotate--45 text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Pinned to profile"></i>{% endif %}
{% if p.over_18 %}<span class="badge badge-danger text-small-extra mr-1">+18</span>{% endif %}
{% if p.is_bot %} <i class="fas fa-robot text-info" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Bot"></i>{% endif %}
{% if p.is_blocking %}<i class="fas fa-user-minus text-warning" data-bs-toggle="tooltip" data-bs-placement="bottom" title="You're blocking this user, but you can see this post because you're an admin."></i>{% endif %}
{% if p.is_blocked %}<i class="fas fa-user-minus text-danger" data-bs-toggle="tooltip" data-bs-placement="bottom" title="This user is blocking you."></i>{% endif %}
{% if p.private %}<span class="badge border-warning border-1 text-small-extra">Draft</span>{% endif %}
{% if p.active_flags(v) %}<a class="btn btn-primary" role="button" style="padding:1px 5px; font-size:10px"onclick="document.getElementById('flaggers-{{p.id}}').classList.toggle('d-none')">{{p.active_flags(v)}} Reports</a>{% endif %}
{% if not p.author %}
{{p.print()}}
{% endif %}
{% if p.ghost %}
👻
{% else %}
{% if p.author.verified %}<i class="fas fa-badge-check align-middle ml-1 {% if p.author.verified=='Glowiefied' %}glow{% endif %}" style="color:{% if p.author.verifiedcolor %}#{{p.author.verifiedcolor}}{% else %}#1DA1F2{% endif %}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{p.author.verified}}"></i>
{% endif %}
<a href="/@{{p.author_name}}" class="user-name text-decoration-none" onclick='popclick({{p.author.json_popover(v) | tojson}})' data-bs-placement="bottom" data-bs-toggle="popover" data-bs-trigger="click" data-content-id="popover" role="button" tabindex="0" style="color: #{{p.author.namecolor}}; font-weight: bold;"><img loading="lazy" src="{{p.author.profile_url}}" class="profile-pic-25 mr-2"><span {% if p.author.patron and not p.distinguish_level %}class="patron" style="background-color:#{{p.author.namecolor}};"{% elif p.distinguish_level %}class="mod"{% endif %}>{{p.author_name}}</span></a>{% if p.author.customtitle %}<bdi style="color: #{{p.author.titlecolor}}">&nbsp;&nbsp;{{p.author.customtitle | safe}}</bdi>{% endif %}
{% if v and v.admin_level > 2 %}
<span
class="usernote-link"
data-micromodal-trigger="modal-1"
onclick='fillnote( {{p.author.json_popover(v) | tojson}}, {{p.id}}, null )'>_U_</span>
{% endif %}
{% endif %}
<span data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('timestamp-{{p.id}}','{{p.created_utc}}')" id="timestamp-{{p.id}}">&nbsp;{{p.age_string}}</span>
&nbsp;
({% if p.is_image %}image post{% elif p.is_video %}video post{% elif p.domain %}<a href="/search/posts/?q=domain%3A{{p.domain}}&sort=new&t=all" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %}>{{p.domain}}</a>{% else %}text post{% endif %})
{% if p.edited_utc %}
&nbsp;&nbsp;Edited <span data-bs-toggle="tooltip" data-bs-placement="bottom" id="edited_timestamp-{{p.id}}" onmouseover="timestamp('edited_timestamp-{{p.id}}','{{p.edited_utc}}')">{{p.edited_string}}</span>
{% endif %}
&nbsp;&nbsp;{{p.views}} thread views
</div>
<h5 class="card-title post-title text-left w-lg-95 mb-0 pb-0 pb-md-1">
<a id="{{p.id}}-title" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}" class="{% if voted and v.id == AEVANN_ID %}visited{% endif %} stretched-link">
{% if p.club %}<span class="patron font-weight-bolder mr-1" style="background-color:red; font-size:12px; line-height:2;">{{CC}}</span>{% endif %}
{% if p.flair %}<span class="patron font-weight-bolder mr-1" style="background-color:var(--primary); font-size:12px; line-height:2;">{{p.flair | safe}}</span>{% endif %}
{{p.realtitle(v) | safe}}
</a></h5>
<div class="post-info text-left">
<div class="post-author x-scroll">
{% if p.bannedfor %}
<a role="button"><i class="fas fa-hammer-crash text-danger" data-bs-toggle="tooltip" data-bs-placement="bottom" title="User was banned for this post{% if p.author.banned_by %} by @{{p.author.banned_by.username}}{% endif %}"></i></a>
{% endif %}
<div class="post-actions mt-2 d-none d-md-block">
<ul class="list-inline text-right d-flex">
{% for a in p.awards|reverse %}
<i class="{{a.class_list}} px-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{a.title}} Award given by @{{a.user.username}}"></i>
{% endfor %}
{% if v and v.admin_level > 1 and p.author.shadowbanned %}
<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Shadowbanned by @{{p.author.shadowbanned}}"></i>
{% endif %}
{% if p.stickied %}
<i id='pinned-{{p.id}}' class="fas fa-thumbtack fa-rotate--45 text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Pinned by @{{p.stickied}}" {% if p.stickied_utc %}onmouseover="pinned_timestamp('pinned-{{p.id}}')" data-timestamp={{p.stickied_utc}} {% endif %}></i>
{% endif %}
{% if p.distinguish_level %}<i class="fas fa-broom text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{SITE_NAME}} Admin, speaking officially"></i>{% endif %}
{% if p.is_pinned and request.path.startswith('/@') %}<i class="fas fa-thumbtack fa-rotate--45 text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Pinned to profile"></i>{% endif %}
{% if p.over_18 %}<span class="badge badge-danger text-small-extra mr-1">+18</span>{% endif %}
{% if p.is_bot %} <i class="fas fa-robot text-info" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Bot"></i>{% endif %}
{% if p.is_blocking %}<i class="fas fa-user-minus text-warning" data-bs-toggle="tooltip" data-bs-placement="bottom" title="You're blocking this user, but you can see this post because you're an admin."></i>{% endif %}
{% if p.is_blocked %}<i class="fas fa-user-minus text-danger" data-bs-toggle="tooltip" data-bs-placement="bottom" title="This user is blocking you."></i>{% endif %}
{% if p.private %}<span class="badge border-warning border-1 text-small-extra">Draft</span>{% endif %}
{% if p.active_flags(v) %}<a class="btn btn-primary" role="button" style="padding:1px 5px; font-size:10px"onclick="document.getElementById('flaggers-{{p.id}}').classList.toggle('d-none')">{{p.active_flags(v)}} Reports</a>{% endif %}
<span data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('timestamp-{{p.id}}','{{p.created_utc}}')" id="timestamp-{{p.id}}">&nbsp;{{p.age_string}} by </span>
{% if not p.author %}
{{p.print()}}
{% endif %}
{% if p.ghost %}
👻
{% else %}
{% if p.author.verified %}<i class="fas fa-badge-check align-middle ml-1 {% if p.author.verified=='Glowiefied' %}glow{% endif %}" style="color:{% if p.author.verifiedcolor %}#{{p.author.verifiedcolor}}{% else %}#1DA1F2{% endif %}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{p.author.verified}}"></i>
{% endif %}
<a href="/@{{p.author_name}}"
class="user-name text-decoration-none"
data-bs-placement="bottom"
data-bs-toggle="popover"
data-bs-trigger="click"
data-content-id="popover"
role="button"
tabindex="0"
style="color: var(--primary-light1); font-weight: bold;">
<span
{% if p.author.patron and not p.distinguish_level %}
class="patron"
style="background-color:#{{p.author.namecolor}};"
{% elif p.distinguish_level %}
class="mod"
{% endif %}>{{p.author_name}}</span>
</a>{% if p.author.customtitle %}<bdi style="color: #{{p.author.titlecolor}}">&nbsp;&nbsp;{{p.author.customtitle | safe}}</bdi>{% endif %}
{% if v and v.admin_level > 2 %}
<span
class="usernote-link"
data-micromodal-trigger="modal-1"
onclick='fillnote( {{p.author.json_popover(v) | tojson}}, {{p.id}}, null )'>_U_</span>
{% endif %}
{% endif %}
&nbsp;
({% if p.is_image %}image post{% elif p.is_video %}video post{% elif p.domain %}<a href="/search/posts/?q=domain%3A{{p.domain}}&sort=new&t=all" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %}>{{p.domain}}</a>{% else %}text post{% endif %})
{% if p.edited_utc %}
&nbsp;&nbsp;Edited <span data-bs-toggle="tooltip" data-bs-placement="bottom" id="edited_timestamp-{{p.id}}" onmouseover="timestamp('edited_timestamp-{{p.id}}','{{p.edited_utc}}')">{{p.edited_string}}</span>
{% endif %}
&nbsp;&nbsp;{{p.views}} thread views
</div>
<div class="post-actions d-none d-md-block">
<ul class="list-inline text-right d-flex">
{% if p.realbody(v) %}
<a class="list-inline-item" role="button" onclick="expandText('{{p.id}}')"><i class="fas fa-expand-alt mr-0 text-expand-icon-{{p.id}}"></i></a>
{% endif %}
@ -218,8 +240,9 @@
</a>
</li>
{% include 'post_actions.html' %}
</ul>
</div>
</ul>
</div>
</div>
</div>
</div>

View file

@ -13,7 +13,7 @@
<meta property="og:article:author" content="@{{u.username}}">
<meta property="article:section" content="{{u.username}}'s profile - {{SITE_NAME}}">
<meta property="article:published_time" content="{{u.created_date}}">
<meta property="og:description" name="description" content="{{u.coins}} coins - Joined {{u.created_date}} - {% if u.stored_subscriber_count >=1 and not u.is_private and not u.is_nofollow %}{{u.stored_subscriber_count}} Followers - {% endif %}{% if not u.is_private %} {{0 if u.shadowbanned else u.post_count}} Posts - {{0 if u.shadowbanned else u.comment_count}} Comments - {% endif %}{{u.bio}}">
<meta property="og:description" name="description" content="Joined {{u.created_date}} - {% if u.stored_subscriber_count >=1 and not u.is_private and not u.is_nofollow %}{{u.stored_subscriber_count}} Followers - {% endif %}{% if not u.is_private %} {{0 if u.shadowbanned else u.post_count}} Posts - {{0 if u.shadowbanned else u.comment_count}} Comments - {% endif %}{{u.bio}}">
<meta property="og:author" name="author" content="@{{u.username}}">
<meta property="og:title" content="{{u.username}}">
<meta property="og:image" content="{{u.banner_url}}">
@ -24,7 +24,7 @@
<meta name="twitter:site" content="{{SITE_FULL}}">
<meta name="twitter:title" content="{{u.username}}'s profile - {{SITE_NAME}}">
<meta name="twitter:creator" content="@{{u.username}}">
<meta name="twitter:description" content="{{u.coins}} coins - Joined {{u.created_date}} - {% if u.stored_subscriber_count >=1 and not u.is_private and not u.is_nofollow %}{{u.stored_subscriber_count}} Followers -{% endif %} {% if not u.is_private %} {{0 if u.shadowbanned else u.post_count}} Posts - {{0 if u.shadowbanned else u.comment_count}} Comments - {% endif %}{{u.bio}}">
<meta name="twitter:description" content="Joined {{u.created_date}} - {% if u.stored_subscriber_count >=1 and not u.is_private and not u.is_nofollow %}{{u.stored_subscriber_count}} Followers -{% endif %} {% if not u.is_private %} {{0 if u.shadowbanned else u.post_count}} Posts - {{0 if u.shadowbanned else u.comment_count}} Comments - {% endif %}{{u.bio}}">
<meta name="twitter:image" content="{{u.banner_url}}">
<meta name="twitter:url" content="{{u.url}}">
{% endblock %}
@ -51,7 +51,7 @@
{% if u.unban_utc %}<h5 class="text-primary">>{{u.unban_string}}</h5>{% endif %}
{% endif %}
<div class="d-flex align-items-center mt-1 mb-2">
<h1 class="font-weight-bolder h3 mb-0" style="color: var(--bright)"><span {% if u.patron %}class="patron" style="background-color:#{{u.namecolor}}"{% endif %}>{{u.username}}</span></h1>
<h1 class="font-weight-bolder h3 mb-0"><span {% if u.patron %}class="patron" style="background-color:#{{u.namecolor}}"{% endif %}>{{u.username}}</span></h1>
{% if u.username != u.original_username %}
<span>
@ -104,7 +104,7 @@
{% else %}<pre></pre>
{% endif %}
<div class="font-weight-bolder mb-2"><a class="mr-1" href="/@{{u.username}}/upvoters">Simps</a> | <a class="mx-1" href="/@{{u.username}}/downvoters">Haters</a> | <a class="mx-1" href="/@{{u.username}}/upvoting">Simps for</a> | <a class="ml-1" href="/@{{u.username}}/downvoting">Hates</a></div>
<div class="font-weight-bolder mb-2"><a class="mr-1" href="/@{{u.username}}/upvoters">Upvoters</a> | <a class="mx-1" href="/@{{u.username}}/downvoters">Downvoters</a> | <a class="mx-1" href="/@{{u.username}}/upvoting">Upvoted</a> | <a class="ml-1" href="/@{{u.username}}/downvoting">Downvoted</a></div>
<div class="font-weight-bolder">
<a href="/@{{u.username}}/followers">{{u.stored_subscriber_count}} follower{{'s' if u.stored_subscriber_count != 1 else ''}}</a>&nbsp;&nbsp;
@ -113,12 +113,12 @@
joined <span data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{u.created_datetime}}">{{u.created_date}}</span>
</div>
{% if u.basedcount %}<p class="text-muted">Based Count: {{u.basedcount}}</p>{% endif %}
{% if u.bio_html %}
<pre></pre>
<div class="text-muted font-weight-bolder">{{u.bio_html | safe}}</div>
{% else %}
<pre></pre>
<p class="text-muted">No bio...</p>
{% endif %}
@ -276,9 +276,7 @@
{% endif %}
<pre></pre>
<p>User ID: {{u.id}}</p>
<p>Coins spent: {{u.coins_spent}}</p>
<p>True score: {{u.truecoins}}</p>
<p>Winnings: {{u.winnings}}</p>
{% if u.is_private %}
<p>User has private mode enabled.</p>
{% endif %}
@ -365,7 +363,7 @@
<pre></pre>
{% endif %}
<div class="font-weight-bolder mb-2"><a class="mr-1" href="/@{{u.username}}/upvoters">Simps</a> | <a class="mx-1" href="/@{{u.username}}/downvoters">Haters</a> | <a class="mx-1" href="/@{{u.username}}/upvoting">Simps for</a> | <a class="ml-1" href="/@{{u.username}}/downvoting">Hates</a></div>
<div class="font-weight-bolder mb-2"><a class="mr-1" href="/@{{u.username}}/upvoters">Upvoters</a> | <a class="mx-1" href="/@{{u.username}}/downvoters">Downvoters</a> | <a class="mx-1" href="/@{{u.username}}/upvoting">Upvoted</a> | <a class="ml-1" href="/@{{u.username}}/downvoting">Downvoted</a></div>
<div class="font-weight-normal">
<a href="/@{{u.username}}/followers" class="font-weight-bold">{{u.stored_subscriber_count}} follower{{'s' if u.stored_subscriber_count != 1 else ''}}</a>&nbsp;&nbsp;
@ -547,9 +545,7 @@
{% endif %}
<pre></pre>
<p>User ID: {{u.id}}</p>
<p>Coins spent: {{u.coins_spent}}</p>
<p>True score: {{u.truecoins}}</p>
<p>Winnings: {{u.winnings}}</p>
{% if u.is_private %}
<p>User has private mode enabled.</p>
{% endif %}
@ -697,7 +693,8 @@
</nav>
{% endif %}
<script src="/assets/js/vendor/marked.js?v=251"></script>
<script src="/assets/js/vendor/purify.min.js?v=251"></script>
<script src="/assets/js/vendor/marked.min.js?v=251"></script>
<script src="/assets/js/marked.custom.js?v=251"></script>
{% endblock %}

View file

@ -1 +1 @@
{"Bots": true, "Fart mode": false, "Read-only mode": false, "Signups": true}
{"Bots": true, "Fart mode": false, "Read-only mode": false, "Signups": true}