interpretation inline tags

This commit is contained in:
SvyatoslavArtymovych 2023-05-22 09:54:20 +03:00
parent 7276050bb3
commit 8702503f40
14 changed files with 106 additions and 143423 deletions

View File

@ -68,9 +68,10 @@ def create_app(environment="development"):
login_manager.anonymous_user = AnonymousUser
# Jinja globals
from app.controllers.jinja_globals import form_hidden_tag
from app.controllers.jinja_globals import form_hidden_tag, display_tags
app.jinja_env.globals["form_hidden_tag"] = form_hidden_tag
app.jinja_env.globals["display_tags"] = display_tags
# Error handlers.
@app.errorhandler(HTTPException)

View File

@ -1,7 +1,28 @@
import re
from flask import current_app
from flask_wtf import FlaskForm
TAG_REGEX = re.compile(r"\[.*?\]")
# Using: {{ form_hidden_tag() }}
def form_hidden_tag():
form = FlaskForm()
return form.hidden_tag()
# Using: {{ display_tags("Some text with [tags] here") }}
def display_tags(text: str):
tags = current_app.config["TAG_REGEX"].findall(text)
classes = ["text-orange-500", "!no-underline"]
classes = " ".join(classes)
for tag in tags:
text = text.replace(
tag,
f"<a href='#' target='_blank' class='{classes}'>{tag}</a>",
)
return text

View File

@ -71,13 +71,13 @@ def set_comment_tags(comment: m.Comment, tags: str):
db.session.commit()
def set_interpretation_tags(interpretation: m.InterpretationTag, tags: str):
def set_interpretation_tags(interpretation: m.InterpretationTag, tags: list[str]):
interpretation_tags = m.InterpretationTag.query.filter_by(
interpretation_id=interpretation.id
).all()
for tag in interpretation_tags:
db.session.delete(tag)
tags_names = [tag.title() for tag in tags.split(",") if len(tag)]
tags_names = [tag.lower().replace("[", "").replace("]", "") for tag in tags]
for tag_name in tags_names:
try:

View File

@ -5,7 +5,6 @@ from wtforms.validators import DataRequired
class BaseInterpretationForm(FlaskForm):
about = StringField("About")
tags = StringField("Tags")
text = StringField("Text")

View File

