Compare commits

...

10 Commits

14 changed files with 241 additions and 44 deletions

View File

@ -25,7 +25,7 @@ Designers: Paul James Miller
## ICONCINO ## ICONCINO
Affected files: [`data/static/misc/error.svg`](./data/static/misc/error.svg) [`data/static/misc/image.svg`](./data/static/misc/image.svg) [`data/static/misc/info.svg`](./data/static/misc/info.svg) [`data/static/misc/lock.svg`](./data/static/misc/lock.svg) [`data/static/misc/sticky.svg`](./data/static/misc/sticky.svg) [`data/static/misc/warn.svg`](./data/static/misc/warn.svg) Affected files: [`data/static/misc/error.svg`](./data/static/misc/error.svg) [`data/static/misc/image.svg`](./data/static/misc/image.svg) [`data/static/misc/info.svg`](./data/static/misc/info.svg) [`data/static/misc/lock.svg`](./data/static/misc/lock.svg) [`data/static/misc/spoiler.svg`](./data/static/misc/spoiler.svg) [`data/static/misc/sticky.svg`](./data/static/misc/sticky.svg) [`data/static/misc/warn.svg`](./data/static/misc/warn.svg)
URL: https://www.figma.com/community/file/1136337054881623512/iconcino-v2-0-0-free-icons-cc0-1-0-license URL: https://www.figma.com/community/file/1136337054881623512/iconcino-v2-0-0-free-icons-cc0-1-0-license
Copyright: Gabriele Malaspina Copyright: Gabriele Malaspina
Designers: Gabriele Malaspina Designers: Gabriele Malaspina

View File

@ -1,6 +1,6 @@
from flask import Flask, session from flask import Flask, session
from dotenv import load_dotenv from dotenv import load_dotenv
from .models import Avatars, Users from .models import Avatars, Users, PostHistory, Posts
from .auth import digest from .auth import digest
from .routes.users import is_logged_in, get_active_user from .routes.users import is_logged_in, get_active_user
from .routes.threads import get_post_url from .routes.threads import get_post_url
@ -9,7 +9,7 @@ from .constants import (
InfoboxKind, InfoboxIcons, InfoboxHTMLClass, InfoboxKind, InfoboxIcons, InfoboxHTMLClass,
REACTION_EMOJI, REACTION_EMOJI,
) )
from .lib.babycode import babycode_to_html, EMOJI from .lib.babycode import babycode_to_html, EMOJI, BABYCODE_VERSION
from datetime import datetime from datetime import datetime
import os import os
import time import time
@ -48,6 +48,23 @@ def create_deleted_user():
"permission": PermissionLevel.SYSTEM.value, "permission": PermissionLevel.SYSTEM.value,
}) })
def reparse_posts():
from .db import db
post_histories = PostHistory.findall([
('markup_language', '=', 'babycode'),
('format_version', 'IS NOT', BABYCODE_VERSION)
])
if len(post_histories) == 0:
return
print('Re-parsing babycode, this may take a while...')
with db.transaction():
for ph in post_histories:
ph.update({
'content': babycode_to_html(ph['original_markup']),
'format_version': BABYCODE_VERSION,
})
print('Re-parsing done.')
def create_app(): def create_app():
app = Flask(__name__) app = Flask(__name__)
app.config.from_file('../config/pyrom_config.toml', load=tomllib.load, text=False) app.config.from_file('../config/pyrom_config.toml', load=tomllib.load, text=False)
@ -76,6 +93,8 @@ def create_app():
create_admin() create_admin()
create_deleted_user() create_deleted_user()
reparse_posts()
from app.routes.app import bp as app_bp from app.routes.app import bp as app_bp
from app.routes.topics import bp as topics_bp from app.routes.topics import bp as topics_bp
from app.routes.threads import bp as threads_bp from app.routes.threads import bp as threads_bp

View File

@ -202,9 +202,9 @@ class Model:
@classmethod @classmethod
def findall(cls, condition): def findall(cls, condition, operator='='):
rows = db.QueryBuilder(cls.table)\ rows = db.QueryBuilder(cls.table)\
.where(condition)\ .where(condition, operator)\
.all() .all()
res = [] res = []
for row in rows: for row in rows:

View File

