add infobox support
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
from flask import Blueprint, abort, redirect, url_for, request, render_template
|
||||
from flask import Blueprint, abort, redirect, url_for, request, render_template, flash
|
||||
from ..constants import InfoboxKind
|
||||
from ..auth import is_logged_in, get_active_user, csrf_verified
|
||||
from ..models import Topics, Threads
|
||||
from slugify import slugify
|
||||
bp = Blueprint('mod', __name__, url_prefix='/mod/')
|
||||
|
||||
@bp.before_request
|
||||
@@ -39,9 +41,21 @@ def edit_topic_post(topic_id):
|
||||
topic = Topics.find({'id': topic_id})
|
||||
if not topic:
|
||||
abort(404)
|
||||
|
||||
target_name = request.form.get('name').strip()
|
||||
|
||||
name_exists = Topics.count([
|
||||
('lower(name)', '=', target_name.lower()),
|
||||
('id', '!=', topic.id)
|
||||
]) > 0
|
||||
if name_exists:
|
||||
flash(f'A topic named "{target_name}" already exists.', InfoboxKind.ERROR)
|
||||
return redirect(url_for('.edit_topic', topic_id=topic_id))
|
||||
|
||||
topic.update({
|
||||
'name': request.form.get('name').strip(),
|
||||
'name': target_name,
|
||||
'description': request.form.get('description').strip(),
|
||||
'slug': slugify(target_name[:50]),
|
||||
})
|
||||
return redirect(url_for('topics.topic_by_id', topic_id=topic.id))
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{%- from 'common/macros.html' import infobox with context -%}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -13,6 +14,13 @@
|
||||
</head>
|
||||
<body>
|
||||
{%- include 'common/topnav.html' -%}
|
||||
{%- with messages = get_flashed_messages(with_categories=true) -%}
|
||||
{%- if messages -%}
|
||||
{%- for category, message in messages -%}
|
||||
{{- infobox(message, category) -}}
|
||||
{%- endfor -%}
|
||||
{%- endif -%}
|
||||
{%- endwith -%}
|
||||
{%- block content -%}{%- endblock -%}
|
||||
{%- include 'common/footer.html' -%}
|
||||
</body>
|
||||
|
||||
11
app/templates/common/icons.html
Normal file
11
app/templates/common/icons.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{%- macro icn_info(width=48) -%}
|
||||
<svg height="{{width}}" viewBox="0 0 32 32" width="{{width}}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><filter id="if1" color-interpolation-filters="sRGB" height="1.09976" width="1" x="0" y="0"><feFlood flood-opacity=".14902" in="SourceGraphic" result="flood"/><feGaussianBlur in="SourceGraphic" result="blur" stdDeviation="0"/><feOffset dx="0" dy="1.5" in="blur" result="offset"/><feComposite in="flood" in2="offset" operator="in" result="comp1"/><feComposite in="SourceGraphic" in2="comp1" operator="over" result="comp2"/></filter><linearGradient id="ilg1" gradientTransform="matrix(.921875 0 0 .9225 1.249998 1.239999)" gradientUnits="userSpaceOnUse" x1="16" x2="16" y1="0" y2="32"><stop offset=".15427744" stop-color="#4b8be1" stop-opacity=".992157"/><stop offset="1" stop-color="#1078e8" stop-opacity=".992157"/></linearGradient><linearGradient id="ilg2" gradientUnits="userSpaceOnUse" x1="15.99999832" x2="15.99999832" y1=".126983" y2="31.87301564"><stop offset="0" stop-color="#a9cef8"/><stop offset=".73127526" stop-color="#4f99e7"/></linearGradient><g><circle cx="16" cy="16" fill="#0e3459" fill-opacity=".500866" r="16"/><circle cx="16" cy="16" fill="url(#ilg2)" r="15.625" stroke="#4d677d" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25"/><ellipse cx="16" cy="16" fill="url(#ilg1)" rx="14.75" ry="14.76"/><g fill="#fff" stroke-linecap="round" stroke-linejoin="round"><path d="m29.494141 10.042735a14.75 14.76 0 0 0 -13.494141-8.8027352 14.75 14.76 0 0 0 -13.49414 8.8027352c2.987994-2.3171382 8.240661-4.0429692 13.49414-4.0429692s10.506146 1.725831 13.494141 4.0429692z" fill-opacity=".216645"/><path d="m15.716477 10.189534q-.789603 0-1.344793-.5428521-.542852-.5551897-.542852-1.3447928 0-.7772656.542852-1.3201177.55519-.5551897 1.344793-.5551897.777266 0 1.320118.5551897.55519.5428521.55519 1.3201177 0 .7896031-.55519 1.3447928-.542852.5428521-1.320118.5428521zm1.529856 14.780383h-2.282446v-11.091456h-1.233755v-1.86297h3.516201z" filter="url(#if1)" stroke-width=".25"/></g></g></svg>
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro icn_warn(width=48) -%}
|
||||
<svg height="{{width}}" viewBox="0 0 32 32" width="{{width}}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><filter id="wf1" color-interpolation-filters="sRGB" height="1.09976" width="1" x="0" y="0"><feFlood flood-opacity=".14902" in="SourceGraphic" result="flood"/><feGaussianBlur in="SourceGraphic" result="blur" stdDeviation="0"/><feOffset dx="0" dy="1.5" in="blur" result="offset"/><feComposite in="flood" in2="offset" operator="in" result="comp1"/><feComposite in="SourceGraphic" in2="comp1" operator="over" result="comp2"/></filter><linearGradient id="wlg1" gradientTransform="matrix(1.01415 0 0 .99686492 -.226398 -.52981)" gradientUnits="userSpaceOnUse" x1="16" x2="15.999999" y1="1.302475" y2="30.000002"><stop offset="0" stop-color="#f4f4ed"/><stop offset=".72657222" stop-color="#ddcf76"/></linearGradient><linearGradient id="wlg2" gradientUnits="userSpaceOnUse" x1="16" x2="16" y1="2.369791" y2="29.630209"><stop offset=".25" stop-color="#edd86d"/><stop offset="1" stop-color="#d5901a"/></linearGradient><g><path d="m14.960961 2.718822-14.675898 25.36219a1.2153386 1.2001658 0 0 0 1.055209 1.795616h29.319455a1.2153386 1.2001658 0 0 0 1.05521-1.795616l-14.6759-25.36219a1.1967125 1.1817724 0 0 0 -2.078076 0z" fill="#443c09" fill-opacity=".500632"/><path d="m14.99368 3.1949619-14.21375986 24.4501341a1.1770681 1.1570063 0 0 0 1.02198136 1.731044h28.3961965a1.1770681 1.1570063 0 0 0 1.021982-1.731044l-14.213761-24.4501341a1.1590285 1.1392744 0 0 0 -2.012639 0z" fill="url(#wlg1)" stroke="#6b5b07" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25"/><path d="m15.11254 4.0052032-12.6044459 22.9058128c-.3954388.72251.1042399 1.621487.901271 1.621487l25.1812709-.0031c.79703-.000097 1.296709-.898977.90127-1.621487l-12.604448-22.9027128c-.39239-.7169421-1.382527-.7169421-1.774918 0z" fill="url(#wlg2)"/><g stroke-linecap="round" stroke-linejoin="round"><path d="m11.150645 10.205078c1.849355-1.205078 3.775283-1.205078 4.848141-1.205078 1.072971 0 3.001214 0 4.851104 1.205078l-3.962432-6.1998748c-.39239-.716943-1.383-.716943-1.775391 0z" fill="#fff" fill-opacity=".397479"/><path d="m16.00535 25.361656q-.620708 0-1.059484-.428074-.428074-.438776-.428074-1.059484 0-.610006.428074-1.03808.438776-.438776 1.059484-.438776.610005 0 1.03808.438776.438776.428074.438776 1.03808 0 .620708-.438776 1.059484-.428075.428074-1.03808.428074zm.791937-4.494779h-1.551769l-.310354-10.541328h2.129669z" fill="#443c09" filter="url(#wf1)" stroke-width=".220327" transform="matrix(1.1346739 0 0 1.1346739 -2.154783 -2.497989)"/></g></g></svg>
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro icn_error(width=48) -%}
|
||||
<svg height="{{width}}" viewBox="0 0 32 32" width="{{width}}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="elg1" gradientTransform="matrix(.921875 0 0 .9225 1.249998 1.239999)" gradientUnits="userSpaceOnUse" x1="16" x2="16" y1="0" y2="32"><stop offset=".15427744" stop-color="#de4747"/><stop offset="1" stop-color="#b52222"/></linearGradient><linearGradient id="elg2" gradientUnits="userSpaceOnUse" x1="15.99999832" x2="15.99999832" y1=".126983" y2="31.87301564"><stop offset="0" stop-color="#f09797"/><stop offset=".73127526" stop-color="#d24141"/></linearGradient><filter id="ef1" color-interpolation-filters="sRGB" height="1.09976" width="1" x="0" y="0"><feFlood flood-opacity=".14902" in="SourceGraphic" result="flood"/><feGaussianBlur in="SourceGraphic" result="blur" stdDeviation="0"/><feOffset dx="0" dy="1.5" in="blur" result="offset"/><feComposite in="flood" in2="offset" operator="in" result="comp1"/><feComposite in="SourceGraphic" in2="comp1" operator="over" result="comp2"/></filter><g><circle cx="16" cy="16" fill="#590e0e" fill-opacity=".500866" r="16"/><circle cx="16" cy="16" fill="url(#elg2)" r="15.625" stroke="#7d4d4d" stroke-linecap="round" stroke-linejoin="round" stroke-width=".25"/><ellipse cx="16" cy="16" fill="url(#elg1)" rx="14.75" ry="14.76"/><g fill="#fff"><path d="m8 10 2-2 6 6 6-6 2 2-6 6 6 6-2 2-6-6-6 6-2-2 6-6z" filter="url(#ef1)"/><path d="m29.494141 10.042735a14.75 14.76 0 0 0 -13.494141-8.8027352 14.75 14.76 0 0 0 -13.49414 8.8027352c2.987994-2.3171382 8.240661-4.0429692 13.49414-4.0429692s10.506146 1.725831 13.494141 4.0429692z" fill-opacity=".216645" stroke-linecap="round" stroke-linejoin="round"/></g></g></svg>
|
||||
{%- endmacro -%}
|
||||
@@ -1,3 +1,5 @@
|
||||
{%- from 'common/icons.html' import icn_info, icn_warn, icn_error -%}
|
||||
|
||||
{% macro timestamp(unix_ts) -%}
|
||||
<span class="timestamp" data-utc="{{ unix_ts }}">{{ unix_ts | ts_datetime('%Y-%m-%d %H:%M')}} <abbr title="Server Time">ST</abbr></span>
|
||||
{%- endmacro %}
|
||||
@@ -180,3 +182,20 @@
|
||||
{%- endif -%}
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro infobox(message, kind=InfoboxKind.INFO) -%}
|
||||
<div class="infobox plank top contain-svg horizontal {{InfoboxHTMLClass[kind]}}">
|
||||
{%- if kind == InfoboxKind.INFO -%}
|
||||
{{- icn_info() -}}
|
||||
{%- elif kind == InfoboxKind.WARN -%}
|
||||
{{- icn_warn() -}}
|
||||
{%- elif kind == InfoboxKind.ERROR -%}
|
||||
{{- icn_error() -}}
|
||||
{%- endif -%}
|
||||
{%- set m = message.split(';', maxsplit=1) -%}
|
||||
<strong>{{m[0]}}</strong>
|
||||
{%- if m[1] -%}
|
||||
{{m[1]}}
|
||||
{%- endif -%}
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<legend>Actions</legend>
|
||||
{%- if is_logged_in() -%}
|
||||
{%- if thread.user_id == get_active_user().id -%}
|
||||
<a class="linkbutton" href="{{url_for('threads.edit', thread_id=thread.id)}}">Edit…</a>
|
||||
<a class="linkbutton" href="{{url_for('threads.edit', thread_id=thread.id)}}">Edit</a>
|
||||
{%- endif -%}
|
||||
<button>Subscribe</button>
|
||||
<button disabled title="This feature requires JavaScript to be enabled.">Bookmark…</button>
|
||||
@@ -32,7 +32,7 @@
|
||||
<fieldset class="plank even no-shadow minimal thread-actions">
|
||||
<legend>Moderation actions</legend>
|
||||
{%- if thread.user_id != get_active_user().id -%}
|
||||
<a class="linkbutton warn" href="{{url_for('threads.edit', thread_id=thread.id)}}">Edit…</a>
|
||||
<a class="linkbutton warn" href="{{url_for('threads.edit', thread_id=thread.id)}}">Edit</a>
|
||||
{%- endif -%}
|
||||
<form method="POST">
|
||||
<input type="hidden" name="lock" value="{{(not thread.locked()) | int}}">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{% from 'common/macros.html' import timestamp, subheader %}
|
||||
{% from 'common/icons.html' import icn_info, icn_warn, icn_error %}
|
||||
{%- extends 'base.html' -%}
|
||||
{%- block content -%}
|
||||
{%- call() subheader('All topics') -%}
|
||||
|
||||
@@ -411,11 +411,11 @@ ul.horizontal, ol.horizontal {
|
||||
color: oklch(from var(--main-color) round(1.21 - L) 0 0);
|
||||
|
||||
&.critical {
|
||||
--main-color: hsl(from var(--critical-color) h 50% calc(l * 0.7));
|
||||
--main-color: hsl(from var(--critical-color) h 50% l);
|
||||
}
|
||||
|
||||
&.warn {
|
||||
--main-color: hsl(from var(--warn-color) h 50% calc(l * 1.2));
|
||||
--main-color: hsl(from var(--warn-color) h 50% 75%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user