@ -1113,10 +1113,6 @@ input:checked + .toggle-bg {
top: 2.5rem;
}
.top-3 {
top: 0.75rem;
}
.top-32 {
top: 8rem;
}
@ -1125,10 +1121,6 @@ input:checked + .toggle-bg {
top: 11rem;
}
.-z-10 {
z-index: -10;
}
.z-0 {
z-index: 0;
}
@ -1157,14 +1149,14 @@ input:checked + .toggle-bg {
z-index: 100;
}
.z-\[55\] {
z-index: 55;
}
.z-\[150\] {
z-index: 150;
}
.z-\[55\] {
z-index: 55;
}
.col-span-6 {
grid-column: span 6 / span 6;
}
@ -1357,10 +1349,6 @@ input:checked + .toggle-bg {
margin-top: auto;
}
.ml-1 {
margin-left: 0.25rem;
}
.block {
display: block;
}
@ -1413,6 +1401,10 @@ input:checked + .toggle-bg {
height: 1rem;
}
.h-40 {
height: 10rem;
}
.h-5 {
height: 1.25rem;
}
@ -1429,10 +1421,6 @@ input:checked + .toggle-bg {
height: 2rem;
}
.h-80 {
height: 20rem;
}
.h-9 {
height: 2.25rem;
}
@ -1458,34 +1446,14 @@ input:checked + .toggle-bg {
height: 100vh;
}
.h-16 {
height: 4rem;
}
.h-40 {
height: 10rem;
.max-h-40 {
max-height: 10rem;
}
.max-h-full {
max-height: 100%;
}
.max-h-16 {
max-height: 4rem;
}
.max-h-20 {
max-height: 5rem;
}
.max-h-28 {
max-height: 7rem;
}
.max-h-40 {
max-height: 10rem;
}
.w-1\/2 {
width: 50%;
}
@ -1598,20 +1566,11 @@ input:checked + .toggle-bg {
flex-shrink: 0;
}
.origin-\[0\] {
transform-origin: 0;
}
.-translate-x-full {
--tw-translate-x: -100%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.-translate-y-6 {
--tw-translate-y: -1.5rem;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.-translate-y-full {
--tw-translate-y: -100%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@ -1642,12 +1601,6 @@ input:checked + .toggle-bg {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.scale-75 {
--tw-scale-x: .75;
--tw-scale-y: .75;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.transform {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
@ -1656,6 +1609,10 @@ input:checked + .toggle-bg {
transform: none;
}
.\!cursor-pointer {
cursor: pointer !important;
}
.cursor-default {
cursor: default;
}
@ -1668,10 +1625,6 @@ input:checked + .toggle-bg {
cursor: pointer;
}
.\!cursor-pointer {
cursor: pointer !important;
}
.select-none {
-webkit-user-select: none;
-moz-user-select: none;
@ -1686,12 +1639,6 @@ input:checked + .toggle-bg {
list-style-type: none;
}
.appearance-none {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.grid-cols-4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
@ -1748,6 +1695,10 @@ input:checked + .toggle-bg {
justify-content: space-between;
}
.gap-1 {
gap: 0.25rem;
}
.gap-2 {
gap: 0.5rem;
}
@ -1756,10 +1707,6 @@ input:checked + .toggle-bg {
gap: 1.5rem;
}
.gap-1 {
gap: 0.25rem;
}
.-space-x-px > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(-1px * var(--tw-space-x-reverse));
@ -2070,6 +2017,11 @@ input:checked + .toggle-bg {
background-color: rgb(200 30 30 / var(--tw-bg-opacity));
}
.bg-sky-300 {
--tw-bg-opacity: 1;
background-color: rgb(125 211 252 / var(--tw-bg-opacity));
}
.bg-slate-300 {
--tw-bg-opacity: 1;
background-color: rgb(203 213 225 / var(--tw-bg-opacity));
@ -2098,11 +2050,6 @@ input:checked + .toggle-bg {
background-color: rgb(255 255 255 / 0.5);
}
.bg-sky-300 {
--tw-bg-opacity: 1;
background-color: rgb(125 211 252 / var(--tw-bg-opacity));
}
.bg-opacity-50 {
--tw-bg-opacity: 0.5;
}
@ -2172,9 +2119,9 @@ input:checked + .toggle-bg {
padding: 1.5rem;
}
.px-0 {
padding-left: 0px;
padding-right: 0px;
.\!px-0 {
padding-left: 0px !important;
padding-right: 0px !important;
}
.px-2 {
@ -2232,11 +2179,6 @@ input:checked + .toggle-bg {
padding-bottom: 1rem;
}
.\!px-0 {
padding-left: 0px !important;
padding-right: 0px !important;
}
.pb-3 {
padding-bottom: 0.75rem;
}
@ -2285,10 +2227,6 @@ input:checked + .toggle-bg {
padding-top: 1.5rem;
}
.pt-4 {
padding-top: 1rem;
}
.text-left {
text-align: left;
}
@ -2432,10 +2370,33 @@ input:checked + .toggle-bg {
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.text-orange-400 {
--tw-text-opacity: 1;
color: rgb(255 138 76 / var(--tw-text-opacity));
}
.text-orange-500 {
--tw-text-opacity: 1;
color: rgb(255 90 31 / var(--tw-text-opacity));
}
.text-orange-800 {
--tw-text-opacity: 1;
color: rgb(138 44 13 / var(--tw-text-opacity));
}
.line-through {
text-decoration-line: line-through;
}
.no-underline {
text-decoration-line: none;
}
.\!no-underline {
text-decoration-line: none !important;
}
.opacity-0 {
opacity: 0;
}
@ -2569,16 +2530,16 @@ input:checked + .toggle-bg {
background-color: rgb(155 28 28 / var(--tw-bg-opacity));
}
.hover\:bg-white:hover {
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.hover\:bg-sky-400:hover {
--tw-bg-opacity: 1;
background-color: rgb(56 189 248 / var(--tw-bg-opacity));
}
.hover\:bg-white:hover {
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.hover\:bg-gradient-to-bl:hover {
background-image: linear-gradient(to bottom left, var(--tw-gradient-stops));
}
@ -2628,12 +2589,6 @@ input:checked + .toggle-bg {
outline-offset: 2px;
}
.focus\:ring-0:focus {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
.focus\:ring-2:focus {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@ -2701,52 +2656,6 @@ input:checked + .toggle-bg {
color: rgb(17 24 39 / var(--tw-text-opacity));
}
.peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:translate-y-0 {
--tw-translate-y: 0px;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.peer:placeholder-shown ~ .peer-placeholder-shown\:translate-y-0 {
--tw-translate-y: 0px;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:scale-100 {
--tw-scale-x: 1;
--tw-scale-y: 1;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.peer:placeholder-shown ~ .peer-placeholder-shown\:scale-100 {
--tw-scale-x: 1;
--tw-scale-y: 1;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.peer:focus ~ .peer-focus\:left-0 {
left: 0px;
}
.peer:focus ~ .peer-focus\:-translate-y-6 {
--tw-translate-y: -1.5rem;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.peer:focus ~ .peer-focus\:scale-75 {
--tw-scale-x: .75;
--tw-scale-y: .75;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.peer:focus ~ .peer-focus\:font-medium {
font-weight: 500;
}
.peer:focus ~ .peer-focus\:text-blue-600 {
--tw-text-opacity: 1;
color: rgb(28 100 242 / var(--tw-text-opacity));
}
:is(.dark .dark\:block) {
display: block;
}
@ -2863,11 +2772,6 @@ input:checked + .toggle-bg {
background-color: rgb(4 116 129 / var(--tw-bg-opacity));
}
:is(.dark .dark\:bg-green-600) {
--tw-bg-opacity: 1;
background-color: rgb(5 122 85 / var(--tw-bg-opacity));
}
:is(.dark .dark\:bg-opacity-80) {
--tw-bg-opacity: 0.8;
}
@ -2912,6 +2816,11 @@ input:checked + .toggle-bg {
color: rgb(255 255 255 / var(--tw-text-opacity));
}
:is(.dark .dark\:text-orange-400) {
--tw-text-opacity: 1;
color: rgb(255 138 76 / var(--tw-text-opacity));
}
:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder {
--tw-placeholder-opacity: 1;
color: rgb(156 163 175 / var(--tw-placeholder-opacity));
@ -2972,11 +2881,6 @@ input:checked + .toggle-bg {
background-color: rgb(3 102 114 / var(--tw-bg-opacity));
}
:is(.dark .dark\:hover\:bg-green-700:hover) {
--tw-bg-opacity: 1;
background-color: rgb(4 108 78 / var(--tw-bg-opacity));
}
:is(.dark .dark\:hover\:text-blue-500:hover) {
--tw-text-opacity: 1;
color: rgb(63 131 248 / var(--tw-text-opacity));
@ -3042,21 +2946,11 @@ input:checked + .toggle-bg {
--tw-ring-color: rgb(5 80 92 / var(--tw-ring-opacity));
}
:is(.dark .dark\:focus\:ring-green-800:focus) {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(3 84 63 / var(--tw-ring-opacity));
}
:is(.dark .group:hover .dark\:group-hover\:text-white) {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.peer:focus ~ :is(.dark .peer-focus\:dark\:text-blue-500) {
--tw-text-opacity: 1;
color: rgb(63 131 248 / var(--tw-text-opacity));
}
@media (min-width: 640px) {
.sm\:col-span-3 {
grid-column: span 3 / span 3;

File diff suppressed because one or more lines are too long

View File

@ -93,5 +93,9 @@
{% endblock %}
<!-- scripts -->
{% block scripts %} {% endblock %}
<!-- DO NOT REMOVE THIS! -->
<!-- Adding tailwind classes that are not in html, but will be added by jinja -->
<span class="hidden text-orange-500 !no-underline"></span>
</body>
</html>

View File

@ -29,25 +29,6 @@
</div>
</div>
</div>
<div class="multiple-input-block">
<label for="tags-input" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
Tags
</label>
<input type="text" name="tags" class="hidden create-interpretation-tags">
<input
type="text"
id="tags-input"
class="multiple-input mb-3 shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-600 focus:border-blue-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="e.g. Law (press 'Enter' or Comma to add tag. Click on tag to edit it)"
data-save-results-to="create-interpretation-tags"
>
<div class="multiple-input-items gap-1 flex flex-wrap">
{% for tag in interpretation.tags %}
<div class="cursor-pointer multiple-input-word bg-sky-300 hover:bg-sky-400 dark:bg-blue-600 dark:hover:bg-blue-700 dark:text-white rounded text-center py-1/2 px-2">{{tag.name}}</div>
{% endfor %}
</div>
</div>
</div>
<!-- Modal footer -->
<div class="flex items-center p-6 space-x-2 border-t border-gray-200 rounded-b dark:border-gray-600">

View File

@ -70,27 +70,6 @@
</div>
</div>
</div>
<div class="multiple-input-block p-6 pt-0 space-y-6">
<div class="w-full max-w-6xl mx-auto rounded-xl bg-gray-50 dark:bg-gray-600 shadow-lg text-white-900">
<div class="overflow-hidden rounded-md bg-gray-50 [&>*]:dark:bg-gray-600 text-black [&>*]:!border-none [&>*]:!stroke-black dark:text-white dark:[&>*]:!stroke-white">
<div id="interpretation-text" class="quill-editor dark:text-white h-64">
</div>
</div>
</div>
<label for="tags-input" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
Tags
</label>
<input type="text" name="tags" class="hidden create-interpretation-tags">
<input
type="text"
id="tags-input"
class="multiple-input mb-3 shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-600 focus:border-blue-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="e.g. Law (press 'Enter' or Comma to add tag. Click on tag to edit it)"
data-save-results-to="create-interpretation-tags"
>
<div class="multiple-input-items gap-1 flex flex-wrap"></div>
</div>
<!-- Modal footer -->
<div class="flex items-center p-6 space-x-2 border-t border-gray-200 rounded-b dark:border-gray-600">
@ -158,7 +137,7 @@
<dt class="flex justify-center w-full mb-1 text-gray-500 md:text-lg dark:text-gray-400 flex-col">
<div class="ql-snow mb-2 truncate md:max-w-xl">
<div class="dark:text-white h-30 ql-editor-readonly !px-0">
<p>{{ interpretation.text|safe }}</p>
<p>{{ display_tags(interpretation.text)|safe }}</p>
</div>
</div>

View File

@ -23,7 +23,7 @@
<h1 class="text-l font-extrabold dark:text-white ml-4 truncate">
{{ section.label }}
</h1>
<div class="ql-editor-readonly text-lg dark:text-white p-3">{{interpretation.text|safe}}</div>
<div class="ql-editor-readonly text-lg dark:text-white p-3">{{display_tags(interpretation.text)|safe}}</div>
</div>
<div class="p-1">
<!-- prettier-ignore -->

View File

@ -73,7 +73,7 @@
<p>{{ interpretation.section.label }}</p>
</a>
<div class="dark:text-white h-30 ql-editor-readonly">
<p>{{ interpretation.text|safe }}</p>
<p>{{ display_tags(interpretation.text)|safe }}</p>
</div>
</div>
<div class="flex mt-auto align-center justify-between md:w-full">

View File

@ -117,7 +117,7 @@
<p>{{ interpretation.section.label }}</p>
</a>
<div class="dark:text-white h-30 ql-editor-readonly">
<p>{{ interpretation.text|safe }}</p>
<p>{{ display_tags(interpretation.text)|safe }}</p>
</div>
</div>
<div class="flex mt-auto align-center justify-between md:w-full">

View File

@ -3,6 +3,7 @@ from flask import (
flash,
redirect,
url_for,
current_app,
)
from flask_login import login_required, current_user
@ -121,8 +122,10 @@ def interpretation_create(
)
if form.validate_on_submit():
text = form.text.data
interpretation: m.Interpretation = m.Interpretation(
text=form.text.data,
text=text,
section_id=section_id,
user_id=current_user.id,
)
@ -134,7 +137,7 @@ def interpretation_create(
)
interpretation.save()
tags = form.tags.data
tags = current_app.config["TAG_REGEX"].findall(text)
if tags:
set_interpretation_tags(interpretation, tags)
@ -183,9 +186,10 @@ def interpretation_edit(
)
if form.validate_on_submit():
interpretation.text = form.text.data
text = form.text.data
interpretation.text = text
tags = form.tags.data
tags = current_app.config["TAG_REGEX"].findall(text)
if tags:
set_interpretation_tags(interpretation, tags)

View File

@ -1,4 +1,5 @@
import os
import re
from functools import lru_cache
from pydantic import BaseSettings
from flask import Flask
@ -28,6 +29,9 @@ class BaseConfig(BaseSettings):
# HTTPProvider for SIWE
HTTP_PROVIDER_URL: str
# regex
TAG_REGEX = re.compile(r"\[.*?\]")
@staticmethod
def configure(app: Flask):
# Implement this method to do further configuration on your app.