@ -2,6 +2,8 @@ from .babycode_parser import Parser
from markupsafe import escape from markupsafe import escape
import re import re
BABYCODE_VERSION = 3
NAMED_COLORS = [ NAMED_COLORS = [
'black', 'silver', 'gray', 'white', 'maroon', 'red', 'black', 'silver', 'gray', 'white', 'maroon', 'red',
'purple', 'fuchsia', 'green', 'lime', 'olive', 'yellow', 'purple', 'fuchsia', 'green', 'lime', 'olive', 'yellow',
@ -33,7 +35,23 @@ NAMED_COLORS = [
'violet', 'wheat', 'white', 'whitesmoke', 'yellow', 'yellowgreen', 'violet', 'wheat', 'white', 'whitesmoke', 'yellow', 'yellowgreen',
] ]
def tag_code(children, attr): def is_tag(e, tag=None):
if e is None:
return False
if isinstance(e, str):
return False
if e['type'] != 'bbcode':
return False
if tag is None:
return True
return e['name'] == tag
def is_text(e):
return isinstance(e, str)
def tag_code(children, attr, surrounding):
is_inline = children.find('\n') == -1 is_inline = children.find('\n') == -1
if is_inline: if is_inline:
return f"<code class=\"inline-code\">{children}</code>" return f"<code class=\"inline-code\">{children}</code>"
@ -47,7 +65,7 @@ def tag_list(children):
list_body = re.sub(r"\n\n+", "\1", list_body) list_body = re.sub(r"\n\n+", "\1", list_body)
return " ".join([f"<li>{x}</li>" for x in list_body.split("\1") if x]) return " ".join([f"<li>{x}</li>" for x in list_body.split("\1") if x])
def tag_color(children, attr): def tag_color(children, attr, surrounding):
hex_re = r"^#?([0-9a-f]{6}|[0-9a-f]{3})$" hex_re = r"^#?([0-9a-f]{6}|[0-9a-f]{3})$"
potential_color = attr.lower().strip() potential_color = attr.lower().strip()
@ -61,25 +79,48 @@ def tag_color(children, attr):
# return just the way it was if we can't parse it # return just the way it was if we can't parse it
return f"[color={attr}]{children}[/color]" return f"[color={attr}]{children}[/color]"
def tag_spoiler(children, attr, surrounding):
spoiler_name = attr if attr else "Spoiler"
content = f"<div class='accordion-content post-accordion-content hidden'>{children}</div>"
container = f"""<div class='accordion hidden'><div class='accordion-header'><button type='button' class='accordion-toggle'>+</button><span>{spoiler_name}</span></div>{content}</div>"""
return container
def tag_image(children, attr, surrounding):
img = f"<img class=\"post-image\" src=\"{attr}\" alt=\"{children}\">"
if not is_tag(surrounding[0], 'img'):
img = f"<div class=post-img-container>{img}"
if not is_tag(surrounding[1], 'img'):
img = f"{img}</div>"
return img
TAGS = { TAGS = {
"b": lambda children, attr: f"<strong>{children}</strong>", "b": lambda children, attr, _: f"<strong>{children}</strong>",
"i": lambda children, attr: f"<em>{children}</em>", "i": lambda children, attr, _: f"<em>{children}</em>",
"s": lambda children, attr: f"<del>{children}</del>", "s": lambda children, attr, _: f"<del>{children}</del>",
"u": lambda children, attr: f"<u>{children}</u>", "u": lambda children, attr, _: f"<u>{children}</u>",
"img": lambda children, attr: f"<div class=\"post-img-container\"><img class=\"block-img\" src=\"{attr}\" alt=\"{children}\"></div>", "img": tag_image,
"url": lambda children, attr: f"<a href={attr}>{children}</a>", "url": lambda children, attr, _: f"<a href={attr}>{children}</a>",
"quote": lambda children, attr: f"<blockquote>{children}</blockquote>", "quote": lambda children, attr, _: f"<blockquote>{children}</blockquote>",
"code": tag_code, "code": tag_code,
"ul": lambda children, attr: f"<ul>{tag_list(children)}</ul>", "ul": lambda children, attr, _: f"<ul>{tag_list(children)}</ul>",
"ol": lambda children, attr: f"<ol>{tag_list(children)}</ol>", "ol": lambda children, attr, _: f"<ol>{tag_list(children)}</ol>",
"big": lambda children, attr: f"<span style='font-size: 2rem;'>{children}</span>", "big": lambda children, attr, _: f"<span style='font-size: 2rem;'>{children}</span>",
"small": lambda children, attr: f"<span style='font-size: 0.75rem;'>{children}</span>", "small": lambda children, attr, _: f"<span style='font-size: 0.75rem;'>{children}</span>",
"color": tag_color, "color": tag_color,
"center": lambda children, attr: f"<div style='text-align: center;'>{children}</div>", "center": lambda children, attr, _: f"<div style='text-align: center;'>{children}</div>",
"right": lambda children, attr: f"<div style='text-align: right;'>{children}</div>", "right": lambda children, attr, _: f"<div style='text-align: right;'>{children}</div>",
"spoiler": tag_spoiler,
}
# [img] is considered block for the purposes of collapsing whitespace,
# despite being potentially inline (since the resulting <img> tag is inline, but creates a block container around itself and sibling images).
# [code] has a special case in is_inline().
INLINE_TAGS = {
'b', 'i', 's', 'u', 'color', 'big', 'small', 'url'
} }
def make_emoji(name, code): def make_emoji(name, code):
@ -138,6 +179,33 @@ def break_lines(text):
text = re.sub(r"\n\n+", "<br><br>", text) text = re.sub(r"\n\n+", "<br><br>", text)
return text return text
def is_inline(e):
if e is None:
return False # i think
if is_text(e):
return True
if is_tag(e):
if is_tag(e, 'code'): # special case, since [code] can be inline OR block
return '\n' not in e['children']
return e['name'] in INLINE_TAGS
return e['type'] != 'rule'
def should_collapse(text, surrounding):
if not isinstance(text, str):
return False
if not text:
return True
if not text.strip() and '\n' not in text:
return not is_inline(surrounding[0]) and not is_inline(surrounding[1])
return False
def babycode_to_html(s): def babycode_to_html(s):
subj = escape(s.strip().replace('\r\n', '\n').replace('\r', '\n')) subj = escape(s.strip().replace('\r\n', '\n').replace('\r', '\n'))
parser = Parser(subj) parser = Parser(subj)
@ -145,10 +213,19 @@ def babycode_to_html(s):
parser.bbcode_tags_only_text_children = TEXT_ONLY parser.bbcode_tags_only_text_children = TEXT_ONLY
parser.valid_emotes = EMOJI.keys() parser.valid_emotes = EMOJI.keys()
elements = parser.parse() uncollapsed = parser.parse()
print(elements) elements = []
for i in range(len(uncollapsed)):
e = uncollapsed[i]
surrounding = (
uncollapsed[i - 1] if i-1 >= 0 else None,
uncollapsed[i + 1] if i+1 < len(uncollapsed) else None
)
if not should_collapse(e, surrounding):
elements.append(e)
out = "" out = ""
def fold(element, nobr): def fold(element, nobr, surrounding):
if isinstance(element, str): if isinstance(element, str):
if nobr: if nobr:
return element return element
@ -157,10 +234,15 @@ def babycode_to_html(s):
match element['type']: match element['type']:
case "bbcode": case "bbcode":
c = "" c = ""
for child in element['children']: for i in range(len(element['children'])):
child = element['children'][i]
_surrounding = (
element['children'][i - 1] if i-1 >= 0 else None,
element['children'][i + 1] if i+1 < len(element['children']) else None
)
_nobr = element['name'] == "code" or element['name'] == "ul" or element['name'] == "ol" _nobr = element['name'] == "code" or element['name'] == "ul" or element['name'] == "ol"
c = c + fold(child, _nobr) c = c + fold(child, _nobr, _surrounding)
res = TAGS[element['name']](c, element['attr']) res = TAGS[element['name']](c, element['attr'], surrounding)
return res return res
case "link": case "link":
return f"<a href=\"{element['url']}\">{element['url']}</a>" return f"<a href=\"{element['url']}\">{element['url']}</a>"
@ -168,6 +250,12 @@ def babycode_to_html(s):
return EMOJI[element['name']] return EMOJI[element['name']]
case "rule": case "rule":
return "<hr>" return "<hr>"
for e in elements:
out = out + fold(e, False) for i in range(len(elements)):
e = elements[i]
surrounding = (
elements[i - 1] if i-1 >= 0 else None,
elements[i + 1] if i+1 < len(elements) else None
)
out = out + fold(e, False, surrounding)
return out return out

View File

@ -4,7 +4,7 @@ import re
PAT_EMOTE = r"[^\s:]" PAT_EMOTE = r"[^\s:]"
PAT_BBCODE_TAG = r"\w" PAT_BBCODE_TAG = r"\w"
PAT_BBCODE_ATTR = r"[^\s\]]" PAT_BBCODE_ATTR = r"[^\]]"
PAT_LINK = r"https?:\/\/[\w\-_.?:\/=&~@#%]+[\w\-\/]" PAT_LINK = r"https?:\/\/[\w\-_.?:\/=&~@#%]+[\w\-\/]"
class Parser: class Parser:

View File

@ -10,6 +10,7 @@ MIGRATIONS = [
migrate_old_avatars, migrate_old_avatars,
'DELETE FROM sessions', # delete old lua porom sessions 'DELETE FROM sessions', # delete old lua porom sessions
'ALTER TABLE "users" ADD COLUMN "invited_by" INTEGER REFERENCES users(id)', # invitation system 'ALTER TABLE "users" ADD COLUMN "invited_by" INTEGER REFERENCES users(id)', # invitation system
'ALTER TABLE "post_history" ADD COLUMN "format_version" INTEGER DEFAULT NULL',
] ]
def run_migrations(): def run_migrations():

