Compare commits

...

9 Commits

17 changed files with 2165 additions and 29 deletions

View File

@ -2,7 +2,7 @@ from flask import Flask, session
from dotenv import load_dotenv from dotenv import load_dotenv
from .models import Avatars, Users, PostHistory, Posts 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, get_prefers_theme
from .routes.threads import get_post_url from .routes.threads import get_post_url
from .constants import ( from .constants import (
PermissionLevel, permission_level_string, PermissionLevel, permission_level_string,
@ -83,6 +83,18 @@ def create_app():
app.config['MAX_CONTENT_LENGTH'] = 1000 * 1000 app.config['MAX_CONTENT_LENGTH'] = 1000 * 1000
os.makedirs(os.path.dirname(app.config["DB_PATH"]), exist_ok = True) os.makedirs(os.path.dirname(app.config["DB_PATH"]), exist_ok = True)
css_dir = 'data/static/css/'
allowed_themes = []
for f in os.listdir(css_dir):
if not os.path.isfile(os.path.join(css_dir, f)):
continue
theme_name = os.path.splitext(os.path.basename(f))[0]
allowed_themes.append(theme_name)
allowed_themes.sort(key=(lambda x: (x != 'style', x)))
app.config['allowed_themes'] = allowed_themes
with app.app_context(): with app.app_context():
from .schema import create as create_tables from .schema import create as create_tables
from .migrations import run_migrations from .migrations import run_migrations
@ -140,6 +152,7 @@ def create_app():
def inject_funcs(): def inject_funcs():
return { return {
'get_post_url': get_post_url, 'get_post_url': get_post_url,
'get_prefers_theme': get_prefers_theme,
} }
@app.template_filter("ts_datetime") @app.template_filter("ts_datetime")
@ -178,4 +191,11 @@ def create_app():
def cachebust(subject): def cachebust(subject):
return f"{subject}?v={str(int(time.time()))}" return f"{subject}?v={str(int(time.time()))}"
@app.template_filter('theme_name')
def get_theme_name(subject: str):
if subject == 'style':
return 'Default'
return f'{subject.removeprefix('theme-').capitalize()} (beta)'
return app return app

View File

@ -1,5 +1,5 @@
from .babycode_parser import Parser from .babycode_parser import Parser
from markupsafe import escape from markupsafe import Markup, escape
import re import re
BABYCODE_VERSION = 3 BABYCODE_VERSION = 3
@ -241,7 +241,7 @@ def babycode_to_html(s):
element['children'][i + 1] if i+1 < len(element['children']) 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, _surrounding) c = c + Markup(fold(child, _nobr, _surrounding))
res = TAGS[element['name']](c, element['attr'], surrounding) res = TAGS[element['name']](c, element['attr'], surrounding)
return res return res
case "link": case "link":

View File

@ -178,7 +178,7 @@ class Topics(Model):
q = """ q = """
SELECT SELECT
threads.title, threads.slug, threads.created_at, threads.is_locked, threads.is_stickied, threads.id, threads.title, threads.slug, threads.created_at, threads.is_locked, threads.is_stickied,
users.username AS started_by, users.username AS started_by,
u.username AS latest_post_username, u.username AS latest_post_username,
ph.content AS latest_post_content, ph.content AS latest_post_content,
@ -251,6 +251,16 @@ class Avatars(Model):
class Subscriptions(Model): class Subscriptions(Model):
table = "subscriptions" table = "subscriptions"
def get_unread_count(self):
q = """SELECT COUNT(*) AS unread_count
FROM posts
LEFT JOIN subscriptions ON subscriptions.thread_id = posts.thread_id
WHERE subscriptions.user_id = ? AND posts.created_at > subscriptions.last_seen AND posts.thread_id = ?"""
res = db.fetch_one(q, self.user_id, self.thread_id)
if res:
return res['unread_count']
return None
class APIRateLimits(Model): class APIRateLimits(Model):
table = 'api_rate_limits' table = 'api_rate_limits'

View File

@ -54,12 +54,14 @@ def thread(slug):
other_topics = Topics.select() other_topics = Topics.select()
is_subscribed = False is_subscribed = False
unread_count = None
if is_logged_in(): if is_logged_in():
subscription = Subscriptions.find({ subscription = Subscriptions.find({
'thread_id': thread.id, 'thread_id': thread.id,
'user_id': get_active_user().id, 'user_id': get_active_user().id,
}) })
if subscription: if subscription:
unread_count = subscription.get_unread_count()
if int(posts[-1]['created_at']) > int(subscription.last_seen): if int(posts[-1]['created_at']) > int(subscription.last_seen):
subscription.update({ subscription.update({
'last_seen': int(posts[-1]['created_at']) 'last_seen': int(posts[-1]['created_at'])
@ -76,6 +78,7 @@ def thread(slug):
topics = other_topics, topics = other_topics,
is_subscribed = is_subscribed, is_subscribed = is_subscribed,
Reactions = Reactions, Reactions = Reactions,
unread_count = unread_count,
) )

View File

@ -1,8 +1,8 @@
from flask import ( from flask import (
Blueprint, render_template, request, redirect, url_for, flash, session Blueprint, render_template, request, redirect, url_for, flash, session
) )
from .users import login_required, mod_only from .users import login_required, mod_only, get_active_user, is_logged_in
from ..models import Users, Topics, Threads from ..models import Users, Topics, Threads, Subscriptions
from ..constants import InfoboxKind from ..constants import InfoboxKind
from slugify import slugify from slugify import slugify
import time import time
@ -62,9 +62,21 @@ def topic(slug):
page_count = max(math.ceil(threads_count / THREADS_PER_PAGE), 1) page_count = max(math.ceil(threads_count / THREADS_PER_PAGE), 1)
page = max(1, min(int(request.args.get('page', default=1)), page_count)) page = max(1, min(int(request.args.get('page', default=1)), page_count))
threads_list = target_topic.get_threads(THREADS_PER_PAGE, page, sort_by)
subscriptions = {}
if is_logged_in():
for thread in threads_list:
subscription = Subscriptions.find({
'user_id': get_active_user().id,
'thread_id': thread['id'],
})
if subscription:
subscriptions[thread['id']] = subscription.get_unread_count()
return render_template( return render_template(
"topics/topic.html", "topics/topic.html",
threads_list = target_topic.get_threads(THREADS_PER_PAGE, page, sort_by), threads_list = threads_list,
subscriptions = subscriptions,
topic = target_topic, topic = target_topic,
current_page = page, current_page = page,
page_count = page_count page_count = page_count

View File

@ -165,6 +165,15 @@ def admin_only(*args, **kwargs):
return decorator return decorator
def get_prefers_theme():
if not 'theme' in session:
return 'style'
if session['theme'] not in current_app.config['allowed_themes']:
return 'style'
return session['theme']
@bp.get("/log_in") @bp.get("/log_in")
@redirect_if_logged_in(".page", username = lambda: get_active_user().username) @redirect_if_logged_in(".page", username = lambda: get_active_user().username)
def log_in(): def log_in():
@ -288,6 +297,12 @@ def settings_form(username):
# we silently ignore the passed username # we silently ignore the passed username
# and grab the correct user from the session # and grab the correct user from the session
user = get_active_user() user = get_active_user()
theme = request.form.get('theme', default='style')
if theme == 'style':
if 'theme' in session:
session.pop('theme')
else:
session['theme'] = theme
topic_sort_by = request.form.get('topic_sort_by', default='activity') topic_sort_by = request.form.get('topic_sort_by', default='activity')
if topic_sort_by == 'activity' or topic_sort_by == 'thread': if topic_sort_by == 'activity' or topic_sort_by == 'thread':
sort_by = session['sort_by'] = topic_sort_by sort_by = session['sort_by'] = topic_sort_by

View File

@ -8,7 +8,7 @@
{% else %} {% else %}
<title>{{config.SITE_NAME}}</title> <title>{{config.SITE_NAME}}</title>
{% endif %} {% endif %}
<link rel="stylesheet" href="{{ "/static/css/style.css" | cachebust }}"> <link rel="stylesheet" href="{{ ("/static/css/%s.css" % get_prefers_theme()) | cachebust }}">
<link rel="icon" type="image/png" href="/static/favicon.png"> <link rel="icon" type="image/png" href="/static/favicon.png">
</head> </head>
<body> <body>

View File

@ -12,7 +12,7 @@
{% endif %} {% endif %}
<main> <main>
<nav class="darkbg"> <nav class="darkbg">
<h1 class="thread-title">{{ thread.title }}</h1> <h1 class="thread-title">{{ thread.title }}{% if unread_count is not none %} ({{ unread_count }} unread){% endif %}</h1>
<span>Posted in <a href="{{ url_for("topics.topic", slug=topic.slug) }}">{{ topic.name }}</a> <span>Posted in <a href="{{ url_for("topics.topic", slug=topic.slug) }}">{{ topic.name }}</a>
{% if thread.is_stickied %} {% if thread.is_stickied %}
&bullet; <i>stickied, so it's probably important</i> &bullet; <i>stickied, so it's probably important</i>

View File

@ -40,6 +40,9 @@
<div class="thread-info-container"> <div class="thread-info-container">
<span> <span>
<span class="thread-title"><a href="{{ url_for("threads.thread", slug=thread['slug']) }}">{{thread['title']}}</a></span> <span class="thread-title"><a href="{{ url_for("threads.thread", slug=thread['slug']) }}">{{thread['title']}}</a></span>
{% if thread['id'] in subscriptions %}
({{ subscriptions[thread['id']] }} unread)
{% endif %}
&bullet; &bullet;
Started by <a href="{{ url_for("users.page", username=thread['started_by']) }}">{{ thread['started_by'] }}</a> on {{ timestamp(thread['created_at'])}} Started by <a href="{{ url_for("users.page", username=thread['started_by']) }}">{{ thread['started_by'] }}</a> on {{ timestamp(thread['created_at'])}}
</span> </span>

View File

@ -15,6 +15,12 @@
</div> </div>
</form> </form>
<form method='post'> <form method='post'>
<label for='theme'>Theme (beta)</label>
<select autocomplete='off' id='theme' name='theme'>
{% for theme in config.allowed_themes %}
<option value="{{ theme }}" {{ 'selected' if get_prefers_theme() == theme }}>{{ theme | theme_name }}</option>
{% endfor %}
</select>
<label for='topic_sort_by'>Sort threads by:</label> <label for='topic_sort_by'>Sort threads by:</label>
<select id='topic_sort_by' name='topic_sort_by'> <select id='topic_sort_by' name='topic_sort_by'>
<option value='activity' {{ 'selected' if session['sort_by'] == 'activity' else '' }}>Latest activity</option> <option value='activity' {{ 'selected' if session['sort_by'] == 'activity' else '' }}>Latest activity</option>

View File

@ -145,6 +145,7 @@ a:visited {
align-items: center; align-items: center;
border-top: 1px solid black; border-top: 1px solid black;
border-bottom: 1px solid black; border-bottom: 1px solid black;
background-color: rgb(173.5214173228, 183.6737007874, 161.0262992126);
} }
.post-content { .post-content {
@ -249,6 +250,7 @@ pre code {
padding: 20px; padding: 20px;
min-width: 400px; min-width: 400px;
background-color: #c1ceb1; background-color: #c1ceb1;
color: black;
gap: 10px; gap: 10px;
} }
@ -462,6 +464,7 @@ input[type=text], input[type=password], textarea, select {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
resize: vertical; resize: vertical;
color: black;
background-color: rgb(217.8, 225.6, 208.2); background-color: rgb(217.8, 225.6, 208.2);
} }
input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus { input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus {
@ -472,12 +475,15 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus
border: 2px solid black; border: 2px solid black;
background-color: #81a3e6; background-color: #81a3e6;
padding: 20px 15px; padding: 20px 15px;
color: black;
} }
.infobox.critical { .infobox.critical {
background-color: rgb(237, 129, 129); background-color: #ed8181;
color: black;
} }
.infobox.warn { .infobox.warn {
background-color: #fbfb8d; background-color: #fbfb8d;
color: black;
} }
.infobox > span { .infobox > span {
@ -503,11 +509,13 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus
.thread-sticky-container { .thread-sticky-container {
grid-area: thread-sticky-container; grid-area: thread-sticky-container;
border: 2px outset rgb(217.26, 220.38, 213.42); border: 2px outset rgb(217.26, 220.38, 213.42);
background-color: none;
} }
.thread-locked-container { .thread-locked-container {
grid-area: thread-locked-container; grid-area: thread-locked-container;
border: 2px outset rgb(217.26, 220.38, 213.42); border: 2px outset rgb(217.26, 220.38, 213.42);
background-color: none;
} }
.contain-svg { .contain-svg {
@ -657,6 +665,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus
.topic-locked-container { .topic-locked-container {
grid-area: topic-locked-container; grid-area: topic-locked-container;
border: 2px outset rgb(217.26, 220.38, 213.42); border: 2px outset rgb(217.26, 220.38, 213.42);
background-color: none;
} }
.draggable-topic { .draggable-topic {

View File

@ -0,0 +1,909 @@
@font-face {
font-family: "site-title";
src: url("/static/fonts/ChicagoFLF.woff2");
}
@font-face {
font-family: "Cadman";
src: url("/static/fonts/Cadman_Roman.woff2");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "Cadman";
src: url("/static/fonts/Cadman_Bold.woff2");
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: "Cadman";
src: url("/static/fonts/Cadman_Italic.woff2");
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: "Cadman";
src: url("/static/fonts/Cadman_BoldItalic.woff2");
font-weight: bold;
font-style: italic;
}
.reaction-button.active, .tab-button, .currentpage, .pagebutton, input[type=file]::file-selector-button, button.warn, input[type=submit].warn, .linkbutton.warn, button.critical, input[type=submit].critical, .linkbutton.critical, button, input[type=submit], .linkbutton {
cursor: default;
font-size: 0.9em;
font-family: "Cadman";
text-decoration: none;
border: 1px solid black;
border-radius: 4px;
padding: 5px 20px;
margin: 10px 0;
}
body {
font-family: "Cadman";
margin: 20px 100px;
background-color: #220d16;
color: #e6e6e6;
}
a:link {
color: #e87fe1;
}
a:visited {
color: #ed4fb1;
}
.big {
font-size: 1.8rem;
}
#topnav {
padding: 10px;
margin: 0;
display: flex;
justify-content: end;
background-color: #303030;
justify-content: space-between;
align-items: baseline;
}
#bottomnav {
padding: 10px;
margin: 0;
display: flex;
justify-content: end;
background-color: #231c23;
}
.darkbg {
padding-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
background-color: #502d50;
}
.user-actions {
display: flex;
column-gap: 15px;
}
.site-title {
font-family: "site-title";
font-size: 3rem;
margin: 0 20px;
text-decoration: none;
color: white !important;
}
.thread-title {
margin: 0;
font-size: 1.5rem;
font-weight: bold;
}
.post {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: 1fr;
gap: 0;
grid-auto-flow: row;
grid-template-areas: "usercard post-content-container";
border: 2px outset rgb(96.95, 81.55, 96.95);
}
.usercard {
grid-area: usercard;
padding: 20px 10px;
border: 4px outset #503250;
background-color: #502d50;
border-right: solid 2px;
}
.usercard-inner {
display: flex;
flex-direction: column;
align-items: center;
top: 10px;
position: sticky;
}
.post-content-container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: min-content 1fr min-content;
gap: 0;
grid-auto-flow: row;
grid-template-areas: "post-info" "post-content" "post-reactions";
grid-area: post-content-container;
min-height: 100%;
}
.post-info {
grid-area: post-info;
display: flex;
min-height: 70px;
justify-content: space-between;
padding: 5px 20px;
align-items: center;
border-top: 1px solid black;
border-bottom: 1px solid black;
background-color: #412841;
}
.post-content {
grid-area: post-content;
padding: 20px 20px 0 20px;
display: flex;
flex-direction: column;
overflow: hidden;
background-color: #231c23;
}
.post-reactions {
grid-area: post-reactions;
min-height: 50px;
display: flex;
padding: 5px 20px;
align-items: center;
flex-wrap: wrap;
gap: 5px;
background-color: #503250;
border-top: 2px dotted gray;
}
.post-inner {
height: 100%;
padding-right: 25%;
}
.post-inner.wider {
padding-right: 12.5%;
}
.signature-container {
border-top: 2px dotted gray;
padding: 10px 0;
}
pre code {
display: block;
background-color: #302731;
font-size: 1rem;
color: white;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
border-left: 10px solid #ae6bae;
padding: 20px;
overflow: scroll;
tab-size: 4;
}
.copy-code-container {
position: sticky;
width: calc(100% - 4px);
display: flex;
justify-content: space-between;
align-items: last baseline;
font-family: "Cadman";
border-top-right-radius: 8px;
border-top-left-radius: 8px;
background-color: #9b649b;
border-left: 2px solid black;
border-right: 2px solid black;
border-top: 2px solid black;
}
.copy-code-container::before {
content: "code block";
font-style: italic;
margin-left: 10px;
}
.copy-code {
margin-right: 10px;
}
.inline-code {
background-color: #302731;
color: white;
padding: 5px 10px;
display: inline-block;
margin: 4px;
border-radius: 4px;
font-size: 1rem;
white-space: pre;
}
#delete-dialog, .lightbox-dialog {
padding: 0;
border-radius: 4px;
border: 2px solid black;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.25);
}
.delete-dialog-inner {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
.lightbox-inner {
display: flex;
flex-direction: column;
padding: 20px;
min-width: 400px;
background-color: #503250;
color: #e6e6e6;
gap: 10px;
}
.lightbox-image {
max-width: 70vw;
max-height: 70vh;
object-fit: scale-down;
}
.lightbox-nav {
display: flex;
justify-content: space-between;
align-items: center;
}
blockquote {
padding: 10px 20px;
margin: 10px;
border-radius: 4px;
border-left: 10px solid #ae6bae;
background-color: rgba(251, 175, 207, 0.0392156863);
}
.user-info {
display: grid;
grid-template-columns: 300px 1fr;
grid-template-rows: 1fr;
gap: 0;
grid-template-areas: "user-page-usercard user-page-stats";
}
.user-page-usercard {
grid-area: user-page-usercard;
padding: 20px 10px;
border: 4px outset #503250;
background-color: #502d50;
border-right: solid 2px;
}
.user-page-stats {
grid-area: user-page-stats;
padding: 20px 30px;
border: 1px solid black;
}
.user-stats-list {
list-style: none;
margin: 0 0 10px 0;
}
.user-page-posts {
border-left: 1px solid black;
border-right: 1px solid black;
border-bottom: 1px solid black;
background-color: #9b649b;
}
.user-page-post-preview {
max-height: 200px;
mask-image: linear-gradient(180deg, #000 60%, transparent);
}
.avatar {
width: 90%;
height: 90%;
object-fit: contain;
margin-bottom: 10px;
}
.username-link {
overflow-wrap: anywhere;
}
.user-status {
text-align: center;
}
button, input[type=submit], .linkbutton {
display: inline-block;
background-color: #3c283c;
color: #e6e6e6 !important;
}
button:hover, input[type=submit]:hover, .linkbutton:hover {
background-color: rgb(109.2, 72.8, 109.2);
}
button:active, input[type=submit]:active, .linkbutton:active {
background-color: rgb(47.7, 42.3, 47.7);
}
button:disabled, input[type=submit]:disabled, .linkbutton:disabled {
background-color: rgb(113.73, 109.27, 113.73);
}
button.reduced, input[type=submit].reduced, .linkbutton.reduced {
margin: 0;
padding: 5px;
}
button.critical, input[type=submit].critical, .linkbutton.critical {
background-color: #d53232;
color: #e6e6e6 !important;
}
button.critical:hover, input[type=submit].critical:hover, .linkbutton.critical:hover {
background-color: rgb(221.4, 91, 91);
}
button.critical:active, input[type=submit].critical:active, .linkbutton.critical:active {
background-color: rgb(141.7804251012, 94.9195748988, 94.9195748988);
}
button.critical:disabled, input[type=submit].critical:disabled, .linkbutton.critical:disabled {
background-color: rgb(174.255, 162.845, 162.845);
}
button.critical.reduced, input[type=submit].critical.reduced, .linkbutton.critical.reduced {
margin: 0;
padding: 5px;
}
button.warn, input[type=submit].warn, .linkbutton.warn {
background-color: #eaea6a;
color: black !important;
}
button.warn:hover, input[type=submit].warn:hover, .linkbutton.warn:hover {
background-color: rgb(238.2, 238.2, 135.8);
}
button.warn:active, input[type=submit].warn:active, .linkbutton.warn:active {
background-color: rgb(176.04, 176.04, 129.96);
}
button.warn:disabled, input[type=submit].warn:disabled, .linkbutton.warn:disabled {
background-color: rgb(199.98, 199.98, 191.02);
}
button.warn.reduced, input[type=submit].warn.reduced, .linkbutton.warn.reduced {
margin: 0;
padding: 5px;
}
input[type=file]::file-selector-button {
background-color: #3c283c;
color: #e6e6e6 !important;
margin: 10px;
}
input[type=file]::file-selector-button:hover {
background-color: rgb(109.2, 72.8, 109.2);
}
input[type=file]::file-selector-button:active {
background-color: rgb(47.7, 42.3, 47.7);
}
input[type=file]::file-selector-button:disabled {
background-color: rgb(113.73, 109.27, 113.73);
}
input[type=file]::file-selector-button.reduced {
margin: 0;
padding: 5px;
}
p {
margin: 15px 0;
}
.pagebutton {
background-color: #3c283c;
color: #e6e6e6 !important;
padding: 5px 5px;
margin: 0;
display: inline-block;
min-width: 20px;
text-align: center;
}
.pagebutton:hover {
background-color: rgb(109.2, 72.8, 109.2);
}
.pagebutton:active {
background-color: rgb(47.7, 42.3, 47.7);
}
.pagebutton:disabled {
background-color: rgb(113.73, 109.27, 113.73);
}
.pagebutton.reduced {
margin: 0;
padding: 5px;
}
.currentpage {
border: none;
padding: 5px 5px;
margin: 0;
display: inline-block;
min-width: 20px;
text-align: center;
}
.modform {
display: inline;
}
.login-container > * {
width: 40%;
margin: auto;
}
.settings-container > * {
width: 40%;
margin: auto;
}
.avatar-form {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px 0;
}
input[type=text], input[type=password], textarea, select {
border: 1px solid black;
border-radius: 4px;
padding: 7px 10px;
width: 100%;
box-sizing: border-box;
resize: vertical;
color: #e6e6e6;
background-color: #371e37;
}
input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus {
background-color: #514151;
}
.infobox {
border: 2px solid black;
background-color: #775891;
padding: 20px 15px;
color: #e6e6e6;
}
.infobox.critical {
background-color: #d53232;
color: #e6e6e6;
}
.infobox.warn {
background-color: #eaea6a;
color: black;
}
.infobox > span {
display: flex;
align-items: center;
}
.infobox-icon-container {
min-width: 60px;
padding-right: 15px;
}
.thread {
display: grid;
grid-template-columns: 96px 1.6fr 96px;
grid-template-rows: 1fr;
gap: 0;
grid-auto-flow: row;
min-height: 96px;
grid-template-areas: "thread-sticky-container thread-info-container thread-locked-container";
}
.thread-sticky-container {
grid-area: thread-sticky-container;
border: 2px outset #231c23;
background-color: #503250;
}
.thread-locked-container {
grid-area: thread-locked-container;
border: 2px outset #231c23;
background-color: #503250;
}
.contain-svg {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.contain-svg:not(.full) > svg, .contain-svg:not(.full) > img {
height: 50%;
width: 50%;
}
.contain-svg.full > svg, .contain-svg.full > img {
height: 100%;
width: 100%;
}
.post-img-container {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.post-image {
object-fit: contain;
max-width: 400px;
max-height: 400px;
min-width: 200px;
min-height: 200px;
flex: 1 1 0%;
width: auto;
height: auto;
}
.thread-info-container {
grid-area: thread-info-container;
background-color: #231c23;
padding: 5px 20px;
border-top: 1px solid black;
border-bottom: 1px solid black;
display: flex;
flex-direction: column;
overflow: hidden;
max-height: 110px;
mask-image: linear-gradient(180deg, #000 60%, transparent);
}
.thread-info-post-preview {
overflow: hidden;
text-overflow: ellipsis;
display: inline;
margin-right: 25%;
}
.babycode-guide-section {
background-color: #231c23;
padding: 5px 20px;
border: 1px solid black;
padding-right: 25%;
}
.babycode-guide-container {
display: grid;
grid-template-columns: 1.5fr 300px;
grid-template-rows: 1fr;
gap: 0;
grid-auto-flow: row;
grid-template-areas: "guide-topics guide-toc";
}
.guide-topics {
grid-area: guide-topics;
overflow: hidden;
}
.guide-toc {
grid-area: guide-toc;
position: sticky;
top: 100px;
align-self: start;
padding: 10px;
border-bottom-right-radius: 8px;
background-color: #3c233c;
border-right: 1px solid black;
border-top: 1px solid black;
border-bottom: 1px solid black;
}
.emoji-table tr td {
text-align: center;
}
.emoji-table tr th {
padding-left: 50px;
padding-right: 50px;
}
.emoji-table {
margin: auto;
}
.emoji-table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
.colorful-table {
border-collapse: collapse;
width: 100%;
margin: 10px 0;
overflow: hidden;
}
.colorful-table tr th {
background-color: #503250;
padding: 5px 0;
}
.colorful-table tr td {
background-color: #231c23;
padding: 5px 0;
text-align: center;
}
.colorful-table .small {
width: 250px;
}
.topic {
display: grid;
grid-template-columns: 1.5fr 96px;
grid-template-rows: 1fr;
gap: 0;
grid-auto-flow: row;
grid-template-areas: "topic-info-container topic-locked-container";
}
.topic-info-container {
grid-area: topic-info-container;
background-color: #231c23;
padding: 5px 20px;
border: 1px solid black;
display: flex;
flex-direction: column;
}
.topic-locked-container {
grid-area: topic-locked-container;
border: 2px outset #231c23;
background-color: #503250;
}
.draggable-topic {
cursor: pointer;
user-select: none;
background-color: #9b649b;
padding: 20px;
margin: 15px 0;
border-top: 5px outset #503250;
border-bottom: 5px outset rgb(96.95, 81.55, 96.95);
}
.draggable-topic.dragged {
background-color: #3c283c;
}
.editing {
background-color: #503250;
}
.context-explain {
margin: 20px 0;
display: flex;
justify-content: space-evenly;
}
.post-edit-form {
display: flex;
flex-direction: column;
align-items: baseline;
height: 100%;
}
.babycode-editor {
height: 150px;
font-size: 1rem;
}
.babycode-editor-container {
width: 100%;
}
.babycode-preview-errors-container {
font-size: 0.8rem;
}
.tab-button {
background-color: #3c283c;
color: #e6e6e6 !important;
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
margin-bottom: 0;
}
.tab-button:hover {
background-color: rgb(109.2, 72.8, 109.2);
}
.tab-button:active {
background-color: rgb(47.7, 42.3, 47.7);
}
.tab-button:disabled {
background-color: rgb(113.73, 109.27, 113.73);
}
.tab-button.reduced {
margin: 0;
padding: 5px;
}
.tab-button.active {
background-color: #8a5584;
padding-top: 8px;
}
.tab-content {
display: none;
}
.tab-content.active {
min-height: 250px;
display: block;
background-color: #503250;
border: 1px solid black;
padding: 10px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
}
ul, ol {
margin: 10px 0 10px 30px;
padding: 0;
}
.new-concept-notification.hidden {
display: none;
}
.new-concept-notification {
position: fixed;
bottom: 80px;
right: 80px;
border: 1px solid black;
background-color: #775891;
padding: 20px 15px;
border-radius: 4px;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.25);
}
.emoji {
max-width: 15px;
max-height: 15px;
}
.accordion {
border-top-right-radius: 4px;
border-top-left-radius: 4px;
box-sizing: border-box;
border: 1px solid black;
margin: 10px 5px;
overflow: hidden;
}
.accordion.hidden {
border-bottom: none;
}
.accordion-header {
display: flex;
align-items: center;
background-color: #7d467d;
padding: 0 10px;
gap: 10px;
border-bottom: 1px solid black;
}
.accordion-toggle {
padding: 0;
width: 36px;
height: 36px;
min-width: 36px;
min-height: 36px;
}
.accordion-title {
margin-right: auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.accordion-content {
padding: 0 15px;
}
.accordion-content.hidden {
display: none;
}
.post-accordion-content {
padding-top: 10px;
padding-bottom: 10px;
background-color: #2d212d;
}
.inbox-container {
padding: 10px;
}
.babycode-button-container {
display: flex;
gap: 5px;
flex-wrap: wrap;
}
.babycode-button {
padding: 5px 10px;
min-width: 36px;
}
.babycode-button > * {
font-size: 1rem;
}
.quote-popover {
position: absolute;
transform: translateX(-50%);
margin: 0;
border: none;
border-radius: 4px;
background-color: rgba(0, 0, 0, 0.5019607843);
padding: 5px 10px;
}
footer {
border-top: 1px solid black;
}
.reaction-button.active {
background-color: #8a5584;
color: #e6e6e6 !important;
}
.reaction-button.active:hover {
background-color: rgb(167.4843049327, 112.9156950673, 161.3067264574);
}
.reaction-button.active:active {
background-color: rgb(107.505, 93.195, 105.885);
}
.reaction-button.active:disabled {
background-color: rgb(156.9373766816, 152.1626233184, 156.396838565);
}
.reaction-button.active.reduced {
margin: 0;
padding: 5px;
}
.reaction-popover {
position: relative;
margin: 0;
border: none;
border-radius: 4px;
background-color: rgba(0, 0, 0, 0.5019607843);
padding: 5px 10px;
width: 250px;
}
.reaction-popover-inner {
display: flex;
flex-wrap: wrap;
overflow: scroll;
margin: auto;
justify-content: center;
}
.babycode-guide-list {
border-bottom: 1px dashed;
}
#topnav {
margin-bottom: 10px;
border: 10px solid rgb(40, 40, 40);
}
footer {
margin-top: 10px;
}

View File

@ -0,0 +1,929 @@
@font-face {
font-family: "site-title";
src: url("/static/fonts/ChicagoFLF.woff2");
}
@font-face {
font-family: "Cadman";
src: url("/static/fonts/Cadman_Roman.woff2");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "Cadman";
src: url("/static/fonts/Cadman_Bold.woff2");
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: "Cadman";
src: url("/static/fonts/Cadman_Italic.woff2");
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: "Cadman";
src: url("/static/fonts/Cadman_BoldItalic.woff2");
font-weight: bold;
font-style: italic;
}
.reaction-button.active, .tab-button, .currentpage, .pagebutton, input[type=file]::file-selector-button, button.warn, input[type=submit].warn, .linkbutton.warn, button.critical, input[type=submit].critical, .linkbutton.critical, button, input[type=submit], .linkbutton {
cursor: default;
font-size: 0.9em;
font-family: "Cadman";
text-decoration: none;
border: 1px solid black;
border-radius: 16px;
padding: 8px 12px;
margin: 6px 0;
}
body {
font-family: "Cadman";
margin: 12px 50px;
background-color: #c85d45;
color: black;
}
a:link {
color: black;
}
a:visited {
color: black;
}
.big {
font-size: 1.8rem;
}
#topnav {
padding: 6px;
margin: 0;
display: flex;
justify-content: end;
background-color: #f27a5a;
justify-content: space-between;
align-items: baseline;
}
#bottomnav {
padding: 6px;
margin: 0;
display: flex;
justify-content: end;
background-color: #88486d;
}
.darkbg {
padding-bottom: 6px;
padding-left: 6px;
padding-right: 6px;
background-color: #88486d;
}
.user-actions {
display: flex;
column-gap: 8px;
}
.site-title {
font-family: "site-title";
font-size: 3rem;
margin: 0 12px;
text-decoration: none;
color: black !important;
}
.thread-title {
margin: 0;
font-size: 1.5rem;
font-weight: bold;
}
.post {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: 1fr;
gap: 0;
grid-auto-flow: row;
grid-template-areas: "usercard post-content-container";
border: 2px outset rgb(155.8907865169, 93.2211235955, 76.5092134831);
}
.usercard {
grid-area: usercard;
padding: 12px 6px;
border: none;
background-color: #88486d;
border-right: none;
}
.usercard-inner {
display: flex;
flex-direction: column;
align-items: center;
top: 6px;
position: sticky;
}
.post-content-container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: min-content 1fr min-content;
gap: 0;
grid-auto-flow: row;
grid-template-areas: "post-info" "post-content" "post-reactions";
grid-area: post-content-container;
min-height: 100%;
}
.post-info {
grid-area: post-info;
display: flex;
min-height: 35px;
justify-content: space-between;
padding: 3px 12px;
align-items: center;
border-top: 1px solid black;
border-bottom: 1px solid black;
background-color: #c85d45;
}
.post-content {
grid-area: post-content;
padding: 12px 12px 0 12px;
display: flex;
flex-direction: column;
overflow: hidden;
background-color: #f27a5a;
}
.post-reactions {
grid-area: post-reactions;
min-height: 50px;
display: flex;
padding: 6px 12px;
align-items: center;
flex-wrap: wrap;
gap: 6px;
background-color: #c85d45;
border-top: 2px dotted #f7bfdf;
}
.post-inner {
height: 100%;
padding-right: 25%;
}
.post-inner.wider {
padding-right: 12.5%;
}
.signature-container {
border-top: 2px dotted #f7bfdf;
padding: 6px 0;
}
pre code {
display: block;
background-color: rgb(41.7051685393, 28.2759550562, 24.6948314607);
font-size: 1rem;
color: white;
border-bottom-right-radius: 16px;
border-bottom-left-radius: 16px;
border-left: 6px solid rgb(231.56, 212.36, 207.24);
padding: 12px;
overflow: scroll;
tab-size: 4;
}
.copy-code-container {
position: sticky;
width: calc(100% - 4px);
display: flex;
justify-content: space-between;
align-items: last baseline;
font-family: "Cadman";
border-top-right-radius: 16px;
border-top-left-radius: 16px;
background-color: #f27a5a;
border-left: 2px solid black;
border-right: 2px solid black;
border-top: 2px solid black;
}
.copy-code-container::before {
content: "code block";
font-style: italic;
margin-left: 6px;
}
.copy-code {
margin-right: 6px;
}
.inline-code {
background-color: rgb(41.7051685393, 28.2759550562, 24.6948314607);
color: white;
padding: 3px 6px;
display: inline-block;
margin: 4px;
border-radius: 16px;
font-size: 1rem;
white-space: pre;
}
#delete-dialog, .lightbox-dialog {
padding: 0;
border-radius: 16px;
border: 2px solid black;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.25);
}
.delete-dialog-inner {
display: flex;
flex-direction: column;
align-items: center;
padding: 12px;
}
.lightbox-inner {
display: flex;
flex-direction: column;
padding: 12px;
min-width: 400px;
background-color: #f27a5a;
color: black;
gap: 6px;
}
.lightbox-image {
max-width: 70vw;
max-height: 70vh;
object-fit: scale-down;
}
.lightbox-nav {
display: flex;
justify-content: space-between;
align-items: center;
}
blockquote {
padding: 6px 12px;
margin: 6px;
border-radius: 16px;
border-left: 6px solid rgb(231.56, 212.36, 207.24);
background-color: rgba(0, 0, 0, 0.1333333333);
}
.user-info {
display: grid;
grid-template-columns: 300px 1fr;
grid-template-rows: 1fr;
gap: 0;
grid-template-areas: "user-page-usercard user-page-stats";
}
.user-page-usercard {
grid-area: user-page-usercard;
padding: 12px 6px;
border: none;
background-color: #88486d;
border-right: none;
}
.user-page-stats {
grid-area: user-page-stats;
padding: 12px 16px;
border: 1px solid black;
}
.user-stats-list {
list-style: none;
margin: 0 0 6px 0;
}
.user-page-posts {
border-left: 1px solid black;
border-right: 1px solid black;
border-bottom: 1px solid black;
background-color: #f27a5a;
}
.user-page-post-preview {
max-height: 200px;
mask-image: linear-gradient(180deg, #000 60%, transparent);
}
.avatar {
width: 90%;
height: 90%;
object-fit: contain;
margin-bottom: 6px;
}
.username-link {
overflow-wrap: anywhere;
}
.user-status {
text-align: center;
}
button, input[type=submit], .linkbutton {
display: inline-block;
background-color: #f27a5a;
color: black !important;
}
button:hover, input[type=submit]:hover, .linkbutton:hover {
background-color: rgb(244.6, 148.6, 123);
}
button:active, input[type=submit]:active, .linkbutton:active {
background-color: rgb(176.4525842697, 133.7379775281, 122.3474157303);
}
button:disabled, input[type=submit]:disabled, .linkbutton:disabled {
background-color: rgb(198.02, 189.62, 187.38);
}
button.reduced, input[type=submit].reduced, .linkbutton.reduced {
margin: 0;
padding: 6px;
}
button.critical, input[type=submit].critical, .linkbutton.critical {
background-color: #f73030;
color: white !important;
}
button.critical:hover, input[type=submit].critical:hover, .linkbutton.critical:hover {
background-color: rgb(248.6, 89.4, 89.4);
}
button.critical:active, input[type=submit].critical:active, .linkbutton.critical:active {
background-color: rgb(166.6956976744, 98.8043023256, 98.8043023256);
}
button.critical:disabled, input[type=submit].critical:disabled, .linkbutton.critical:disabled {
background-color: rgb(186.715, 172.785, 172.785);
}
button.critical.reduced, input[type=submit].critical.reduced, .linkbutton.critical.reduced {
margin: 0;
padding: 6px;
}
button.warn, input[type=submit].warn, .linkbutton.warn {
background-color: #fbfb8d;
color: black !important;
}
button.warn:hover, input[type=submit].warn:hover, .linkbutton.warn:hover {
background-color: rgb(251.8, 251.8, 163.8);
}
button.warn:active, input[type=submit].warn:active, .linkbutton.warn:active {
background-color: rgb(198.3813559322, 198.3813559322, 154.4186440678);
}
button.warn:disabled, input[type=submit].warn:disabled, .linkbutton.warn:disabled {
background-color: rgb(217.55, 217.55, 209.85);
}
button.warn.reduced, input[type=submit].warn.reduced, .linkbutton.warn.reduced {
margin: 0;
padding: 6px;
}
input[type=file]::file-selector-button {
background-color: #f27a5a;
color: black !important;
margin: 6px;
}
input[type=file]::file-selector-button:hover {
background-color: rgb(244.6, 148.6, 123);
}
input[type=file]::file-selector-button:active {
background-color: rgb(176.4525842697, 133.7379775281, 122.3474157303);
}
input[type=file]::file-selector-button:disabled {
background-color: rgb(198.02, 189.62, 187.38);
}
input[type=file]::file-selector-button.reduced {
margin: 0;
padding: 6px;
}
p {
margin: 8px 0;
}
.pagebutton {
background-color: #f27a5a;
color: black !important;
padding: 3px 3px;
margin: 0;
display: inline-block;
min-width: 36px;
text-align: center;
}
.pagebutton:hover {
background-color: rgb(244.6, 148.6, 123);
}
.pagebutton:active {
background-color: rgb(176.4525842697, 133.7379775281, 122.3474157303);
}
.pagebutton:disabled {
background-color: rgb(198.02, 189.62, 187.38);
}
.pagebutton.reduced {
margin: 0;
padding: 6px;
}
.currentpage {
border: none;
padding: 3px 3px;
margin: 0;
display: inline-block;
min-width: 36px;
text-align: center;
}
.modform {
display: inline;
}
.login-container > * {
width: 60%;
margin: auto;
}
.settings-container > * {
width: 60%;
margin: auto;
}
.avatar-form {
display: flex;
flex-direction: column;
align-items: center;
padding: 12px 0;
}
input[type=text], input[type=password], textarea, select {
border: 1px solid black;
border-radius: 16px;
padding: 8px;
width: 100%;
box-sizing: border-box;
resize: vertical;
color: black;
background-color: rgb(247.2, 175.2, 156);
}
input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus {
background-color: rgb(249.8, 201.8, 189);
}
.infobox {
border: 2px solid black;
background-color: #81a3e6;
padding: 12px 8px;
color: black;
}
.infobox.critical {
background-color: #f73030;
color: white;
}
.infobox.warn {
background-color: #fbfb8d;
color: black;
}
.infobox > span {
display: flex;
align-items: center;
}
.infobox-icon-container {
min-width: 60px;
padding-right: 8px;
}
.thread {
display: grid;
grid-template-columns: 96px 1.6fr 96px;
grid-template-rows: 1fr;
gap: 0;
grid-auto-flow: row;
min-height: 96px;
grid-template-areas: "thread-sticky-container thread-info-container thread-locked-container";
}
.thread-sticky-container {
grid-area: thread-sticky-container;
border: 1px solid black;
background-color: #f27a5a;
}
.thread-locked-container {
grid-area: thread-locked-container;
border: 1px solid black;
background-color: #f27a5a;
}
.contain-svg {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.contain-svg:not(.full) > svg, .contain-svg:not(.full) > img {
height: 50%;
width: 50%;
}
.contain-svg.full > svg, .contain-svg.full > img {
height: 100%;
width: 100%;
}
.post-img-container {
display: flex;
flex-wrap: wrap;
gap: 3px;
}
.post-image {
object-fit: contain;
max-width: 400px;
max-height: 400px;
min-width: 200px;
min-height: 200px;
flex: 1 1 0%;
width: auto;
height: auto;
}
.thread-info-container {
grid-area: thread-info-container;
background-color: #f27a5a;
padding: 3px 12px;
border-top: 1px solid black;
border-bottom: 1px solid black;
display: flex;
flex-direction: column;
overflow: hidden;
max-height: 110px;
mask-image: linear-gradient(180deg, #000 60%, transparent);
}
.thread-info-post-preview {
overflow: hidden;
text-overflow: ellipsis;
display: inline;
margin-right: 25%;
}
.babycode-guide-section {
background-color: #f27a5a;
padding: 3px 12px;
border: 1px solid black;
padding-right: 25%;
}
.babycode-guide-container {
display: grid;
grid-template-columns: 1.5fr 300px;
grid-template-rows: 1fr;
gap: 0;
grid-auto-flow: row;
grid-template-areas: "guide-topics guide-toc";
}
.guide-topics {
grid-area: guide-topics;
overflow: hidden;
}
.guide-toc {
grid-area: guide-toc;
position: sticky;
top: 100px;
align-self: start;
padding: 6px;
border-bottom-right-radius: 8px;
background-color: #f27a5a;
border-right: 1px solid black;
border-top: 1px solid black;
border-bottom: 1px solid black;
}
.emoji-table tr td {
text-align: center;
}
.emoji-table tr th {
padding-left: 50px;
padding-right: 50px;
}
.emoji-table {
margin: auto;
}
.emoji-table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
.colorful-table {
border-collapse: collapse;
width: 100%;
margin: 6px 0;
overflow: hidden;
}
.colorful-table tr th {
background-color: #b54444;
padding: 3px 0;
}
.colorful-table tr td {
background-color: #f27a5a;
padding: 3px 0;
text-align: center;
}
.colorful-table .small {
width: 250px;
}
.topic {
display: grid;
grid-template-columns: 1.5fr 96px;
grid-template-rows: 1fr;
gap: 0;
grid-auto-flow: row;
grid-template-areas: "topic-info-container topic-locked-container";
}
.topic-info-container {
grid-area: topic-info-container;
background-color: #f27a5a;
padding: 3px 12px;
border: 1px solid black;
display: flex;
flex-direction: column;
}
.topic-locked-container {
grid-area: topic-locked-container;
border: 1px solid black;
background-color: #f27a5a;
}
.draggable-topic {
cursor: pointer;
user-select: none;
background-color: #f27a5a;
padding: 12px;
margin: 8px 0;
border-top: 5px outset rgb(219.84, 191.04, 183.36);
border-bottom: 5px outset rgb(155.8907865169, 93.2211235955, 76.5092134831);
}
.draggable-topic.dragged {
background-color: #f27a5a;
}
.editing {
background-color: rgb(219.84, 191.04, 183.36);
}
.context-explain {
margin: 12px 0;
display: flex;
justify-content: space-evenly;
}
.post-edit-form {
display: flex;
flex-direction: column;
align-items: baseline;
height: 100%;
}
.babycode-editor {
height: 150px;
font-size: 1rem;
}
.babycode-editor-container {
width: 100%;
}
.babycode-preview-errors-container {
font-size: 0.8rem;
}
.tab-button {
background-color: #f27a5a;
color: black !important;
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
margin-bottom: 0;
}
.tab-button:hover {
background-color: rgb(244.6, 148.6, 123);
}
.tab-button:active {
background-color: rgb(176.4525842697, 133.7379775281, 122.3474157303);
}
.tab-button:disabled {
background-color: rgb(198.02, 189.62, 187.38);
}
.tab-button.reduced {
margin: 0;
padding: 6px;
}
.tab-button.active {
background-color: #b54444;
padding-top: 8px;
}
.tab-content {
display: none;
}
.tab-content.active {
min-height: 250px;
display: block;
background-color: rgb(156.1, 92.9, 92.9);
border: 1px solid black;
padding: 6px;
border-top-right-radius: 16px;
border-bottom-right-radius: 16px;
border-bottom-left-radius: 16px;
}
ul, ol {
margin: 6px 0 6px 16px;
padding: 0;
}
.new-concept-notification.hidden {
display: none;
}
.new-concept-notification {
position: fixed;
bottom: 80px;
right: 80px;
border: 1px solid black;
background-color: #81a3e6;
padding: 12px 8px;
border-radius: 16px;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.25);
}
.emoji {
max-width: 15px;
max-height: 15px;
}
.accordion {
border-top-right-radius: 16px;
border-top-left-radius: 16px;
box-sizing: border-box;
border: 1px solid black;
margin: 6px 3px;
overflow: hidden;
}
.accordion.hidden {
border-bottom: none;
}
.accordion-header {
display: flex;
align-items: center;
background-color: #c6655b;
padding: 0 6px;
gap: 6px;
border-bottom: 1px solid black;
}
.accordion-toggle {
padding: 0;
width: 36px;
height: 36px;
min-width: 36px;
min-height: 36px;
}
.accordion-title {
margin-right: auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.accordion-content {
padding: 0 8px;
}
.accordion-content.hidden {
display: none;
}
.post-accordion-content {
padding-top: 6px;
padding-bottom: 6px;
background-color: #c85d45;
}
.inbox-container {
padding: 6px;
}
.babycode-button-container {
display: flex;
gap: 3px;
flex-wrap: wrap;
}
.babycode-button {
padding: 3px 6px;
min-width: 36px;
}
.babycode-button > * {
font-size: 1rem;
}
.quote-popover {
position: absolute;
transform: translateX(-50%);
margin: 0;
border: none;
border-radius: 16px;
background-color: rgba(0, 0, 0, 0.5019607843);
padding: 3px 6px;
}
footer {
border-top: 1px solid black;
}
.reaction-button.active {
background-color: #b54444;
color: white !important;
}
.reaction-button.active:hover {
background-color: rgb(197.978313253, 103.221686747, 103.221686747);
}
.reaction-button.active:active {
background-color: rgb(127.305, 96.795, 96.795);
}
.reaction-button.active:disabled {
background-color: rgb(167.7956024096, 159.5043975904, 159.5043975904);
}
.reaction-button.active.reduced {
margin: 0;
padding: 6px;
}
.reaction-popover {
position: relative;
margin: 0;
border: none;
border-radius: 16px;
background-color: rgba(0, 0, 0, 0.5019607843);
padding: 3px 6px;
width: 250px;
}
.reaction-popover-inner {
display: flex;
flex-wrap: wrap;
overflow: scroll;
margin: auto;
justify-content: center;
}
.babycode-guide-list {
border-bottom: 1px dashed;
}
#topnav {
border-top-left-radius: 16px;
border-top-right-radius: 16px;
}
#bottomnav {
border-bottom-left-radius: 16px;
border-bottom-right-radius: 16px;
color: white;
}
textarea {
padding: 12px 16px;
}
footer {
margin-top: 10px;
border-radius: 16px;
border: none;
text-align: center;
}
.darkbg {
color: white;
}
.darkbg a {
color: white;
}

View File

@ -144,20 +144,33 @@ document.addEventListener("DOMContentLoaded", () => {
document.body.appendChild(lightboxObj.dialog); document.body.appendChild(lightboxObj.dialog);
function setImageMaxSize(img) { function setImageMaxSize(img) {
const { maxWidth: origMaxWidth } = getComputedStyle(img); const {
if (img.naturalWidth >= parseInt(origMaxWidth)) { maxWidth: origMaxWidth,
return; maxHeight: origMaxHeight,
minWidth: origMinWidth,
minHeight: origMinHeight,
} = getComputedStyle(img);
console.log(img, img.naturalWidth, img.naturalHeight, origMinWidth, origMinHeight, origMaxWidth, origMaxHeight)
if (img.naturalWidth < parseInt(origMinWidth)) {
console.log(1)
img.style.minWidth = img.naturalWidth + "px";
}
if (img.naturalHeight < parseInt(origMinHeight)) {
console.log(2)
img.style.minHeight = img.naturalHeight + "px";
}
if (img.naturalWidth < parseInt(origMaxWidth)) {
console.log(3)
img.style.maxWidth = img.naturalWidth + "px";
}
if (img.naturalHeight < parseInt(origMaxHeight)) {
console.log(4)
img.style.maxHeight = img.naturalHeight + "px";
} }
img.style.maxWidth = img.naturalWidth + "px";
} }
const postImages = document.querySelectorAll(".post-inner img.post-image"); 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({
@ -171,6 +184,14 @@ document.addEventListener("DOMContentLoaded", () => {
openLightbox(belongingTo, idx); openLightbox(belongingTo, idx);
}); });
}); });
const postAndSigImages = document.querySelectorAll("img.post-image");
postAndSigImages.forEach(image => {
if (image.complete) {
setImageMaxSize(image);
} else {
image.addEventListener("load", () => setImageMaxSize(image));
}
})
// copy code blocks // copy code blocks
for (let button of document.querySelectorAll(".copy-code")) { for (let button of document.querySelectorAll(".copy-code")) {

View File

@ -23,6 +23,7 @@ $ACCORDION_COLOR: color.adjust($ACCENT_COLOR, $hue: 140, $lightness: -10%, $satu
$DEFAULT_FONT_COLOR: black !default; $DEFAULT_FONT_COLOR: black !default;
$DEFAULT_FONT_COLOR_INVERSE: white !default; $DEFAULT_FONT_COLOR_INVERSE: white !default;
$BUTTON_FONT_COLOR: $DEFAULT_FONT_COLOR !default;
$BUTTON_COLOR_WARN: #fbfb8d !default; $BUTTON_COLOR_WARN: #fbfb8d !default;
$BUTTON_COLOR_CRITICAL: red !default; $BUTTON_COLOR_CRITICAL: red !default;
$BUTTON_WARN_FONT_COLOR: $DEFAULT_FONT_COLOR !default; $BUTTON_WARN_FONT_COLOR: $DEFAULT_FONT_COLOR !default;
@ -258,6 +259,7 @@ $post_info_min_height: 70px !default;
$post_info_padding: $SMALL_PADDING $BIG_PADDING !default; $post_info_padding: $SMALL_PADDING $BIG_PADDING !default;
$post_info_border_top: $DEFAULT_BORDER !default; $post_info_border_top: $DEFAULT_BORDER !default;
$post_info_border_bottom: $DEFAULT_BORDER !default; $post_info_border_bottom: $DEFAULT_BORDER !default;
$post_info_background: $MAIN_BG !default;
.post-info { .post-info {
grid-area: post-info; grid-area: post-info;
display: flex; display: flex;
@ -267,6 +269,7 @@ $post_info_border_bottom: $DEFAULT_BORDER !default;
align-items: center; align-items: center;
border-top: $post_info_border_top; border-top: $post_info_border_top;
border-bottom: $post_info_border_bottom; border-bottom: $post_info_border_bottom;
background-color: $post_info_background;
} }
$post_content_padding: $BIG_PADDING $BIG_PADDING $ZERO_PADDING $BIG_PADDING !default; $post_content_padding: $BIG_PADDING $BIG_PADDING $ZERO_PADDING $BIG_PADDING !default;
@ -392,6 +395,7 @@ $delete_dialog_padding: $BIG_PADDING !default;
} }
$lightbox_background: $ACCENT_COLOR !default; $lightbox_background: $ACCENT_COLOR !default;
$lightbox_font_color: $DEFAULT_FONT_COLOR !default;
$lightbox_gap: $MEDIUM_PADDING !default; $lightbox_gap: $MEDIUM_PADDING !default;
$lightbox_inner_padding: $BIG_PADDING !default; $lightbox_inner_padding: $BIG_PADDING !default;
.lightbox-inner { .lightbox-inner {
@ -400,6 +404,7 @@ $lightbox_inner_padding: $BIG_PADDING !default;
padding: $lightbox_inner_padding; padding: $lightbox_inner_padding;
min-width: 400px; min-width: 400px;
background-color: $lightbox_background; background-color: $lightbox_background;
color: $lightbox_font_color;
gap: $lightbox_gap; gap: $lightbox_gap;
} }
@ -501,7 +506,7 @@ $avatar_margin_bottom: $MEDIUM_PADDING !default;
button, input[type="submit"], .linkbutton { button, input[type="submit"], .linkbutton {
display: inline-block; display: inline-block;
@include button($BUTTON_COLOR, $DEFAULT_FONT_COLOR); @include button($BUTTON_COLOR, $BUTTON_FONT_COLOR);
&.critical { &.critical {
@include button($BUTTON_COLOR_CRITICAL, $BUTTON_CRITICAL_FONT_COLOR); @include button($BUTTON_COLOR_CRITICAL, $BUTTON_CRITICAL_FONT_COLOR);
@ -514,7 +519,7 @@ button, input[type="submit"], .linkbutton {
// not sure why this one has to be separate, but if it's included in the rule above everything breaks // not sure why this one has to be separate, but if it's included in the rule above everything breaks
input[type="file"]::file-selector-button { input[type="file"]::file-selector-button {
@include button($BUTTON_COLOR, $DEFAULT_FONT_COLOR); @include button($BUTTON_COLOR, $BUTTON_FONT_COLOR);
margin: $MEDIUM_PADDING; margin: $MEDIUM_PADDING;
} }
@ -527,7 +532,7 @@ $pagebutton_padding: $SMALL_PADDING $SMALL_PADDING !default;
$pagebutton_margin: $ZERO_PADDING !default; $pagebutton_margin: $ZERO_PADDING !default;
$pagebutton_min_width: $BIG_PADDING !default; $pagebutton_min_width: $BIG_PADDING !default;
.pagebutton { .pagebutton {
@include button($BUTTON_COLOR, $DEFAULT_FONT_COLOR); @include button($BUTTON_COLOR, $BUTTON_FONT_COLOR);
padding: $pagebutton_padding; padding: $pagebutton_padding;
margin: $pagebutton_margin; margin: $pagebutton_margin;
display: inline-block; display: inline-block;
@ -574,6 +579,7 @@ $text_input_border_radius: $DEFAULT_BORDER_RADIUS !default;
$text_input_padding: 7px $MEDIUM_PADDING !default; $text_input_padding: 7px $MEDIUM_PADDING !default;
$text_input_background: color.scale($ACCENT_COLOR, $lightness: 40%) !default; $text_input_background: color.scale($ACCENT_COLOR, $lightness: 40%) !default;
$text_input_background_focus: color.scale($ACCENT_COLOR, $lightness: 60%) !default; $text_input_background_focus: color.scale($ACCENT_COLOR, $lightness: 60%) !default;
$text_input_font_color: $DEFAULT_FONT_COLOR !default;
input[type="text"], input[type="password"], textarea, select { input[type="text"], input[type="password"], textarea, select {
border: $text_input_border; border: $text_input_border;
border-radius: $text_input_border_radius; border-radius: $text_input_border_radius;
@ -581,6 +587,7 @@ input[type="text"], input[type="password"], textarea, select {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
resize: vertical; resize: vertical;
color: $text_input_font_color;
background-color: $text_input_background; background-color: $text_input_background;
&:focus { &:focus {
@ -589,21 +596,26 @@ input[type="text"], input[type="password"], textarea, select {
} }
$infobox_info_color: #81a3e6 !default; $infobox_info_color: #81a3e6 !default;
$infobox_critical_color: rgb(237, 129, 129) !default; $infobox_critical_color: #ed8181 !default;
$infobox_warn_color: #fbfb8d !default; $infobox_warn_color: #fbfb8d !default;
$infobox_border: 2px solid black !default; $infobox_border: 2px solid black !default;
$infobox_padding: $BIG_PADDING $MEDIUM_BIG_PADDING !default; $infobox_padding: $BIG_PADDING $MEDIUM_BIG_PADDING !default;
$infobox_info_font_color: $DEFAULT_FONT_COLOR !default;
$infobox_critical_font_color: $DEFAULT_FONT_COLOR !default;
$infobox_warn_font_color: $DEFAULT_FONT_COLOR !default;
.infobox { .infobox {
border: $infobox_border; border: $infobox_border;
background-color: $infobox_info_color; background-color: $infobox_info_color;
padding: $infobox_padding; padding: $infobox_padding;
color: $infobox_info_font_color;
&.critical { &.critical {
background-color: $infobox_critical_color; background-color: $infobox_critical_color;
color: $infobox_critical_font_color;
} }
&.warn { &.warn {
background-color: $infobox_warn_color; background-color: $infobox_warn_color;
color: $infobox_warn_font_color;
} }
} }
@ -633,14 +645,17 @@ $thread_column_gap: $ZERO_PADDING !default;
} }
$thread_locked_border: 2px outset $LIGHT !default; $thread_locked_border: 2px outset $LIGHT !default;
$thread_locked_background: none !default;
.thread-sticky-container { .thread-sticky-container {
grid-area: thread-sticky-container; grid-area: thread-sticky-container;
border: $thread_locked_border; border: $thread_locked_border;
background-color: $thread_locked_background;
} }
.thread-locked-container { .thread-locked-container {
grid-area: thread-locked-container; grid-area: thread-locked-container;
border: $thread_locked_border; border: $thread_locked_border;
background-color: $thread_locked_background;
} }
.contain-svg { .contain-svg {
@ -783,7 +798,7 @@ $colorful_table_tr_padding: $SMALL_PADDING $ZERO_PADDING !default;
$colorful_table_td_color: $BUTTON_COLOR !default; $colorful_table_td_color: $BUTTON_COLOR !default;
.colorful-table tr td { .colorful-table tr td {
background-color: $BUTTON_COLOR; background-color: $colorful_table_td_color;
padding: $colorful_table_tr_padding; padding: $colorful_table_tr_padding;
text-align: center; text-align: center;
} }
@ -818,9 +833,11 @@ $topic_info_border: $DEFAULT_BORDER !default;
} }
$topic_locked_border: $thread_locked_border !default; $topic_locked_border: $thread_locked_border !default;
$topic_locked_background: none !default;
.topic-locked-container { .topic-locked-container {
grid-area: topic-locked-container; grid-area: topic-locked-container;
border: $topic_locked_border; border: $topic_locked_border;
background-color: $topic_locked_background;
} }
$draggable_topic_background: $ACCENT_COLOR !default; $draggable_topic_background: $ACCENT_COLOR !default;
@ -878,7 +895,7 @@ $post_editing_context_margin: $BIG_PADDING $ZERO_PADDING !default;
$tab_button_color: $BUTTON_COLOR !default; $tab_button_color: $BUTTON_COLOR !default;
$tab_button_active_color: $BUTTON_COLOR_2 !default; $tab_button_active_color: $BUTTON_COLOR_2 !default;
$tab_button_font_color: $DEFAULT_FONT_COLOR !default; $tab_button_font_color: $BUTTON_FONT_COLOR !default;
.tab-button { .tab-button {
@include button($tab_button_color, $tab_button_font_color); @include button($tab_button_color, $tab_button_font_color);
border-bottom: none; border-bottom: none;
@ -1003,7 +1020,7 @@ $post_accordion_content_background: $MAIN_BG !default;
.post-accordion-content { .post-accordion-content {
padding-top: $post_accordion_content_padding_top; padding-top: $post_accordion_content_padding_top;
padding-bottom: $post_accordion_content_padding_bottom; padding-bottom: $post_accordion_content_padding_bottom;
background-color: $MAIN_BG; background-color: $post_accordion_content_background;
} }
$inbox_padding: $MEDIUM_PADDING !default; $inbox_padding: $MEDIUM_PADDING !default;
@ -1048,7 +1065,7 @@ footer {
} }
$reaction_button_active_color: $BUTTON_COLOR_2 !default; $reaction_button_active_color: $BUTTON_COLOR_2 !default;
$reaction_button_active_font_color: $DEFAULT_FONT_COLOR !default; $reaction_button_active_font_color: $BUTTON_FONT_COLOR !default;
.reaction-button.active { .reaction-button.active {
@include button($reaction_button_active_color, $reaction_button_active_font_color); @include button($reaction_button_active_color, $reaction_button_active_font_color);
} }

85
sass/otomotone.scss Normal file
View File

@ -0,0 +1,85 @@
$fc: #e6e6e6;
$fci: black;
$lightish_accent: #503250;
$lightish_accent2: #502d50;
$dark_accent: #231c23;
$warn: #eaea6a;
$crit: #d53232;
@use 'default' with (
$ACCENT_COLOR: #9b649b,
$MAIN_BG: #220d16,
$DARK_1: $lightish_accent2,
$DARK_3: #302731,
$LIGHT_2: #ae6bae,
$LIGHT: $lightish_accent,
$DEFAULT_FONT_COLOR: $fc,
$DEFAULT_FONT_COLOR_INVERSE: $fci,
$BUTTON_COLOR: #3c283c,
$BUTTON_COLOR_2: #8a5584,
$BUTTON_FONT_COLOR: $fc,
$BUTTON_COLOR_WARN: $warn,
$BUTTON_WARN_FONT_COLOR: $fci,
$BUTTON_COLOR_CRITICAL: $crit,
$BUTTON_CRITICAL_FONT_COLOR: $fc,
$ACCORDION_COLOR: #7d467d,
$bottomnav_color: $dark_accent,
$topic_info_background: $dark_accent,
$topic_locked_background: $lightish_accent,
$thread_locked_background: $lightish_accent,
$thread_locked_border: 2px outset $dark_accent,
$site_title_color: white,
$topnav_color: #303030,
$quote_background_color: #fbafcf0a,
$link_color: #e87fe1,
$link_color_visited: #ed4fb1,
$post_info_background: #412841,
$post_content_background: $dark_accent,
$thread_info_background_color: $dark_accent,
$post_reactions_background: $lightish_accent,
$post_accordion_content_background: #2d212d,
$babycode_guide_toc_background: #3c233c,
$babycode_guide_section_background: $dark_accent,
$text_input_background: #371e37,
$text_input_background_focus: #514151,
$text_input_font_color: $fc,
$colorful_table_th_color: $lightish_accent,
$colorful_table_td_color: $dark_accent,
$lightbox_background: $lightish_accent,
$infobox_info_color: #775891,
$infobox_warn_color: $warn,
$infobox_warn_font_color: $fci,
$infobox_critical_color: $crit,
$tab_content_background: $lightish_accent,
$tab_button_active_color: #8a5584,
);
#topnav {
margin-bottom: 10px;
border: 10px solid rgb(40, 40, 40);
}
footer {
margin-top: 10px;
}

97
sass/peachy.scss Normal file
View File

@ -0,0 +1,97 @@
// $accent: #dd5536;
$accent: #f27a5a;
$br: 16px;
@use 'default' with (
$ACCENT_COLOR: $accent,
$thread_locked_background: $accent,
$topic_locked_background: $accent,
// $DARK_1: #e36286,
$DARK_1: #88486d,
$MAIN_BG: #c85d45,
$usercard_border: none,
$usercard_border_right: none,
$thread_locked_border: 1px solid black,
$SETTINGS_WIDTH: 60%,
$PAGE_SIDE_MARGIN: 50px,
$link_color: black,
$link_color_visited: black,
$reaction_button_active_font_color: white,
// $DEFAULT_FONT_COLOR: white,
// $DEFAULT_FONT_COLOR_INVERSE: black,
$text_input_font_color: black,
$BUTTON_COLOR: $accent,
$BUTTON_COLOR_2: #b54444,
$BUTTON_COLOR_CRITICAL: #f73030,
$ACCORDION_COLOR: #c6655b,
$BUTTON_WARN_FONT_COLOR: black,
$BUTTON_CRITICAL_FONT_COLOR: white,
$SMALL_PADDING: 3px,
$MEDIUM_PADDING: 6px,
$MEDIUM_BIG_PADDING: 8px,
$BIG_PADDING: 12px,
$BIGGER_PADDING: 16px,
$DEFAULT_BORDER_RADIUS: $br,
$code_border_radius: $br,
$button_padding: 8px 12px,
$reduced_button_padding: 6px,
$post_reactions_border_top: 2px dotted #f7bfdf,
$post_info_min_height: 35px,
$post_reactions_padding: 6px 12px,
$post_reactions_gap: 6px,
$text_input_padding: 8px,
$infobox_info_color: #81a3e6,
$infobox_critical_color: #f73030,
$infobox_warn_color: #fbfb8d,
$infobox_info_font_color: black,
$infobox_critical_font_color: white,
$infobox_warn_font_color: black,
$pagebutton_min_width: 36px,
$quote_background_color: #0002,
);
#topnav {
border-top-left-radius: $br;
border-top-right-radius: $br;
}
#bottomnav {
border-bottom-left-radius: $br;
border-bottom-right-radius: $br;
color: white;
}
textarea {
padding: 12px 16px;
}
footer {
margin-top: 10px;
border-radius: $br;
border: none;
text-align: center;
}
.darkbg {
color: white;
& a {
color: white;
}
}