accessibility improvements

This commit is contained in:
rimu 2024-02-26 21:26:19 +13:00
parent 3780a74755
commit 684d4f741d
22 changed files with 82 additions and 57 deletions

View file

@ -512,7 +512,7 @@ def add_post(actor):
form.notify_author.data = True form.notify_author.data = True
return render_template('community/add_post.html', title=_('Add post to community'), form=form, community=community, return render_template('community/add_post.html', title=_('Add post to community'), form=form, community=community,
markdown_editor=True, low_bandwidth=request.cookies.get('low_bandwidth', '0') == '1', markdown_editor=current_user.markdown_editor, low_bandwidth=request.cookies.get('low_bandwidth', '0') == '1',
moderating_communities=moderating_communities(current_user.get_id()), moderating_communities=moderating_communities(current_user.get_id()),
joined_communities=joined_communities(current_user.id), joined_communities=joined_communities(current_user.id),
inoculation=inoculation[randint(0, len(inoculation) - 1)] inoculation=inoculation[randint(0, len(inoculation) - 1)]

View file

@ -465,6 +465,7 @@ class User(UserMixin, db.Model):
default_sort = db.Column(db.String(25), default='hot') default_sort = db.Column(db.String(25), default='hot')
theme = db.Column(db.String(20), default='') theme = db.Column(db.String(20), default='')
referrer = db.Column(db.String(256)) referrer = db.Column(db.String(256))
markdown_editor = db.Column(db.Boolean, default=False)
avatar = db.relationship('File', lazy='joined', foreign_keys=[avatar_id], single_parent=True, cascade="all, delete-orphan") avatar = db.relationship('File', lazy='joined', foreign_keys=[avatar_id], single_parent=True, cascade="all, delete-orphan")
cover = db.relationship('File', lazy='joined', foreign_keys=[cover_id], single_parent=True, cascade="all, delete-orphan") cover = db.relationship('File', lazy='joined', foreign_keys=[cover_id], single_parent=True, cascade="all, delete-orphan")

View file

@ -176,7 +176,7 @@ def show_post(post_id: int):
canonical=post.ap_id, form=form, replies=replies, THREAD_CUTOFF_DEPTH=constants.THREAD_CUTOFF_DEPTH, canonical=post.ap_id, form=form, replies=replies, THREAD_CUTOFF_DEPTH=constants.THREAD_CUTOFF_DEPTH,
description=description, og_image=og_image, POST_TYPE_IMAGE=constants.POST_TYPE_IMAGE, description=description, og_image=og_image, POST_TYPE_IMAGE=constants.POST_TYPE_IMAGE,
POST_TYPE_LINK=constants.POST_TYPE_LINK, POST_TYPE_ARTICLE=constants.POST_TYPE_ARTICLE, POST_TYPE_LINK=constants.POST_TYPE_LINK, POST_TYPE_ARTICLE=constants.POST_TYPE_ARTICLE,
etag=f"{post.id}{sort}_{hash(post.last_active)}", markdown_editor=True, etag=f"{post.id}{sort}_{hash(post.last_active)}", markdown_editor=current_user.markdown_editor,
low_bandwidth=request.cookies.get('low_bandwidth', '0') == '1', SUBSCRIPTION_MEMBER=SUBSCRIPTION_MEMBER, low_bandwidth=request.cookies.get('low_bandwidth', '0') == '1', SUBSCRIPTION_MEMBER=SUBSCRIPTION_MEMBER,
moderating_communities=moderating_communities(current_user.get_id()), moderating_communities=moderating_communities(current_user.get_id()),
joined_communities=joined_communities(current_user.get_id()), joined_communities=joined_communities(current_user.get_id()),
@ -368,7 +368,8 @@ def continue_discussion(post_id, comment_id):
replies = get_comment_branch(post.id, comment.id, 'top') replies = get_comment_branch(post.id, comment.id, 'top')
return render_template('post/continue_discussion.html', title=_('Discussing %(title)s', title=post.title), post=post, return render_template('post/continue_discussion.html', title=_('Discussing %(title)s', title=post.title), post=post,
is_moderator=is_moderator, comment=comment, replies=replies, markdown_editor=True, moderating_communities=moderating_communities(current_user.get_id()), is_moderator=is_moderator, comment=comment, replies=replies, markdown_editor=current_user.markdown_editor,
moderating_communities=moderating_communities(current_user.get_id()),
joined_communities=joined_communities(current_user.get_id()), community=post.community, joined_communities=joined_communities(current_user.get_id()), community=post.community,
inoculation=inoculation[randint(0, len(inoculation) - 1)]) inoculation=inoculation[randint(0, len(inoculation) - 1)])
@ -530,7 +531,7 @@ def add_reply(post_id: int, comment_id: int):
else: else:
form.notify_author.data = True form.notify_author.data = True
return render_template('post/add_reply.html', title=_('Discussing %(title)s', title=post.title), post=post, return render_template('post/add_reply.html', title=_('Discussing %(title)s', title=post.title), post=post,
is_moderator=is_moderator, form=form, comment=in_reply_to, markdown_editor=True, is_moderator=is_moderator, form=form, comment=in_reply_to, markdown_editor=current_user.markdown_editor,
moderating_communities=moderating_communities(current_user.get_id()), moderating_communities=moderating_communities(current_user.get_id()),
joined_communities = joined_communities(current_user.id), joined_communities = joined_communities(current_user.id),
inoculation=inoculation[randint(0, len(inoculation) - 1)]) inoculation=inoculation[randint(0, len(inoculation) - 1)])
@ -674,7 +675,7 @@ def post_edit(post_id: int):
form.nsfw.data = post.nsfw form.nsfw.data = post.nsfw
form.nsfl.data = post.nsfl form.nsfl.data = post.nsfl
return render_template('post/post_edit.html', title=_('Edit post'), form=form, post=post, return render_template('post/post_edit.html', title=_('Edit post'), form=form, post=post,
markdown_editor=True, markdown_editor=current_user.markdown_editor,
moderating_communities=moderating_communities(current_user.get_id()), moderating_communities=moderating_communities(current_user.get_id()),
joined_communities=joined_communities(current_user.get_id()), joined_communities=joined_communities(current_user.get_id()),
inoculation=inoculation[randint(0, len(inoculation) - 1)] inoculation=inoculation[randint(0, len(inoculation) - 1)]
@ -1009,7 +1010,7 @@ def post_reply_edit(post_id: int, comment_id: int):
form.body.data = post_reply.body form.body.data = post_reply.body
form.notify_author.data = post_reply.notify_author form.notify_author.data = post_reply.notify_author
return render_template('post/post_reply_edit.html', title=_('Edit comment'), form=form, post=post, post_reply=post_reply, return render_template('post/post_reply_edit.html', title=_('Edit comment'), form=form, post=post, post_reply=post_reply,
comment=comment, markdown_editor=True, moderating_communities=moderating_communities(current_user.get_id()), comment=comment, markdown_editor=current_user.markdown_editor, moderating_communities=moderating_communities(current_user.get_id()),
joined_communities=joined_communities(current_user.get_id()), joined_communities=joined_communities(current_user.get_id()),
inoculation=inoculation[randint(0, len(inoculation) - 1)]) inoculation=inoculation[randint(0, len(inoculation) - 1)])
else: else:

View file

@ -388,7 +388,7 @@ var showCurrentPost = false; // when true, the currently selected post will b
function setupKeyboardShortcuts() { function setupKeyboardShortcuts() {
document.addEventListener('keydown', function(event) { document.addEventListener('keydown', function(event) {
if (document.activeElement.tagName !== 'INPUT' && document.activeElement.tagName !== 'TEXTAREA') { if (document.activeElement.tagName !== 'INPUT' && document.activeElement.tagName !== 'TEXTAREA') {
if(document.activeElement.tagName !== 'A' && document.activeElement.classList.contains('skip-link')) { if(document.activeElement.classList.contains('skip-link')) {
return; return;
} }
var didSomething = false; var didSomething = false;

View file

@ -460,7 +460,7 @@ fieldset legend {
left: 0; left: 0;
background-color: #fff; background-color: #fff;
/* Background color to cover the link for screen readers */ /* Background color to cover the link for screen readers */
z-index: 1030; z-index: 1060;
/* Ensure it's above other content */ /* Ensure it's above other content */
} }
@ -1174,14 +1174,6 @@ fieldset legend {
padding-top: 0; padding-top: 0;
} }
.skip-link {
position: absolute;
top: -40px;
left: 0;
background-color: #fff;
z-index: 999;
}
.skip-link:focus { .skip-link:focus {
top: 0; top: 0;
} }

View file

@ -54,7 +54,7 @@ html {
top: -40px; /* Adjust as needed to hide the link off-screen */ top: -40px; /* Adjust as needed to hide the link off-screen */
left: 0; left: 0;
background-color: #fff; /* Background color to cover the link for screen readers */ background-color: #fff; /* Background color to cover the link for screen readers */
z-index: 1030; /* Ensure it's above other content */ z-index: 1060; /* Ensure it's above other content */
} }
.skip-link:focus { .skip-link:focus {
@ -853,13 +853,6 @@ fieldset {
padding-top: 0; padding-top: 0;
} }
.skip-link {
position: absolute;
top: -40px;
left: 0;
background-color: #fff;
z-index: 999;
}
.skip-link:focus { .skip-link:focus {
top: 0; top: 0;
} }

View file

@ -5,7 +5,7 @@
{% else %} {% else %}
{% if user.avatar_id and not low_bandwidth %} {% if user.avatar_id and not low_bandwidth %}
<a href="/u/{{ user.link() }}" title="{{ user.ap_id if user.ap_id != none else user.user_name }}"> <a href="/u/{{ user.link() }}" title="{{ user.ap_id if user.ap_id != none else user.user_name }}">
<img src="{{ user.avatar_thumbnail() }}" alt="Avatar" loading="lazy" /></a> <img src="{{ user.avatar_thumbnail() }}" alt="" loading="lazy" /></a>
{% endif %} {% endif %}
<a href="/u/{{ user.link() }}" title="{{ user.ap_id if user.ap_id != none else user.user_name }}">{{ user.display_name() }}</a> <a href="/u/{{ user.link() }}" title="{{ user.ap_id if user.ap_id != none else user.user_name }}">{{ user.display_name() }}</a>
{% if user.created_recently() %} {% if user.created_recently() %}
@ -179,7 +179,7 @@
{% endif %} {% endif %}
<li class="nav-item"><a class="nav-link" href="/auth/logout">{{ _('Log out') }}</a></li> <li class="nav-item"><a class="nav-link" href="/auth/logout">{{ _('Log out') }}</a></li>
<li class="nav-item d-none d-md-inline-block"> <li class="nav-item d-none d-md-inline-block">
<a class="nav-link" href="/notifications" aria-label="{{ _('Notifications') }}"> <a class="nav-link" href="/notifications" aria-label="{{ _('%(num)d unread notifications', num=current_user.unread_notifications) if current_user.unread_notifications else _('Notifications') }}">
{% if current_user.unread_notifications %} {% if current_user.unread_notifications %}
<span class="fe fe-bell red"></span> <span class="red">{{ current_user.unread_notifications }}</span> <span class="fe fe-bell red"></span> <span class="red">{{ current_user.unread_notifications }}</span>
{% else %} {% else %}
@ -211,7 +211,7 @@
{% block app_content %}{% endblock %} {% block app_content %}{% endblock %}
</div> </div>
<footer class="footer mt-auto" role="contentinfo"> <footer class="footer mt-auto" role="contentinfo">
<p id="timeSpent" class="text-center mt-4" title="This is how long you have spent using PieFed during this month. We hope this use of your time aligns with your priorities and values."></p> <p role="timer" id="timeSpent" class="text-center mt-4" title="This is how long you have spent using PieFed during this month. We hope this use of your time aligns with your priorities and values."></p>
{% if not low_bandwidth %} {% if not low_bandwidth %}
<p class="text-center mt-4"><a href="https://liberapay.com/PieFed/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a></p> <p class="text-center mt-4"><a href="https://liberapay.com/PieFed/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a></p>
{% else %} {% else %}

View file

@ -4,16 +4,16 @@
</div> </div>
{% endif %} {% endif %}
<div class="btn-group mt-1 mb-2"> <div class="btn-group mt-1 mb-2">
<a href="?sort=hot&layout={{ post_layout }}" class="btn {{ 'btn-primary' if sort == '' or sort == 'hot' else 'btn-outline-secondary' }}" rel="nofollow noindex"> <a href="?sort=hot&layout={{ post_layout }}" aria-label="{{ _('Sort by hot') }}" class="btn {{ 'btn-primary' if sort == '' or sort == 'hot' else 'btn-outline-secondary' }}" rel="nofollow noindex">
{{ _('Hot') }} {{ _('Hot') }}
</a> </a>
<a href="?sort=top&layout={{ post_layout }}" class="btn {{ 'btn-primary' if sort == 'top' else 'btn-outline-secondary' }}" rel="nofollow noindex"> <a href="?sort=top&layout={{ post_layout }}" aria-label="{{ _('Sort by top') }}" class="btn {{ 'btn-primary' if sort == 'top' else 'btn-outline-secondary' }}" rel="nofollow noindex">
{{ _('Top') }} {{ _('Top') }}
</a> </a>
<a href="?sort=new&layout={{ post_layout }}" class="btn {{ 'btn-primary' if sort == 'new' else 'btn-outline-secondary' }}" rel="nofollow noindex"> <a href="?sort=new&layout={{ post_layout }}" aria-label="{{ _('Sort by new') }}" class="btn {{ 'btn-primary' if sort == 'new' else 'btn-outline-secondary' }}" rel="nofollow noindex">
{{ _('New') }} {{ _('New') }}
</a> </a>
<a href="?sort=active&layout={{ post_layout }}" class="btn {{ 'btn-primary' if sort == 'active' else 'btn-outline-secondary' }}" rel="nofollow noindex"> <a href="?sort=active&layout={{ post_layout }}" aria-label="{{ _('Sort by active') }}" class="btn {{ 'btn-primary' if sort == 'active' else 'btn-outline-secondary' }}" rel="nofollow noindex">
{{ _('Active') }} {{ _('Active') }}
</a> </a>
</div> </div>

View file

@ -1,4 +1,5 @@
<a href="/community/{{ community.id }}/notification" rel="nofollow" <a href="/community/{{ community.id }}/notification" rel="nofollow" aria-live="assertive"
aria-label="{{ 'Notify about new posts in this community' if community.notify_new_posts(current_user.id) else 'Do not notify about new posts' }}"
class="fe {{ 'fe-bell' if community.notify_new_posts(current_user.id) else 'fe-no-bell' }} no-underline" class="fe {{ 'fe-bell' if community.notify_new_posts(current_user.id) else 'fe-no-bell' }} no-underline"
hx-post="/community/{{ community.id }}/notification" hx-trigger="click throttle:1s" hx-swap="outerHTML" hx-post="/community/{{ community.id }}/notification" hx-trigger="click throttle:1s" hx-swap="outerHTML"
title="{{ _('Notify about every new post. Not advisable in high traffic communities!') }}"></a> title="{{ _('Notify about every new post. Not advisable in high traffic communities!') }}"></a>

View file

@ -22,7 +22,7 @@
</nav> </nav>
</div> </div>
<img class="community_icon_big bump_up rounded-circle" src="{{ community.icon_image() }}" alt="Community icon" /> <img class="community_icon_big bump_up rounded-circle" src="{{ community.icon_image() }}" alt="Community icon" />
<h1 class="mt-2">{{ community.title }} <h1 class="mt-2" aria-live="assertive">{{ community.title }}
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
{% include 'community/_notification_toggle.html' %} {% include 'community/_notification_toggle.html' %}
{% endif %} {% endif %}

View file

@ -10,13 +10,13 @@
<div class="row g-2 justify-content-between mt-2"> <div class="row g-2 justify-content-between mt-2">
<div class="col-auto"> <div class="col-auto">
<div class="btn-group"> <div class="btn-group">
<a href="/communities" class="btn {{ 'btn-primary' if request.path == '/communities' else 'btn-outline-secondary' }}"> <a href="/communities" aria-label="{{ _('All communities') }}" class="btn {{ 'btn-primary' if request.path == '/communities' else 'btn-outline-secondary' }}">
{{ _('All') }} {{ _('All') }}
</a> </a>
<a href="/communities/local" class="btn {{ 'btn-primary' if request.path == '/communities/local' else 'btn-outline-secondary' }}"> <a href="/communities/local" aria-label="{{ _('Communities on this server') }}" class="btn {{ 'btn-primary' if request.path == '/communities/local' else 'btn-outline-secondary' }}">
{{ _('Local') }} {{ _('Local') }}
</a> </a>
<a href="/communities/subscribed" class="btn {{ 'btn-primary' if request.path == '/communities/subscribed' else 'btn-outline-secondary' }}"> <a href="/communities/subscribed" aria-label="{{ _('Joined communities') }}" class="btn {{ 'btn-primary' if request.path == '/communities/subscribed' else 'btn-outline-secondary' }}">
{{ _('Joined') }} {{ _('Joined') }}
</a> </a>
@ -37,8 +37,8 @@
</div> </div>
<div class="col-auto"> <div class="col-auto">
<div class="btn-group"> <div class="btn-group">
<a href="{{ url_for('community.add_local') }}" class="btn btn-outline-secondary">{{ _('Create local') }}</a> <a href="{{ url_for('community.add_local') }}" class="btn btn-outline-secondary" aria-label="{{ _('Create local community') }}">{{ _('Create local') }}</a>
<a href="{{ url_for('community.add_remote') }}" class="btn btn-outline-secondary">{{ _('Add remote') }}</a> <a href="{{ url_for('community.add_remote') }}" class="btn btn-outline-secondary" aria-label="{{ _('Add community from another instance') }}">{{ _('Add remote') }}</a>
</div> </div>
<!-- <form method="get" action="/communities"> <!-- <form method="get" action="/communities">
<input name='search' type="search" placeholder="Find a community" class="form-control" value="{{ search }}" /> <input name='search' type="search" placeholder="Find a community" class="form-control" value="{{ search }}" />
@ -79,21 +79,21 @@
<tr class=""> <tr class="">
<td width="70">{% if current_user.is_authenticated %} <td width="70">{% if current_user.is_authenticated %}
{% if community_membership(current_user, community) in [SUBSCRIPTION_MEMBER, SUBSCRIPTION_MODERATOR, SUBSCRIPTION_OWNER] %} {% if community_membership(current_user, community) in [SUBSCRIPTION_MEMBER, SUBSCRIPTION_MODERATOR, SUBSCRIPTION_OWNER] %}
<a class="btn btn-primary btn-sm" href="/community/{{ community.link() }}/unsubscribe" rel="nofollow">{{ _('Leave') }}</a> <a class="btn btn-primary btn-sm" href="/community/{{ community.link() }}/unsubscribe" rel="nofollow" aria-label="{{ _('Leave %(name)s', name=community.display_name()) }}">{{ _('Leave') }}</a>
{% elif community_membership(current_user, community) == SUBSCRIPTION_PENDING %} {% elif community_membership(current_user, community) == SUBSCRIPTION_PENDING %}
<a class="btn btn-outline-secondary btn-sm" href="/community/{{ community.link() }}/unsubscribe" rel="nofollow">{{ _('Pending') }}</a> <a class="btn btn-outline-secondary btn-sm" href="/community/{{ community.link() }}/unsubscribe" rel="nofollow">{{ _('Pending') }}</a>
{% else %} {% else %}
<a class="btn btn-primary btn-sm" href="/community/{{ community.link() }}/subscribe" rel="nofollow">{{ _('Join') }}</a> <a class="btn btn-primary btn-sm" href="/community/{{ community.link() }}/subscribe" rel="nofollow" aria-label="{{ _('Join %(name)s', name=community.display_name()) }}">{{ _('Join') }}</a>
{% endif %} {% endif %}
{% else %} {% else %}
<a class="btn btn-primary btn-sm" href="/community/{{ community.link() }}/subscribe" rel="nofollow">{{ _('Join') }}</a> <a class="btn btn-primary btn-sm" href="/community/{{ community.link() }}/subscribe" rel="nofollow" aria-label="{{ _('Join %(name)s', name=community.display_name()) }}">{{ _('Join') }}</a>
{% endif %}</td> {% endif %}</td>
{% if not low_bandwidth %} {% if not low_bandwidth %}
<td width="46"> <td width="46">
<a href="/c/{{ community.link() }}"><img src="{{ community.icon_image('tiny') }}" class="community_icon rounded-circle" loading="lazy" alt="" /></a> <a href="/c/{{ community.link() }}"><img src="{{ community.icon_image('tiny') }}" class="community_icon rounded-circle" loading="lazy" alt="" /></a>
</td> </td>
{% endif %} {% endif %}
<th scope="row" class="pl-0"><a href="/c/{{ community.link() }}">{{ community.display_name() }}</a></th> <th scope="row" class="pl-0"><a href="/c/{{ community.link() }}" aria-label="{{ _('Browse %(name)s', name=community.display_name()) }}">{{ community.display_name() }}</a></th>
<td>{{ community.post_count }}</td> <td>{{ community.post_count }}</td>
<td>{{ community.post_reply_count }}</td> <td>{{ community.post_reply_count }}</td>
<td>{{ moment(community.last_active).fromNow(refresh=True) }}</td> <td>{{ moment(community.last_active).fromNow(refresh=True) }}</td>

View file

@ -1,14 +1,14 @@
{% if current_user.is_authenticated and current_user.verified %} {% if current_user.is_authenticated and current_user.verified %}
{% if can_upvote(current_user, community) %} {% if can_upvote(current_user, community) %}
<div class="upvote_button {{ upvoted_class }}" role="button" aria-label="{{ _('UpVote') }}" aria-live="assertive" <div class="upvote_button {{ upvoted_class }}" role="button" aria-label="{{ _('UpVote button.') }}" aria-live="assertive"
hx-post="/comment/{{ comment.id }}/upvote" hx-trigger="click throttle:1s" hx-target="closest .voting_buttons_new" tabindex="0"> hx-post="/comment/{{ comment.id }}/upvote" hx-trigger="click throttle:1s" hx-target="closest .voting_buttons_new" tabindex="0">
<span class="fe fe-arrow-up"></span> <span class="fe fe-arrow-up"></span>
<img class="htmx-indicator" src="/static/images/spinner.svg" alt="" style="opacity: 0;"> <img class="htmx-indicator" src="/static/images/spinner.svg" alt="" style="opacity: 0;">
</div> </div>
{% endif %} {% endif %}
<span title="{{ comment.up_votes }}, {{ comment.down_votes }}" aria-live="assertive">{{ comment.up_votes - comment.down_votes }}</span> <span title="{{ comment.up_votes }}, {{ comment.down_votes }}" aria-live="assertive" aria-label="{{ _('Score: ') }}{{ comment.up_votes - comment.down_votes }}.">{{ comment.up_votes - comment.down_votes }}</span>
{% if can_downvote(current_user, community) %} {% if can_downvote(current_user, community) %}
<div class="downvote_button {{ downvoted_class }}" role="button" aria-label="{{ _('DownVote') }}" aria-live="assertive" <div class="downvote_button {{ downvoted_class }}" role="button" aria-label="{{ _('DownVote button.') }}" aria-live="assertive"
hx-post="/comment/{{ comment.id }}/downvote" hx-trigger="click throttle:1s" hx-target="closest .voting_buttons_new" tabindex="0"> hx-post="/comment/{{ comment.id }}/downvote" hx-trigger="click throttle:1s" hx-target="closest .voting_buttons_new" tabindex="0">
<span class="fe fe-arrow-down"></span> <span class="fe fe-arrow-down"></span>
<img class="htmx-indicator" src="/static/images/spinner.svg" alt="" style="opacity: 0;"> <img class="htmx-indicator" src="/static/images/spinner.svg" alt="" style="opacity: 0;">
@ -18,7 +18,7 @@
<div class="upvote_button digits_{{ digits(comment.up_votes) }} {{ upvoted_class }} redirect_login"> <div class="upvote_button digits_{{ digits(comment.up_votes) }} {{ upvoted_class }} redirect_login">
<span class="fe fe-arrow-up"></span> <span class="fe fe-arrow-up"></span>
</div> </div>
{{ comment.up_votes - comment.down_votes }} <span title="{{ comment.up_votes }}, {{ comment.down_votes }}" aria-live="assertive" aria-label="{{ _('Score:') }}">{{ comment.up_votes - comment.down_votes }}</span>
<div class="downvote_button digits_{{ digits(comment.down_votes) }} {{ downvoted_class }} redirect_login"> <div class="downvote_button digits_{{ digits(comment.down_votes) }} {{ downvoted_class }} redirect_login">
<span class="fe fe-arrow-down"></span> <span class="fe fe-arrow-down"></span>
</div> </div>

View file

@ -12,7 +12,7 @@
<li class="breadcrumb-item active">{{ post.title|shorten(15) }}</li> <li class="breadcrumb-item active">{{ post.title|shorten(15) }}</li>
</ol> </ol>
</nav> </nav>
<div class="voting_buttons"> <div class="voting_buttons" aria-live="assertive">
{% include "post/_post_voting_buttons.html" %} {% include "post/_post_voting_buttons.html" %}
</div> </div>
<h1 class="mt-2 post_title">{{ post.title }} <h1 class="mt-2 post_title">{{ post.title }}
@ -61,7 +61,7 @@
<li class="breadcrumb-item active">{{ post.title|shorten(15) }}</li> <li class="breadcrumb-item active">{{ post.title|shorten(15) }}</li>
</ol> </ol>
</nav> </nav>
<div class="voting_buttons"> <div class="voting_buttons" aria-live="assertive">
{% include "post/_post_voting_buttons.html" %} {% include "post/_post_voting_buttons.html" %}
</div> </div>
<h1 class="mt-2 post_title">{{ post.title }} <h1 class="mt-2 post_title">{{ post.title }}

View file

@ -3,7 +3,7 @@
{# do nothing - blocked by keyword filter #} {# do nothing - blocked by keyword filter #}
{% else %} {% else %}
<div class="post_teaser type_{{ post.type }}{{ ' reported' if post.reports and current_user.is_authenticated and post.community.is_moderator() }}{{ ' blocked' if content_blocked }}" <div class="post_teaser type_{{ post.type }}{{ ' reported' if post.reports and current_user.is_authenticated and post.community.is_moderator() }}{{ ' blocked' if content_blocked }}"
{% if content_blocked %} title="{{ _('Filtered: ') }}{{ content_blocked }}"{% endif %}> {% if content_blocked %} title="{{ _('Filtered: ') }}{{ content_blocked }}"{% endif %} tabindex="0">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="row main_row"> <div class="row main_row">
@ -62,7 +62,7 @@
</div> </div>
<div class="row utilities_row"> <div class="row utilities_row">
<div class="col-6"> <div class="col-6">
<a href="{{ url_for('activitypub.post_ap', post_id=post.id, sort='new' if sort == 'active' else None, _anchor='post_replies') }}" aria-label="{{ _('View comments') }}"><span class="fe fe-reply"></span> {{ post.reply_count }}</a> <a href="{{ url_for('activitypub.post_ap', post_id=post.id, sort='new' if sort == 'active' else None, _anchor='post_replies') }}" aria-label="{{ _('View comments') }}"><span class="fe fe-reply"></span> <span aria-label="{{ _('Number of comments:') }}">{{ post.reply_count }}</span></a>
{% if post.type == POST_TYPE_IMAGE %} {% if post.type == POST_TYPE_IMAGE %}
{% if post.image_id %} {% if post.image_id %}
<a href="{{ post.image.view_url() }}" rel="nofollow ugc" class="preview_image" aria-label="{{ _('View image') }}" aria-hidden="true"><span class="fe fe-magnify"></span></a> <a href="{{ post.image.view_url() }}" rel="nofollow ugc" class="preview_image" aria-label="{{ _('View image') }}" aria-hidden="true"><span class="fe fe-magnify"></span></a>

View file

@ -1,6 +1,6 @@
{% if current_user.is_authenticated and current_user.verified %} {% if current_user.is_authenticated and current_user.verified %}
{% if can_upvote(current_user, post.community) %} {% if can_upvote(current_user, post.community) %}
<div class="upvote_button {{ upvoted_class }}" role="button" aria-label="{{ _('UpVote') }}" aria-live="assertive" <div class="upvote_button {{ upvoted_class }}" role="button" aria-label="{{ _('UpVote button, %(count)d so far.', count=post.up_votes) }}" aria-live="assertive"
hx-post="/post/{{ post.id }}/upvote" hx-trigger="click throttle:1s" hx-target="closest .voting_buttons" tabindex="0"> hx-post="/post/{{ post.id }}/upvote" hx-trigger="click throttle:1s" hx-target="closest .voting_buttons" tabindex="0">
<span class="fe fe-arrow-up"></span> <span class="fe fe-arrow-up"></span>
{{ shorten_number(post.up_votes) }} {{ shorten_number(post.up_votes) }}
@ -8,7 +8,7 @@
</div> </div>
{% endif %} {% endif %}
{% if can_downvote(current_user, post.community) %} {% if can_downvote(current_user, post.community) %}
<div class="downvote_button {{ downvoted_class }}" role="button" aria-label="{{ _('DownVote') }}" aria-live="assertive" <div class="downvote_button {{ downvoted_class }}" role="button" aria-label="{{ _('DownVote button, %(count)d so far.', count=post.down_votes) }}" aria-live="assertive"
hx-post="/post/{{ post.id }}/downvote" hx-trigger="click throttle:1s" hx-target="closest .voting_buttons" tabindex="0"> hx-post="/post/{{ post.id }}/downvote" hx-trigger="click throttle:1s" hx-target="closest .voting_buttons" tabindex="0">
<span class="fe fe-arrow-down"></span> <span class="fe fe-arrow-down"></span>
{{ shorten_number(post.down_votes) }} {{ shorten_number(post.down_votes) }}

View file

@ -11,7 +11,7 @@
<div class="col-12 col-md-8 position-relative add_reply main_pane"> <div class="col-12 col-md-8 position-relative add_reply main_pane">
<fieldset class="coolfieldset mt-4"><legend class="w-auto">Original post</legend> <fieldset class="coolfieldset mt-4"><legend class="w-auto">Original post</legend>
<h3>{{ post.title }}</h3> <h3>{{ post.title }}</h3>
{{ post.body_html | safe }} {{ post.body_html | safe if post.body_html else '' }}
</fieldset> </fieldset>
<fieldset class="coolfieldset mt-4"><legend class="w-auto">Comment you are replying to</legend> <fieldset class="coolfieldset mt-4"><legend class="w-auto">Comment you are replying to</legend>
{{ comment.body_html | safe}} {{ comment.body_html | safe}}

View file

@ -20,7 +20,7 @@
<div class="col"> <div class="col">
<div class="reply_form_inner position-relative"> <div class="reply_form_inner position-relative">
{% if post.community.ap_id and '@beehaw.org' in post.community.ap_id %} {% if post.community.ap_id and '@beehaw.org' in post.community.ap_id %}
<p>{{ _('This post is hosted on beehaw.org which has <a href="https://docs.beehaw.org/docs/core-principles/what-is-beehaw/" target="_blank" rel="nofollow">higher standards of behaviour than most places. Be nice</a>.') }}</p> <p>{{ _('This post is hosted on beehaw.org which has <a href="https://docs.beehaw.org/docs/core-principles/what-is-beehaw/" target="_blank" rel="nofollow">high er standards of behaviour than most places. Be nice</a>.') }}</p>
{% endif %} {% endif %}
{{ render_form(form) }} {{ render_form(form) }}
{% if markdown_editor %} {% if markdown_editor %}
@ -51,6 +51,7 @@
<p>{{ _('Comments are disabled.') }}</p> <p>{{ _('Comments are disabled.') }}</p>
{% endif %} {% endif %}
{% if replies %} {% if replies %}
<h2 class="visually-hidden">{{ len(replies) }} {{ _('Comments') }}</h2>
<div id="post_replies" class="row"> <div id="post_replies" class="row">
<div class="col"> <div class="col">
<div class="btn-group mt-1 mb-2"> <div class="btn-group mt-1 mb-2">
@ -66,7 +67,7 @@
</div> </div>
{% macro render_comment(comment) %} {% macro render_comment(comment) %}
<div id="comment_{{ comment['comment'].id }}" class="comment {% if comment['comment'].score <= -10 %}low_score{% endif %} <div id="comment_{{ comment['comment'].id }}" class="comment {% if comment['comment'].score <= -10 %}low_score{% endif %}
{% if comment['comment'].author.id == post.author.id %}original_poster{% endif %}" aria-level="{{ comment['comment'].depth + 1 }}" role="treeitem"> {% if comment['comment'].author.id == post.author.id %}original_poster{% endif %}" aria-level="{{ comment['comment'].depth + 1 }}" role="treeitem" aria-expanded="true" tabindex="0">
<div class="limit_height"> <div class="limit_height">
<div class="comment_author"> <div class="comment_author">
{% if comment['comment'].author.deleted %} {% if comment['comment'].author.deleted %}
@ -120,7 +121,7 @@
{% if current_user.is_authenticated and current_user.verified and current_user.id == comment['comment'].author.id %} {% if current_user.is_authenticated and current_user.verified and current_user.id == comment['comment'].author.id %}
{% include "post/_reply_notification_toggle.html" %} {% include "post/_reply_notification_toggle.html" %}
{% endif %} {% endif %}
<a href="{{ url_for('post.post_reply_options', post_id=post.id, comment_id=comment['comment'].id) }}" class="comment_actions_link" rel="nofollow noindex"><span class="fe fe-options" title="Options"> </span></a> <a href="{{ url_for('post.post_reply_options', post_id=post.id, comment_id=comment['comment'].id) }}" class="comment_actions_link" rel="nofollow noindex" aria-label="{{ _('Comment options') }}"><span class="fe fe-options" title="Options"> </span></a>
</div> </div>
{% if comment['replies'] %} {% if comment['replies'] %}
{% if comment['comment'].depth <= THREAD_CUTOFF_DEPTH %} {% if comment['comment'].depth <= THREAD_CUTOFF_DEPTH %}

View file

@ -24,6 +24,7 @@
{{ render_field(form.ignore_bots) }} {{ render_field(form.ignore_bots) }}
{{ render_field(form.nsfw) }} {{ render_field(form.nsfw) }}
{{ render_field(form.nsfl) }} {{ render_field(form.nsfl) }}
{{ render_field(form.markdown_editor) }}
{{ render_field(form.searchable) }} {{ render_field(form.searchable) }}
{{ render_field(form.indexable) }} {{ render_field(form.indexable) }}
{{ render_field(form.default_sort) }} {{ render_field(form.default_sort) }}

View file

@ -22,7 +22,7 @@
<tr> <tr>
<th>Notification</th> <th>Notification</th>
<th>When</th> <th>When</th>
<th><a href="{{ url_for('user.notifications_all_read') }}" class="btn btn-primary btn-sm">Mark all read</a></th> <th><a href="{{ url_for('user.notifications_all_read') }}" class="btn btn-primary btn-sm">{{ _('Mark all as read') }}</a></th>
</tr> </tr>
{% for notification in notifications %} {% for notification in notifications %}
<tr> <tr>

View file

@ -36,6 +36,7 @@ class SettingsForm(FlaskForm):
ignore_bots = BooleanField(_l('Hide posts by bots')) ignore_bots = BooleanField(_l('Hide posts by bots'))
nsfw = BooleanField(_l('Show NSFW posts')) nsfw = BooleanField(_l('Show NSFW posts'))
nsfl = BooleanField(_l('Show NSFL posts')) nsfl = BooleanField(_l('Show NSFL posts'))
markdown_editor = BooleanField(_l('Use markdown editor GUI when writing'))
searchable = BooleanField(_l('Show profile in user list')) searchable = BooleanField(_l('Show profile in user list'))
indexable = BooleanField(_l('Allow search engines to index this profile')) indexable = BooleanField(_l('Allow search engines to index this profile'))
manually_approves_followers = BooleanField(_l('Manually approve followers')) manually_approves_followers = BooleanField(_l('Manually approve followers'))

View file

@ -163,6 +163,7 @@ def change_settings():
current_user.default_sort = form.default_sort.data current_user.default_sort = form.default_sort.data
current_user.theme = form.theme.data current_user.theme = form.theme.data
current_user.email_unread = form.email_unread.data current_user.email_unread = form.email_unread.data
current_user.markdown_editor = form.markdown_editor.data
import_file = request.files['import_file'] import_file = request.files['import_file']
if import_file and import_file.filename != '': if import_file and import_file.filename != '':
file_ext = os.path.splitext(import_file.filename)[1] file_ext = os.path.splitext(import_file.filename)[1]
@ -195,6 +196,7 @@ def change_settings():
form.indexable.data = current_user.indexable form.indexable.data = current_user.indexable
form.default_sort.data = current_user.default_sort form.default_sort.data = current_user.default_sort
form.theme.data = current_user.theme form.theme.data = current_user.theme
form.markdown_editor.data = current_user.markdown_editor
return render_template('user/edit_settings.html', title=_('Edit profile'), form=form, user=current_user, return render_template('user/edit_settings.html', title=_('Edit profile'), form=form, user=current_user,
moderating_communities=moderating_communities(current_user.get_id()), moderating_communities=moderating_communities(current_user.get_id()),

View file

@ -0,0 +1,32 @@
"""markdown editor optional
Revision ID: 2629cf0e2965
Revises: 1505d32771b7
Create Date: 2024-02-26 21:19:16.108520
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '2629cf0e2965'
down_revision = '1505d32771b7'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.add_column(sa.Column('markdown_editor', sa.Boolean(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.drop_column('markdown_editor')
# ### end Alembic commands ###