View File

@ -2,7 +2,7 @@ from flask import (
Blueprint, redirect, url_for, flash, render_template, request Blueprint, redirect, url_for, flash, render_template, request
) )
from .users import login_required, get_active_user from .users import login_required, get_active_user
from ..lib.babycode import babycode_to_html from ..lib.babycode import babycode_to_html, BABYCODE_VERSION
from ..constants import InfoboxKind from ..constants import InfoboxKind
from ..db import db from ..db import db
from ..models import Posts, PostHistory, Threads, Topics from ..models import Posts, PostHistory, Threads, Topics
@ -11,6 +11,7 @@ bp = Blueprint("posts", __name__, url_prefix = "/post")
def create_post(thread_id, user_id, content, markup_language="babycode"): def create_post(thread_id, user_id, content, markup_language="babycode"):
parsed_content = babycode_to_html(content)
with db.transaction(): with db.transaction():
post = Posts.create({ post = Posts.create({
"thread_id": thread_id, "thread_id": thread_id,
@ -20,10 +21,11 @@ def create_post(thread_id, user_id, content, markup_language="babycode"):
revision = PostHistory.create({ revision = PostHistory.create({
"post_id": post.id, "post_id": post.id,
"content": babycode_to_html(content), "content": parsed_content,
"is_initial_revision": True, "is_initial_revision": True,
"original_markup": content, "original_markup": content,
"markup_language": markup_language, "markup_language": markup_language,
"format_version": BABYCODE_VERSION,
}) })
post.update({"current_revision_id": revision.id}) post.update({"current_revision_id": revision.id})
@ -31,14 +33,16 @@ def create_post(thread_id, user_id, content, markup_language="babycode"):
def update_post(post_id, new_content, markup_language='babycode'): def update_post(post_id, new_content, markup_language='babycode'):
parsed_content = babycode_to_html(new_content)
with db.transaction(): with db.transaction():
post = Posts.find({'id': post_id}) post = Posts.find({'id': post_id})
new_revision = PostHistory.create({ new_revision = PostHistory.create({
'post_id': post.id, 'post_id': post.id,
'content': babycode_to_html(new_content), 'content': parsed_content,
'is_initial_revision': False, 'is_initial_revision': False,
'original_markup': new_content, 'original_markup': new_content,
'markup_language': markup_language, 'markup_language': markup_language,
'format_version': BABYCODE_VERSION,
}) })
post.update({'current_revision_id': new_revision.id}) post.update({'current_revision_id': new_revision.id})

View File

@ -126,8 +126,9 @@
<code class="inline-code">[img=https://forum.poto.cafe/avatars/default.webp]the Python logo with a cowboy hat[/img]</code> <code class="inline-code">[img=https://forum.poto.cafe/avatars/default.webp]the Python logo with a cowboy hat[/img]</code>
{{ '[img=/static/avatars/default.webp]the Python logo with a cowboy hat[/img]' | babycode | safe }} {{ '[img=/static/avatars/default.webp]the Python logo with a cowboy hat[/img]' | babycode | safe }}
</p> </p>
<p>Text inside the tag becomes the alt text. The attribute is the image URL.</p> <p>Text inside the tag becomes the alt text. The attribute is the image URL. The text inside the tag will become the image's alt text.</p>
<p>Images will always break up a paragraph and will get scaled down to a maximum of 400px. The text inside the tag will become the image's alt text.</p> <p>Images will always break up a paragraph and will get scaled down to a maximum of 400px. However, consecutive image tags will try to stay in one line, wrapping if necessary. Break the paragraph if you wish to keep images on their own paragraph.</p>
<p>Multiple images attached to a post can be clicked to open a dialog to view them.</p>
</section> </section>
<section class="babycode-guide-section"> <section class="babycode-guide-section">
<h2 id="adding-code-blocks">Adding code blocks</h2> <h2 id="adding-code-blocks">Adding code blocks</h2>
@ -151,6 +152,15 @@
Will produce the following list: Will produce the following list:
{{ list | babycode | safe }} {{ list | babycode | safe }}
</section> </section>
<section class="babycode-guide-section">
<h2 id="spoilers">Spoilers</h2>
{% set spoiler = "[spoiler=Major Metal Gear Spoilers]Snake dies[/spoiler]" %}
<p>You can make a section collapsible by using the <code class="inline-code">[spoiler]</code> tag:</p>
{{ ("[code]\n%s[/code]" % spoiler) | babycode | safe }}
Will produce:
{{ spoiler | babycode | safe }}
All other tags are supported inside spoilers.
</section>
{% endset %} {% endset %}
{{ sections | safe }} {{ sections | safe }}
</div> </div>

View File

@ -59,6 +59,7 @@
<button class="babycode-button contain-svg full" type=button id="post-editor-img" title="Insert Image"><img src="/static/misc/image.svg"></button> <button class="babycode-button contain-svg full" type=button id="post-editor-img" title="Insert Image"><img src="/static/misc/image.svg"></button>
<button class="babycode-button" type=button id="post-editor-ol" title="Insert Ordered list">1.</button> <button class="babycode-button" type=button id="post-editor-ol" title="Insert Ordered list">1.</button>
<button class="babycode-button" type=button id="post-editor-ul" title="Insert Unordered list">&bullet;</button> <button class="babycode-button" type=button id="post-editor-ul" title="Insert Unordered list">&bullet;</button>
<button class="babycode-button contain-svg full" type=button id="post-editor-spoiler" title="Insert spoiler"><img src="/static/misc/spoiler.svg"></button>
</span> </span>
<textarea class="babycode-editor" name="{{ ta_name }}" id="babycode-content" placeholder="{{ ta_placeholder }}" {{ "required" if not optional else "" }}>{{ prefill }}</textarea> <textarea class="babycode-editor" name="{{ ta_name }}" id="babycode-content" placeholder="{{ ta_placeholder }}" {{ "required" if not optional else "" }}>{{ prefill }}</textarea>
<a href="{{ url_for("app.babycode_guide") }}" target="_blank">babycode guide</a> <a href="{{ url_for("app.babycode_guide") }}" target="_blank">babycode guide</a>

View File

@ -48,6 +48,7 @@
const buttonImg = document.getElementById("post-editor-img"); const buttonImg = document.getElementById("post-editor-img");
const buttonOl = document.getElementById("post-editor-ol"); const buttonOl = document.getElementById("post-editor-ol");
const buttonUl = document.getElementById("post-editor-ul"); const buttonUl = document.getElementById("post-editor-ul");
const buttonSpoiler = document.getElementById("post-editor-spoiler");
function insertTag(tagStart, newline = false, prefill = "") { function insertTag(tagStart, newline = false, prefill = "") {
const hasAttr = tagStart[tagStart.length - 1] === "="; const hasAttr = tagStart[tagStart.length - 1] === "=";
@ -130,6 +131,10 @@
e.preventDefault(); e.preventDefault();
insertTag("ul", true); insertTag("ul", true);
}) })
buttonSpoiler.addEventListener("click", (e) => {
e.preventDefault();
insertTag("spoiler=", true, "hidden content");
})
const previewEndpoint = "/api/babycode-preview"; const previewEndpoint = "/api/babycode-preview";
let previousMarkup = ""; let previousMarkup = "";
@ -173,5 +178,8 @@
const json_resp = await req.json(); const json_resp = await req.json();
previewContainer.innerHTML = json_resp.html; previewContainer.innerHTML = json_resp.html;
previewErrorsContainer.textContent = ""; previewErrorsContainer.textContent = "";
const accordionRefreshEvt = new CustomEvent("refresh_accordions");
document.body.dispatchEvent(accordionRefreshEvt);
}); });
} }

