mirror of
http://git.carcosa.net/jmcbray/brutaldon.git
synced 2024-11-23 07:13:52 -05:00
Merge pull request #66 from garbados/master
Bring Brutaldon mirror up to date Note the primary repository is https://git.carcosa.net/jmcbray/brutaldon
This commit is contained in:
commit
00e35409ef
1
.gitignore
vendored
1
.gitignore
vendored
@ -112,3 +112,4 @@ pip-selfcheck.json
|
||||
node_modules
|
||||
/TAGS
|
||||
.vscode
|
||||
package-lock.json
|
||||
|
8
brutaldon/context_processors.py
Normal file
8
brutaldon/context_processors.py
Normal file
@ -0,0 +1,8 @@
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
def bookmarklet_url(request):
|
||||
share_url = request.build_absolute_uri(reverse("share"))
|
||||
return {
|
||||
"bookmarklet_url": f"javascript:location.href='{share_url}?url='+encodeURIComponent(location.href)+';title='+encodeURIComponent(document.title)"
|
||||
}
|
@ -38,6 +38,7 @@ class PreferencesForm(forms.ModelForm):
|
||||
"click_to_load",
|
||||
"lightbox",
|
||||
"filter_notifications",
|
||||
"bundle_notifications",
|
||||
"poll_frequency",
|
||||
]
|
||||
|
||||
|
@ -33,6 +33,13 @@ def set_up_default_themes(apps, schema_editor):
|
||||
is_brutalist=False,
|
||||
)
|
||||
solar.save()
|
||||
material = Theme(
|
||||
name="Material",
|
||||
main_css="css/bulmaswatch-materia.min.css",
|
||||
tweaks_css="css/brutaldon-material.css",
|
||||
is_brutalist=False,
|
||||
)
|
||||
material.save()
|
||||
brutalism = Theme(
|
||||
name="FULLBRUTALISM", main_css="css/fullbrutalism.css", is_brutalist=True
|
||||
)
|
||||
|
19
brutaldon/migrations/0023_preference_bundle_notifications.py
Normal file
19
brutaldon/migrations/0023_preference_bundle_notifications.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 2.2.7 on 2019-11-04 23:53
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("brutaldon", "0022_auto_20190506_0938")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="preference",
|
||||
name="bundle_notifications",
|
||||
field=models.BooleanField(
|
||||
default=False,
|
||||
help_text="Collapse together boosts or likes of the same toot in the notifications page.",
|
||||
),
|
||||
)
|
||||
]
|
@ -65,6 +65,12 @@ class Preference(models.Model):
|
||||
default=False,
|
||||
help_text=_("""Exclude boosts and favs from your notifications."""),
|
||||
)
|
||||
bundle_notifications = models.BooleanField(
|
||||
default=False,
|
||||
help_text=_(
|
||||
"""Collapse together boosts or likes of the same toot in the notifications page."""
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class Account(models.Model):
|
||||
|
@ -67,6 +67,7 @@ TEMPLATES = [
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
"brutaldon.context_processors.bookmarklet_url",
|
||||
]
|
||||
},
|
||||
}
|
||||
@ -203,4 +204,4 @@ ANONYMOUS_HOME_URL = "about"
|
||||
GAB_RICKROLL_URL = "https://invidio.us/watch?v=dQw4w9WgXcQ"
|
||||
|
||||
# Version number displayed on about page
|
||||
BRUTALDON_VERSION = "2.12.1"
|
||||
BRUTALDON_VERSION = "2.14.1"
|
||||
|
237
brutaldon/static/css/brutaldon-material.css
Normal file
237
brutaldon/static/css/brutaldon-material.css
Normal file
@ -0,0 +1,237 @@
|
||||
body > section > div.container {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.reblog-icon {
|
||||
position: relative;
|
||||
top: -24px;
|
||||
left: 40px;
|
||||
}
|
||||
|
||||
img.fav-avatar {
|
||||
display: inline;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.media-content {
|
||||
padding: 1.25ex;
|
||||
}
|
||||
|
||||
.is-max-128 img, .is-max-192 img, .is-max-256 img
|
||||
{
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right:0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.is-max-128 {
|
||||
max-height: 128px;
|
||||
max-width: 128px;
|
||||
}
|
||||
|
||||
.is-max-256 {
|
||||
max-height: 256px;
|
||||
max-width: 256px;
|
||||
}
|
||||
|
||||
.is-max-192 {
|
||||
max-height: 192px;
|
||||
max-width: 192px;
|
||||
}
|
||||
|
||||
|
||||
figure.media-left p.image a img
|
||||
{
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
img.avatar
|
||||
{
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.active-context {
|
||||
background-color: #FFF8DC;
|
||||
}
|
||||
|
||||
h2.subtitle
|
||||
{
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
article.media.user-info .content img
|
||||
{
|
||||
max-height: 1.5rem;
|
||||
max-width: 1.5rem;
|
||||
}
|
||||
|
||||
span.account-locked
|
||||
{
|
||||
margin-top: 48px;
|
||||
margin-left: -16px;
|
||||
}
|
||||
|
||||
.errorlist
|
||||
{
|
||||
color: #FF0000;
|
||||
}
|
||||
|
||||
.emoji-box
|
||||
{
|
||||
padding: .75rem;
|
||||
background-color: #FCFCFC;
|
||||
border: 1px solid #CCC;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
img.emoji
|
||||
{
|
||||
display: inline;
|
||||
max-height: 1.5em;
|
||||
max-width: 1.5em;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
emoji-link
|
||||
{
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.content figure.attachment-image
|
||||
{
|
||||
text-align:left;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.media {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
#page-load-indicator
|
||||
{
|
||||
width: 100%;
|
||||
opacity: 0.8;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 666;
|
||||
transition: all 500ms;
|
||||
height: 2px;
|
||||
overflow: hidden;
|
||||
background-color: #ddd;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#page-load-indicator:before{
|
||||
display: block;
|
||||
position: absolute;
|
||||
content: "";
|
||||
left: -200px;
|
||||
width: 200px;
|
||||
height: 4px;
|
||||
background-color: #888;
|
||||
animation: page-loading 1.5s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes page-loading {
|
||||
from {left: -200px; width: 30%;}
|
||||
50% {width: 30%;}
|
||||
70% {width: 70%;}
|
||||
80% { left: 50%;}
|
||||
95% {left: 120%;}
|
||||
to {left: 100%;}
|
||||
}
|
||||
|
||||
#status_count
|
||||
{
|
||||
margin-left: 90%;
|
||||
margin-top: 1rem;
|
||||
background-color: #888;
|
||||
color: #FFF;
|
||||
float: right;
|
||||
padding: 0.5ex;
|
||||
border-radius: 5px;
|
||||
min-height: 1.5rem;
|
||||
min-width: 1.5rem;
|
||||
font-size: 0.8em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#before-main
|
||||
{
|
||||
width: 100%;
|
||||
height: 2em;
|
||||
background-color: #DEDEDE;
|
||||
color: white;
|
||||
margin-top: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#before-main span
|
||||
{
|
||||
margin-left: 50%;
|
||||
}
|
||||
|
||||
input#id_poll_frequency
|
||||
{
|
||||
max-width: 10em;
|
||||
}
|
||||
|
||||
body.has-navbar-fixed-top, html.has-navbar-fixed-top {
|
||||
padding-top: 5rem;
|
||||
}
|
||||
|
||||
.card
|
||||
{
|
||||
margin-top: 1em;
|
||||
margin: 0, auto;
|
||||
max-width: 90%;
|
||||
}
|
||||
|
||||
|
||||
#username_autocomplete
|
||||
{
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.media-content .content a:not(.mention)
|
||||
{
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: dotted;
|
||||
}
|
||||
|
||||
.media-content a.level-item
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
a.navbar-item span:nth-child(2):before
|
||||
{
|
||||
content: " ";
|
||||
}
|
||||
|
||||
|
||||
div.poll {
|
||||
margin-bottom: 1ex;
|
||||
margin-top: 1em;
|
||||
max-width: 90%;
|
||||
}
|
||||
|
||||
|
||||
/* Fix some rules that don't need to be there */
|
||||
.content figure:not(:last-child)
|
||||
{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.content figure:not(:first-child)
|
||||
{
|
||||
margin-top: 0;
|
||||
}
|
2
brutaldon/static/css/bulma.min.css
vendored
2
brutaldon/static/css/bulma.min.css
vendored
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@ html, a, div, div.notification, body, body div, span, object, iframe, h1, h2, h3
|
||||
font-family: "DEC Terminal Modern", Terminus, Inconsolata, Consolas, "Droid Sans Mono", "DejaVu Sans Mono", "Monaco", monospace;
|
||||
color: #ff7700;
|
||||
background-color: #000000;
|
||||
font-size: medium;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@ a, a.button, a.button.is-primary, input.button.is-primary, input, .input, .texta
|
||||
background-color: #000000;
|
||||
font-weight: bolder;
|
||||
text-decoration-line: none;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
a:hover, a.button:hover, a.button.is-primary:hover, input.button.is-primary:hover {
|
||||
@ -204,6 +203,9 @@ img.emoji
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.navbar-item {
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.media {
|
||||
|
@ -2,7 +2,7 @@ html, body, a, div, div.notification, body, body div, span, object, iframe, h1,
|
||||
font-family: "DEC Terminal Modern", Terminus, Inconsolata, Consolas, "Droid Sans Mono", "DejaVu Sans Mono", "Monaco", monospace;
|
||||
color: #00ff77;
|
||||
background-color: #000;
|
||||
font-size: medium;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
tr, td, ul, ol {
|
||||
@ -21,7 +21,7 @@ a, a.button, a.button.is-primary, input.button.is-primary, input, .input, .texta
|
||||
background-color: #000000;
|
||||
font-weight: bolder;
|
||||
text-decoration-line: none;
|
||||
font-size: medium;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
|
||||
@ -208,6 +208,9 @@ img.emoji
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.navbar-item {
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.media {
|
||||
|
@ -72,7 +72,7 @@ function expandCWButtonPrepare()
|
||||
{
|
||||
var theButton = document.querySelector('#expandCWs');
|
||||
if (!theButton) {
|
||||
theButton = document.createElement('p');
|
||||
theButton = document.createElement('button');
|
||||
theButton.id = "expandCWs";
|
||||
theButton.textContent = "Expand CWs";
|
||||
theButton.classList.toggle('button');
|
||||
|
4
brutaldon/static/js/jquery.min.js
vendored
4
brutaldon/static/js/jquery.min.js
vendored
File diff suppressed because one or more lines are too long
6
brutaldon/static/js/loading-attribute-polyfill.min.js
vendored
Executable file
6
brutaldon/static/js/loading-attribute-polyfill.min.js
vendored
Executable file
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* Loading attribute polyfill - https://github.com/mfranzke/loading-attribute-polyfill
|
||||
* @license Copyright(c) 2019 by Maximilian Franzke
|
||||
* Credits for the initial kickstarter / script to @Sora2455, and supported by @diogoterremoto, @dracos and @Flimm - many thanks for that !
|
||||
*/
|
||||
!function(e,t){"use strict";var r,a,o={rootMargin:"256px 0px",threshold:.01,lazyImage:'img[loading="lazy"]',lazyIframe:'iframe[loading="lazy"]'},n={loading:"loading"in HTMLImageElement.prototype&&"loading"in HTMLIFrameElement.prototype,scrolling:"onscroll"in window};"undefined"!=typeof NodeList&&NodeList.prototype&&!NodeList.prototype.forEach&&(NodeList.prototype.forEach=Array.prototype.forEach),"IntersectionObserver"in window&&(r=new IntersectionObserver(function(e,t){e.forEach(function(e){if(0!==e.intersectionRatio){var r=e.target;t.unobserve(r),c(r)}})},o)),a="requestAnimationFrame"in window?window.requestAnimationFrame:function(e){e()};var i="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";function c(e){var t,r,a=[];"picture"===e.parentNode.tagName.toLowerCase()&&(t=e.parentNode,(r=t.querySelector("source[data-lazy-remove]"))&&t.removeChild(r),a=Array.prototype.slice.call(e.parentNode.querySelectorAll("source"))),a.push(e),a.forEach(function(e){e.dataset.lazySrcset&&(e.setAttribute("srcset",e.dataset.lazySrcset),delete e.dataset.lazySrcset)}),e.setAttribute("src",e.dataset.lazySrc),delete e.dataset.lazySrc}function d(e){var t=document.createElement("div");for(t.innerHTML=function(e){var t=e.textContent||e.innerHTML;return!n.loading&&n.scrolling&&(void 0===r?t=t.replace(/(?:\r\n|\r|\n|\t| )src=/g,' lazyload="1" src='):("picture"===e.parentNode.tagName.toLowerCase()&&(t='<source srcset="'+i+'" data-lazy-remove="true"></source>'+t),t=t.replace(/(?:\r\n|\r|\n|\t| )srcset=/g," data-lazy-srcset=").replace(/(?:\r\n|\r|\n|\t| )src=/g,' src="'+i+'" data-lazy-src='))),t}(e);t.firstChild;)n.loading||!n.scrolling||void 0===r||!t.firstChild.tagName||"img"!==t.firstChild.tagName.toLowerCase()&&"iframe"!==t.firstChild.tagName.toLowerCase()||r.observe(t.firstChild),e.parentNode.insertBefore(t.firstChild,e);e.parentNode.removeChild(e)}function s(){document.querySelectorAll("noscript."+e).forEach(d),window.matchMedia("print").addListener(function(e){e.matches&&document.querySelectorAll(o.lazyImage+"[data-lazy-src],"+o.lazyIframe+"[data-lazy-src]").forEach(function(e){c(e)})})}/comp|inter/.test(document.readyState)?a(s):"addEventListener"in document?document.addEventListener("DOMContentLoaded",function(){a(s)}):document.attachEvent("onreadystatechange",function(){"complete"===document.readyState&&s()})}("loading-lazy");
|
@ -46,6 +46,7 @@
|
||||
<script type="text/javascript" src="{% static 'js/intercooler.js' %}"></script>
|
||||
<script type="application/javascript" src="{% static 'js/mousetrap.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/jquery.magnific-popup.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/loading-attribute-polyfill.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/brutaldon-enhancements.js' %}"></script>
|
||||
{% block page_scripts %}
|
||||
{% endblock %}
|
||||
@ -80,12 +81,12 @@
|
||||
<div class="navbar-brand">
|
||||
<a class="navbar-item" href="{% url "home" %}">
|
||||
{% if own_acct %}
|
||||
<img src="{{ own_acct.avatar_static }}"
|
||||
class="image is-32x32 avatar"
|
||||
alt="Brutaldon ('{{ own_acct.username }}')">
|
||||
<img src="{{ own_acct.avatar_static }}"
|
||||
class="image is-32x32 avatar"
|
||||
alt="Brutaldon ('{{ own_acct.username }}')">
|
||||
{% else %}
|
||||
<img src="{% static "images/brutaldon.png" %}"
|
||||
class="image is-32x32" alt="Brutaldon">
|
||||
<img loading="lazy" src="{% static "images/brutaldon.png" %}"
|
||||
class="image is-32x32" alt="Brutaldon">
|
||||
{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
@ -182,13 +183,16 @@
|
||||
<a class="level-item is-size-7" href="https://github.com/jfmcbrayer/brutaldon">
|
||||
Source
|
||||
</a>
|
||||
<span class="level-item is-size-7" >Bookmarklet: <a href="{{ bookmarklet_url }}">Share via brutaldon</a></span>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
{% if preferences.theme.is_brutalist %}
|
||||
<img class="level-item" src="{% static '/images/lynx.gif' %}"
|
||||
<noscript class="loading-lazy">
|
||||
<img loading="lazy" class="level-item" src="{% static '/images/lynx.gif' %}"
|
||||
alt="Lynx Now!">
|
||||
<img class="level-item" src="{% static '/images/now9.gif' %}"
|
||||
<img loading="lazy" class="level-item" src="{% static '/images/now9.gif' %}"
|
||||
alt="Netscape Now!">
|
||||
</noscript>
|
||||
{% endif %}
|
||||
<a class="level-item is-size-7" href="{% url "privacy" %}">
|
||||
Privacy
|
||||
|
5
brutaldon/templates/comma.html
Normal file
5
brutaldon/templates/comma.html
Normal file
@ -0,0 +1,5 @@
|
||||
{% if not forloop.first %}
|
||||
{% if forloop.last %}, and
|
||||
{% else %},
|
||||
{% endif %}
|
||||
{% endif %}
|
@ -1,9 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
{% load humanetime %}
|
||||
{% load taglinks %}
|
||||
{% load sanitizer %}
|
||||
|
||||
{% block title %}
|
||||
Brutaldon ({{ own_acct.username }}) - Notifications timelime
|
||||
Brutaldon ({{ own_acct.username }}) - Notifications timelime
|
||||
{% endblock %}
|
||||
|
||||
{% comment %}
|
||||
@ -21,69 +22,99 @@ mastodon.notifications()[0]
|
||||
|
||||
|
||||
{% block content %}
|
||||
<h1 class="title">Your notifications timeline</h1>
|
||||
{% for note in notes %}
|
||||
{% if note.type == 'mention' %}
|
||||
<p>
|
||||
<strong>{{ note.account.display_name }}</strong>
|
||||
(<a href="{{ note.account.url | localuser }}">{{ note.account.acct }}</a>)
|
||||
mentioned you.
|
||||
</p>
|
||||
<br>
|
||||
{% include "main/toot_partial.html" with toot=note.status reblog=False %}
|
||||
<hr class="is-hidden">
|
||||
{% elif note.type == 'reblog' %}
|
||||
<p>
|
||||
{{ note.account.display_name }}
|
||||
(<a href="{{ note.account.url | localuser }}">{{ note.account.acct }}</a>)
|
||||
boosted your toot.
|
||||
(<span>
|
||||
<small>{{ note.created_at |humane_time }}</small>
|
||||
</span>)
|
||||
</p>
|
||||
{% include "main/toot_partial.html" with toot=note.status reblog=True reblog_by=note.account.acct reblog_icon=note.account.avatar_static %}
|
||||
<hr class="is-hidden">
|
||||
{% elif note.type == 'favourite' %}
|
||||
<p>
|
||||
{{ note.account.display_name }}
|
||||
(<a href="{{ note.account.url | localuser}}">{{ note.account.acct }}</a>)
|
||||
favorited your toot.
|
||||
(<span>
|
||||
<small>{{ note.created_at |humane_time }}</small>
|
||||
</span>)
|
||||
</p>
|
||||
{% include "main/toot_partial.html" with toot=note.status %}
|
||||
<hr class="is-hidden">
|
||||
{% elif note.type == 'follow' %}
|
||||
<article class="media">
|
||||
<figure class="media-left">
|
||||
<p class="image is-64x64">
|
||||
<img src="{{ note.account.avatar_static }}" alt="">
|
||||
</p>
|
||||
</figure>
|
||||
<div class="media-content" >
|
||||
<div class="content">
|
||||
<strong>{{ note.account.display_name }}</strong>
|
||||
(<a href="{{ note.account.url |localuser }}">{{ note.account.acct }}</a>)
|
||||
followed you.
|
||||
(<a href="{{ note.url }}">
|
||||
<small>{{ note.created_at |humane_time }}</small>
|
||||
</a>)
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<hr class="is-hidden">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<h1 class="title">Your notifications timeline</h1>
|
||||
{% for group in groups %}
|
||||
{% if bundle_notifications and group.0.type in bundleable %}
|
||||
{% if group.0.type == 'favourite' %}
|
||||
<p>
|
||||
{% for account in group.accounts %}
|
||||
{% include "comma.html" %}{{ account.display_name | fix_emojos:account.emojis |strip_html |safe }}
|
||||
(<a href="{{ account.url | localuser}}">{{ account.acct }}</a>)
|
||||
{% endfor %}
|
||||
favorited your toot.
|
||||
</p>
|
||||
{% include "main/toot_partial.html" with toot=group.0.status %}
|
||||
<hr class="is-hidden">
|
||||
{% elif group.0.type == 'reblog' %}
|
||||
<p>
|
||||
{% for account in group.accounts %}
|
||||
{% include "comma.html" %}{{ account.display_name | fix_emojos:account.emojis |strip_html |safe }}
|
||||
(<a href="{{ account.url | localuser }}">{{ account.acct }}</a>)
|
||||
{% endfor %}
|
||||
boosted your toot.
|
||||
</p>
|
||||
{% include "main/toot_partial.html" with toot=group.0.status reblog=True reblog_by=group.0.account.acct reblog_icon=group.0.account.avatar_static %}
|
||||
<hr class="is-hidden">
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% for note in group %}
|
||||
{% if note.type == 'mention' %}
|
||||
<p>
|
||||
<strong>{{ note.account.display_name | fix_emojos:note.account.emojis |strip_html |safe }}</strong>
|
||||
(<a href="{{ note.account.url | localuser }}">{{ note.account.acct }}</a>)
|
||||
mentioned you.
|
||||
</p>
|
||||
<br>
|
||||
{% include "main/toot_partial.html" with toot=note.status reblog=False %}
|
||||
<hr class="is-hidden">
|
||||
{% elif note.type == 'reblog' %}
|
||||
<p>
|
||||
{{ note.account.display_name | fix_emojos:note.account.emojis |strip_html |safe }}
|
||||
(<a href="{{ note.account.url | localuser }}">{{ note.account.acct }}</a>)
|
||||
boosted your toot.
|
||||
(<span>
|
||||
<small>{{ note.created_at |humane_time }}</small>
|
||||
</span>)
|
||||
</p>
|
||||
{% include "main/toot_partial.html" with toot=note.status reblog=True reblog_by=note.account.acct reblog_icon=note.account.avatar_static %}
|
||||
<hr class="is-hidden">
|
||||
{% elif note.type == 'favourite' %}
|
||||
<p>
|
||||
{{ note.account.display_name | fix_emojos:note.account.emojis |strip_html |safe }}
|
||||
(<a href="{{ note.account.url | localuser}}">{{ note.account.acct }}</a>)
|
||||
favorited your toot.
|
||||
(<span>
|
||||
<small>{{ note.created_at |humane_time }}</small>
|
||||
</span>)
|
||||
</p>
|
||||
{% include "main/toot_partial.html" with toot=note.status %}
|
||||
<hr class="is-hidden">
|
||||
{% elif note.type == 'follow' %}
|
||||
<article class="media">
|
||||
<figure class="media-left">
|
||||
<p class="image is-64x64">
|
||||
<img src="{{ note.account.avatar_static }}" alt="">
|
||||
</p>
|
||||
</figure>
|
||||
<div class="media-content" >
|
||||
<div class="content">
|
||||
<strong>{{ note.account.display_name | fix_emojos:note.account.emojis |strip_html |safe }}</strong>
|
||||
(<a href="{{ note.account.url |localuser }}">{{ note.account.acct }}</a>)
|
||||
followed you.
|
||||
(<a href="{{ note.url }}">
|
||||
<small>{{ note.created_at |humane_time }}</small>
|
||||
</a>)
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<hr class="is-hidden">
|
||||
{% elif note.type == 'poll' %}
|
||||
<p>A poll you created or voted in has ended.</p>
|
||||
{% include "main/toot_partial.html" with toot=note.status %}
|
||||
<hr class="is-hidden">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<nav class="pagination is-centered" role="navigation" aria-label="pagination">
|
||||
{% if prev %}
|
||||
<a class="pagination-next" href="{% url 'note_prev' prev.min_id %}">Newer</a>
|
||||
{% endif %}
|
||||
{% if next %}
|
||||
<a class="pagination-previous" href="{% url 'note_next' next.max_id %}">Older</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
<nav class="pagination is-centered" role="navigation" aria-label="pagination">
|
||||
{% if prev %}
|
||||
<a class="pagination-next" href="{% url 'note_prev' prev.min_id %}">Newer</a>
|
||||
{% endif %}
|
||||
{% if next %}
|
||||
<a class="pagination-previous" href="{% url 'note_next' next.max_id %}">Older</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
@ -4,7 +4,7 @@
|
||||
{% load taglinks %}
|
||||
{% load static %}
|
||||
|
||||
|
||||
{% if toot %}
|
||||
{% if active %}
|
||||
<article id="toot-{{toot.id}}" class="media box active-context">
|
||||
{% else %}
|
||||
@ -14,14 +14,14 @@
|
||||
<figure class="media-left">
|
||||
<p class="image is-64x64 account-avatar">
|
||||
<a href="{% url "user" toot.account.acct %}">
|
||||
<img src="{{ toot.account.avatar_static }}"
|
||||
<img loading="auto" src="{{ toot.account.avatar_static }}"
|
||||
alt="">
|
||||
</a>
|
||||
</p>
|
||||
{% if reblog %}
|
||||
<p class="image is-32x32 reblog-icon" >
|
||||
<a href="{% url "user" reblog_by %}">
|
||||
<img src ="{{ reblog_icon }}" alt="">
|
||||
<img loading="auto" src ="{{ reblog_icon }}" alt="">
|
||||
</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
@ -29,7 +29,7 @@
|
||||
<div class="media-content">
|
||||
<div class="content">
|
||||
<p>
|
||||
<strong>{{ toot.account.display_name }}</strong>
|
||||
<strong>{{ toot.account.display_name | fix_emojos:toot.account.emojis | strip_html |safe}}</strong>
|
||||
<small><a href="{% url "user" toot.account.acct %}">
|
||||
@{{ toot.account.acct }}</a></small>
|
||||
<a href="{{ toot.url }}">
|
||||
@ -71,9 +71,11 @@
|
||||
{% if toot.card.image %}
|
||||
<div class="column is-one-third">
|
||||
<a href="{{ toot.card.url }}">
|
||||
<img alt="{{ toot.card.title }}"
|
||||
<noscript class="loading-lazy">
|
||||
<img loading="lazy" alt="{{ toot.card.title }}"
|
||||
src="{{ toot.card.image }}"
|
||||
class="is-max-128">
|
||||
</noscript>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -85,7 +87,7 @@
|
||||
</a>
|
||||
</strong>
|
||||
|
||||
<p>{{ toot.card.description }}</p>
|
||||
<p>{{ toot.card.description |truncatechars_html:500}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -98,10 +100,11 @@
|
||||
{% if media.type == "image" %}
|
||||
<figure class="column attachment-image">
|
||||
<a href="{{ media.url }}">
|
||||
<noscript class="loading-lazy">
|
||||
{% if toot.sensitive %}
|
||||
<img src="{% static "images/sensitive.png" %}"
|
||||
<img loading="lazy" src="{% static "images/sensitive.png" %}"
|
||||
{% else %}
|
||||
<img src="{{ media.preview_url }}"
|
||||
<img loading="lazy" src="{{ media.preview_url }}"
|
||||
{% endif %}
|
||||
alt="{% if media.description %}
|
||||
{{ media.description }}
|
||||
@ -114,6 +117,7 @@
|
||||
title="{{ media.description }}"
|
||||
{% endif %}
|
||||
class="image is-max-256">
|
||||
</noscript>
|
||||
</a>
|
||||
</figure>
|
||||
{% else %}
|
||||
@ -122,10 +126,11 @@
|
||||
poster="{{ media.preview_url }}">
|
||||
<source src="{{ media.url }}" type="video/mp4">
|
||||
<a href="{{ media.url }}">
|
||||
<noscript class="loading-lazy">
|
||||
{% if toot.sensitive %}
|
||||
<img src="{% static "images/sensitive.png" %}"
|
||||
<img loading="lazy" src="{% static "images/sensitive.png" %}"
|
||||
{% else %}
|
||||
<img src="{{ media.preview_url }}"
|
||||
<img loading="lazy" src="{{ media.preview_url }}"
|
||||
{% endif %}
|
||||
alt="{% if media.description %}
|
||||
{{ media.description }}
|
||||
@ -138,6 +143,7 @@
|
||||
title="{{ media.description }}"
|
||||
{% endif %}
|
||||
class="image is-max-256">
|
||||
</noscript>
|
||||
</a>
|
||||
</video>
|
||||
</figure>
|
||||
@ -227,3 +233,4 @@
|
||||
</div>
|
||||
<div class="media-right"></div>
|
||||
</article>
|
||||
{% endif %}
|
||||
|
@ -125,6 +125,23 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column is-quarter">
|
||||
<label class="label checkbox" for="id_bundle_notifications">
|
||||
{% render_field form.bundle_notifications class+="checkbox" %}
|
||||
{{ form.bundle_notifications.label }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="column is-quarter">
|
||||
<p class="notification is-info preferences-help">
|
||||
{{ form.bundle_notifications.help_text }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column is-quarter">
|
||||
<label class="label" for="id_poll_frequency">
|
||||
@ -149,6 +166,12 @@
|
||||
value="Save" class="button is-primary" >
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<h2 class="subtitle">Bookmarklet</h2>
|
||||
<p>
|
||||
<a href="{{ bookmarklet_url }}">Share via brutaldon</a>
|
||||
</p>
|
||||
|
||||
<h2 class="subtitle">Filters and More</h2>
|
||||
<p><a href="{% url "list_filters" %}">List filters</a></p>
|
||||
<p><a href="{% url "follow_requests" %}">Follow requests</a></p>
|
||||
|
@ -69,5 +69,6 @@ urlpatterns = [
|
||||
path("accounts/", views.accounts, name="accounts"),
|
||||
path("accounts/<id>", views.accounts, name="accounts"),
|
||||
path("vote/<id>", views.vote, name="vote"),
|
||||
path("share/", views.share, name="share"),
|
||||
path("", views.home, name=""),
|
||||
]
|
||||
|
@ -4,7 +4,6 @@ from django.conf import settings as django_settings
|
||||
from django.shortcuts import render, redirect
|
||||
from django.urls import reverse
|
||||
from django.views.decorators.cache import never_cache, cache_page
|
||||
from django.urls import reverse
|
||||
from django.core.files.uploadhandler import TemporaryFileUploadHandler
|
||||
from django.utils.translation import gettext as _
|
||||
from brutaldon.forms import (
|
||||
@ -24,8 +23,10 @@ from mastodon import (
|
||||
)
|
||||
from urllib import parse
|
||||
from pdb import set_trace
|
||||
from itertools import groupby
|
||||
from inscriptis import get_text
|
||||
from time import sleep
|
||||
from requests import Session
|
||||
import re
|
||||
|
||||
|
||||
@ -33,11 +34,43 @@ class NotLoggedInException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class LabeledList(list):
|
||||
"""A subclass of list that can accept additional attributes"""
|
||||
|
||||
def __new__(self, *args, **kwargs):
|
||||
return super(LabeledList, self).__new__(self, args, kwargs)
|
||||
|
||||
def __init(self, *args, **kwargs):
|
||||
if len(args) == 1 and hasattr(args[0], "__iter__"):
|
||||
list.__init__(self, args[0])
|
||||
else:
|
||||
list.__init__(self, args)
|
||||
self.__dict__.update(kwargs)
|
||||
|
||||
def __call(self, **kwargs):
|
||||
self.__dict__.update(kwargs)
|
||||
return self
|
||||
|
||||
|
||||
global sessons_cache
|
||||
sessions_cache = {}
|
||||
|
||||
VISIBILITIES = ["direct", "private", "unlisted", "public"]
|
||||
|
||||
###
|
||||
### Utility functions
|
||||
###
|
||||
|
||||
|
||||
def get_session(domain):
|
||||
if domain in sessions_cache:
|
||||
return sessions_cache[domain]
|
||||
else:
|
||||
s = Session()
|
||||
sessions_cache[domain] = s
|
||||
return s
|
||||
|
||||
|
||||
def get_usercontext(request):
|
||||
if is_logged_in(request):
|
||||
try:
|
||||
@ -55,6 +88,7 @@ def get_usercontext(request):
|
||||
client_secret=client.client_secret,
|
||||
access_token=user.access_token,
|
||||
api_base_url=client.api_base_id,
|
||||
session=get_session(client.api_base_id),
|
||||
ratelimit_method="throw",
|
||||
)
|
||||
return user, mastodon
|
||||
@ -150,6 +184,12 @@ def user_search_inner(request, query):
|
||||
)
|
||||
|
||||
|
||||
def min_visibility(visibility1, visibility2):
|
||||
return VISIBILITIES[
|
||||
min(VISIBILITIES.index(visibility1), VISIBILITIES.index(visibility2))
|
||||
]
|
||||
|
||||
|
||||
def timeline(
|
||||
request,
|
||||
timeline="home",
|
||||
@ -590,17 +630,42 @@ def note(request, next=None, prev=None):
|
||||
next = notes[-1]._pagination_next
|
||||
except (IndexError, AttributeError, KeyError):
|
||||
next = None
|
||||
|
||||
# Now group notes into lists based on type and status
|
||||
groups = []
|
||||
if account.preferences.bundle_notifications:
|
||||
|
||||
def bundle_key(note):
|
||||
try:
|
||||
return str(note.status.id) + note.type
|
||||
except:
|
||||
return str(note.id) + note.type
|
||||
def group_sort_key(group):
|
||||
return max([k.id for k in group])
|
||||
|
||||
sorted_notes = sorted(notes, key=bundle_key, reverse=True)
|
||||
for _, group in groupby(sorted_notes, bundle_key):
|
||||
group = LabeledList(group)
|
||||
group.accounts = [x.account for x in group]
|
||||
groups.append(group)
|
||||
groups.sort(key=group_sort_key, reverse=True)
|
||||
else:
|
||||
groups.append(notes)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"main/notifications.html",
|
||||
{
|
||||
"notes": notes,
|
||||
"groups": groups,
|
||||
"timeline": "Notifications",
|
||||
"timeline_name": "Notifications",
|
||||
"own_acct": request.session["active_user"],
|
||||
"preferences": account.preferences,
|
||||
"prev": prev,
|
||||
"next": next,
|
||||
"bundleable": ["favourite", "reblog"],
|
||||
"bundle_notifications": account.preferences.bundle_notifications,
|
||||
},
|
||||
)
|
||||
|
||||
@ -713,6 +778,9 @@ def settings(request):
|
||||
account.preferences.filter_notifications = form.cleaned_data[
|
||||
"filter_notifications"
|
||||
]
|
||||
account.preferences.bundle_notifications = form.cleaned_data[
|
||||
"bundle_notifications"
|
||||
]
|
||||
account.preferences.poll_frequency = form.cleaned_data["poll_frequency"]
|
||||
request.session["timezone"] = account.preferences.timezone
|
||||
account.preferences.save()
|
||||
@ -998,7 +1066,9 @@ def reply(request, id):
|
||||
form = PostForm(
|
||||
initial={
|
||||
"status": initial_text,
|
||||
"visibility": toot.visibility,
|
||||
"visibility": min_visibility(
|
||||
toot.visibility, request.session["active_user"].source.privacy
|
||||
),
|
||||
"spoiler_text": toot.spoiler_text,
|
||||
}
|
||||
)
|
||||
@ -1097,6 +1167,37 @@ def reply(request, id):
|
||||
return HttpResponseRedirect(reverse("reply", args=[id]) + "#toot-" + str(id))
|
||||
|
||||
|
||||
@br_login_required
|
||||
def share(request):
|
||||
account, mastodon = get_usercontext(request)
|
||||
if request.method == "GET":
|
||||
params = request.GET
|
||||
if request.method == "POST":
|
||||
params = request.POST
|
||||
title = params.get("title")
|
||||
url = params.get("url")
|
||||
if title:
|
||||
initial_text = f"{title}\n\n{url}"
|
||||
else:
|
||||
initial_text = f"{url}"
|
||||
|
||||
form = PostForm(
|
||||
initial={
|
||||
"status": initial_text,
|
||||
"visibility": request.session["active_user"].source.privacy,
|
||||
}
|
||||
)
|
||||
return render(
|
||||
request,
|
||||
"main/post.html",
|
||||
{
|
||||
"form": form,
|
||||
"own_acct": request.session["active_user"],
|
||||
"preferences": account.preferences,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@never_cache
|
||||
@br_login_required
|
||||
def fav(request, id):
|
||||
|
@ -1,11 +1,12 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"bulma": "^0.7.1",
|
||||
"bulma": "^0.7.5",
|
||||
"bulma-extensions": "^2.2.2",
|
||||
"bulmaswatch": "^0.6.2",
|
||||
"fork-awesome": "^1.1.0",
|
||||
"intercooler": "^1.2.1",
|
||||
"jquery": "^3.3.1",
|
||||
"jquery": "^3.4.1",
|
||||
"loading-attribute-polyfill": "^1.2.0",
|
||||
"magnific-popup": "^1.1.0",
|
||||
"mousetrap": "^1.6.2"
|
||||
}
|
||||
|
43
yarn.lock
43
yarn.lock
@ -1,43 +0,0 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
bulma-extensions@^2.2.2:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/bulma-extensions/-/bulma-extensions-2.2.2.tgz#d46f11d1242a3fdc60a983afaea0b5e6c137362d"
|
||||
integrity sha512-6hV6SiRT7RZD5+scn/462Dz8RURRgxuvlCy+R5LH9U6FLn7Q/sInAA5VdK8c4DKpxZjfsipp72EAKM7yzgzRig==
|
||||
|
||||
bulma@^0.7.1:
|
||||
version "0.7.4"
|
||||
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.7.4.tgz#7e74512e9118d9799021339e67e365ee0ac4f3f9"
|
||||
integrity sha512-krG2rP6eAX1WE0sf6O0SC/FUVSOBX4m1PBC2+GKLpb2pX0qanaDqcv9U2nu75egFrsHkI0zdWYuk/oGwoszVWg==
|
||||
|
||||
bulmaswatch@^0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/bulmaswatch/-/bulmaswatch-0.6.2.tgz#5d102b1986d5f48d7f45ff68354c5fe367dc1c76"
|
||||
integrity sha512-IMYjMqEnHQ1Yhtzkia3ojeFRvJr8DnLBiDMUuvLcGtJwyaAuZ8AQ4tT3TK21lcnt7cngeM3CKzBtkbQulWQI9w==
|
||||
|
||||
fork-awesome@^1.1.0:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/fork-awesome/-/fork-awesome-1.1.7.tgz#1427da1cac3d1713046ee88427e5fcecb9501d21"
|
||||
integrity sha512-IHI7XCSXrKfUIWslse8c/PaaVDT1oBaYge+ju40ihL2ooiQeBpTr4wvIXhgTd2NuhntlvX+M5jYHAPTzNlmv0g==
|
||||
|
||||
intercooler@^1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/intercooler/-/intercooler-1.2.2.tgz#f2d79dcc22fbba4de6dbe782039545df65dbe680"
|
||||
integrity sha512-YpSnEWowbqunu06SCcVe7hC9zu8GkGM/ouk7B61T6CL33WgfH10wyVidFFX0rPtzLzMz1TG/vIzOeac5vrqRJA==
|
||||
|
||||
jquery@^3.3.1:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.0.tgz#8de513fa0fa4b2c7d2e48a530e26f0596936efdf"
|
||||
integrity sha512-ggRCXln9zEqv6OqAGXFEcshF5dSBvCkzj6Gm2gzuR5fWawaX8t7cxKVkkygKODrDAzKdoYw3l/e3pm3vlT4IbQ==
|
||||
|
||||
magnific-popup@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/magnific-popup/-/magnific-popup-1.1.0.tgz#3e7362c5bd18f6785fe99e59d013e20af33d3049"
|
||||
integrity sha1-PnNixb0Y9nhf6Z5Z0BPiCvM9MEk=
|
||||
|
||||
mousetrap@^1.6.2:
|
||||
version "1.6.3"
|
||||
resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.3.tgz#80fee49665fd478bccf072c9d46bdf1bfed3558a"
|
||||
integrity sha512-bd+nzwhhs9ifsUrC2tWaSgm24/oo2c83zaRyZQF06hYA6sANfsXHtnZ19AbbbDXCDzeH5nZBSQ4NvCjgD62tJA==
|
Loading…
Reference in New Issue
Block a user