View File

@ -110,27 +110,54 @@ document.addEventListener("DOMContentLoaded", () => {
}); });
// accordions // accordions
const accordions = document.querySelectorAll(".accordion"); const handledAccordions = new Set();
accordions.forEach(accordion => { function attachAccordionHandlers(accordion){
if(handledAccordions.has(accordion)) {
return;
}
handledAccordions.add(accordion)
const header = accordion.querySelector(".accordion-header"); const header = accordion.querySelector(".accordion-header");
const toggleButton = header.querySelector(".accordion-toggle"); const toggleButton = header.querySelector(".accordion-toggle");
const content = accordion.querySelector(".accordion-content"); const content = accordion.querySelector(".accordion-content");
const toggle = (e) => { const toggle = (e) => {
e.stopPropagation(); e.stopPropagation();
accordion.classList.toggle("hidden"); accordion.classList.toggle("hidden");
content.classList.toggle("hidden"); content.classList.toggle("hidden");
toggleButton.textContent = content.classList.contains("hidden") ? "+" : "-" toggleButton.textContent = content.classList.contains("hidden") ? "+" : "-"
} }
toggleButton.addEventListener("click", toggle); toggleButton.addEventListener("click", toggle);
}); }
function refreshAccordions(){
const accordions = document.querySelectorAll(".accordion");
accordions.forEach(attachAccordionHandlers);
}
refreshAccordions()
document.body.addEventListener('refresh_accordions', refreshAccordions)
//lightboxes //lightboxes
lightboxObj = constructLightbox(); lightboxObj = constructLightbox();
document.body.appendChild(lightboxObj.dialog); document.body.appendChild(lightboxObj.dialog);
const postImages = document.querySelectorAll(".post-inner img.block-img");
function setImageMaxSize(img) {
const { maxWidth: origMaxWidth } = getComputedStyle(img);
if (img.naturalWidth >= parseInt(origMaxWidth)) {
return;
}
img.style.maxWidth = img.naturalWidth + "px";
}
const postImages = document.querySelectorAll(".post-inner img.post-image");
postImages.forEach(postImage => { postImages.forEach(postImage => {
if (postImage.complete) {
setImageMaxSize(postImage);
} else {
postImage.addEventListener("load", () => setImageMaxSize(postImage));
}
const belongingTo = postImage.closest(".post-inner"); const belongingTo = postImage.closest(".post-inner");
const images = lightboxImages.get(belongingTo) ?? []; const images = lightboxImages.get(belongingTo) ?? [];
images.push({ images.push({

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 4L9.87868 9.87868M20 20L14.1213 14.1213M9.87868 9.87868C9.33579 10.4216 9 11.1716 9 12C9 13.6569 10.3431 15 12 15C12.8284 15 13.5784 14.6642 14.1213 14.1213M9.87868 9.87868L14.1213 14.1213M6.76821 6.76821C4.72843 8.09899 2.96378 10.026 2 11.9998C3.74646 15.5764 8.12201 19 11.9998 19C13.7376 19 15.5753 18.3124 17.2317 17.2317M9.76138 5.34717C10.5114 5.12316 11.2649 5 12.0005 5C15.8782 5 20.2531 8.42398 22 12.0002C21.448 13.1302 20.6336 14.2449 19.6554 15.2412" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<!-- https://www.figma.com/community/file/1136337054881623512/iconcino-v2-0-0-free-icons-cc0-1-0-license -->

After

Width:  |  Height:  |  Size: 814 B

View File

@ -511,10 +511,21 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus
width: 100%; width: 100%;
} }
.block-img { .post-img-container {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.post-image {
object-fit: contain; object-fit: contain;
max-width: 400px; max-width: 300px;
max-height: 400px; max-height: 300px;
min-width: 200px;
min-height: 200px;
flex: 1 1 0%;
width: auto;
height: auto;
} }
.thread-info-container { .thread-info-container {
@ -786,6 +797,12 @@ ul, ol {
display: none; display: none;
} }
.post-accordion-content {
padding-top: 10px;
padding-bottom: 10px;
background-color: rgb(173.5214173228, 183.6737007874, 161.0262992126);
}
.inbox-container { .inbox-container {
padding: 10px; padding: 10px;
} }

View File

@ -512,10 +512,21 @@ input[type="text"], input[type="password"], textarea, select {
} }
} }
.block-img { .post-img-container {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.post-image {
object-fit: contain; object-fit: contain;
max-width: 400px; max-width: 400px;
max-height: 400px; max-height: 400px;
min-width: 200px;
min-height: 200px;
flex: 1 1 0%;
width: auto;
height: auto;
} }
.thread-info-container { .thread-info-container {
@ -781,6 +792,12 @@ ul, ol {
display: none; display: none;
} }
.post-accordion-content {
padding-top: 10px;
padding-bottom: 10px;
background-color: $main_bg;
}
.inbox-container { .inbox-container {
padding: 10px; padding: 10px;
} }