web: show list topics on site
parent
657b58c4ae
commit
6b2c88a44f
|
@ -2036,6 +2036,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
|
"stderrlog",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower",
|
"tower",
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub fn init_stderr_logging() {
|
||||||
INIT_STDERR_LOGGING.call_once(|| {
|
INIT_STDERR_LOGGING.call_once(|| {
|
||||||
stderrlog::new()
|
stderrlog::new()
|
||||||
.quiet(false)
|
.quiet(false)
|
||||||
.verbosity(15)
|
.verbosity(log::LevelFilter::Trace)
|
||||||
.show_module_names(true)
|
.show_module_names(true)
|
||||||
.timestamp(stderrlog::Timestamp::Millisecond)
|
.timestamp(stderrlog::Timestamp::Millisecond)
|
||||||
.init()
|
.init()
|
||||||
|
|
|
@ -7,9 +7,13 @@ async fn main() {
|
||||||
let config_path = std::env::args()
|
let config_path = std::env::args()
|
||||||
.nth(1)
|
.nth(1)
|
||||||
.expect("Expected configuration file path as first argument.");
|
.expect("Expected configuration file path as first argument.");
|
||||||
|
#[cfg(test)]
|
||||||
|
let verbosity = log::LevelFilter::Trace;
|
||||||
|
#[cfg(not(test))]
|
||||||
|
let verbosity = log::LevelFilter::Info;
|
||||||
stderrlog::new()
|
stderrlog::new()
|
||||||
.quiet(false)
|
.quiet(false)
|
||||||
.verbosity(15)
|
.verbosity(verbosity)
|
||||||
.show_module_names(true)
|
.show_module_names(true)
|
||||||
.timestamp(stderrlog::Timestamp::Millisecond)
|
.timestamp(stderrlog::Timestamp::Millisecond)
|
||||||
.init()
|
.init()
|
||||||
|
|
|
@ -34,6 +34,7 @@ percent-encoding = { version = "^2.1" }
|
||||||
rand = { version = "^0.8", features = ["min_const_gen"] }
|
rand = { version = "^0.8", features = ["min_const_gen"] }
|
||||||
serde = { version = "^1", features = ["derive", ] }
|
serde = { version = "^1", features = ["derive", ] }
|
||||||
serde_json = "^1"
|
serde_json = "^1"
|
||||||
|
stderrlog = "^0.5"
|
||||||
tempfile = { version = "^3.5" }
|
tempfile = { version = "^3.5" }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
tower-http = { version = "^0.3" }
|
tower-http = { version = "^0.3" }
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use chrono::TimeZone;
|
use chrono::TimeZone;
|
||||||
use mailpot::{Configuration, Connection};
|
use mailpot::{log, Configuration, Connection};
|
||||||
use mailpot_web::*;
|
use mailpot_web::*;
|
||||||
use minijinja::value::Value;
|
use minijinja::value::Value;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
@ -156,6 +156,17 @@ async fn main() {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
let verbosity = log::LevelFilter::Trace;
|
||||||
|
#[cfg(not(test))]
|
||||||
|
let verbosity = log::LevelFilter::Info;
|
||||||
|
stderrlog::new()
|
||||||
|
.quiet(false)
|
||||||
|
.verbosity(verbosity)
|
||||||
|
.show_module_names(true)
|
||||||
|
.timestamp(stderrlog::Timestamp::Millisecond)
|
||||||
|
.init()
|
||||||
|
.unwrap();
|
||||||
let conf = Configuration::from_file(config_path).unwrap();
|
let conf = Configuration::from_file(config_path).unwrap();
|
||||||
let app = create_app(new_state(conf));
|
let app = create_app(new_state(conf));
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
//! Utils for templates with the [`minijinja`] crate.
|
//! Utils for templates with the [`minijinja`] crate.
|
||||||
|
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
mod compressed;
|
mod compressed;
|
||||||
|
@ -150,6 +152,20 @@ impl Object for MailingList {
|
||||||
"unsubscription_mailto" => Ok(Value::from_serializable(
|
"unsubscription_mailto" => Ok(Value::from_serializable(
|
||||||
&self.inner.unsubscription_mailto(),
|
&self.inner.unsubscription_mailto(),
|
||||||
)),
|
)),
|
||||||
|
"topics" => {
|
||||||
|
let mut ul = String::new();
|
||||||
|
write!(&mut ul, r#"<ul class="tags inline">"#)?;
|
||||||
|
for topic in &self.topics {
|
||||||
|
write!(
|
||||||
|
&mut ul,
|
||||||
|
r#"<li class="tag" style="--red:110;--green:120;--blue:180;"><span class="tag-name">"#
|
||||||
|
)?;
|
||||||
|
write!(&mut ul, "{}", topic)?;
|
||||||
|
write!(&mut ul, r#"</span></li>"#)?;
|
||||||
|
}
|
||||||
|
write!(&mut ul, r#"</ul>"#)?;
|
||||||
|
Ok(Value::from_safe_string(ul))
|
||||||
|
}
|
||||||
_ => Err(Error::new(
|
_ => Err(Error::new(
|
||||||
minijinja::ErrorKind::UnknownMethod,
|
minijinja::ErrorKind::UnknownMethod,
|
||||||
format!("object has no method named {name}"),
|
format!("object has no method named {name}"),
|
||||||
|
|
|
@ -161,6 +161,7 @@
|
||||||
--code-foreground: #124;
|
--code-foreground: #124;
|
||||||
--code-background: #8fbcbb;
|
--code-background: #8fbcbb;
|
||||||
--a-visited-text: var(--a-normal-text);
|
--a-visited-text: var(--a-normal-text);
|
||||||
|
--tag-border-color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) {
|
@media (prefers-color-scheme: light) {
|
||||||
|
@ -237,6 +238,7 @@
|
||||||
--a-hover-bg: #bfbfbf40;
|
--a-hover-bg: #bfbfbf40;
|
||||||
--a-active-text: #c00;
|
--a-active-text: #c00;
|
||||||
--a-active-underline: #c00;
|
--a-active-underline: #c00;
|
||||||
|
--tag-border-color: #0000005e;
|
||||||
color-scheme: light;
|
color-scheme: light;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,6 +318,7 @@
|
||||||
--a-hover-bg: #bfbfbf40;
|
--a-hover-bg: #bfbfbf40;
|
||||||
--a-active-text: #c00;
|
--a-active-text: #c00;
|
||||||
--a-active-underline: #c00;
|
--a-active-underline: #c00;
|
||||||
|
--tag-border-color: #000;
|
||||||
|
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
}
|
}
|
||||||
|
@ -995,4 +998,49 @@
|
||||||
height:1px;
|
height:1px;
|
||||||
overflow:hidden;
|
overflow:hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<
|
||||||
|
ul.tags.inline {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tags {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: max-content;
|
||||||
|
vertical-align: baseline;
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 0.8ex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
--padding-top-bottom: 1px;
|
||||||
|
--padding-left-right: 5.4px;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid var(--tag-border-color);
|
||||||
|
border-radius:.2rem;
|
||||||
|
color: #555;
|
||||||
|
font-size: .9rem;
|
||||||
|
padding: 0px 0.4em 1px 0.4em;
|
||||||
|
padding: var(--padding-top-bottom) var(--padding-left-right);
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
--aa-brightness: ((var(--red) * 299) + (var(--green) * 587) + (var(--blue) * 114)) / 1000;
|
||||||
|
--aa-color: calc((var(--aa-brightness) - 128) * -1000);
|
||||||
|
background: rgb(var(--red), var(--green), var(--blue));
|
||||||
|
color: rgb(var(--aa-color), var(--aa-color), var(--aa-color));
|
||||||
|
min-width: max-content;
|
||||||
|
max-height: calc(1.5cap + var(--padding-top-bottom));
|
||||||
|
min-height: calc(1.5cap + var(--padding-top-bottom));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
span.tag-name a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<dl class="lists" aria-label="list of mailing lists">
|
<dl class="lists" aria-label="list of mailing lists">
|
||||||
{% for l in lists %}
|
{% for l in lists %}
|
||||||
<dt aria-label="mailing list name"><a href="{{ list_path(l.list.id) }}">{{ l.list.name }}</a></dt>
|
<dt aria-label="mailing list name"><a href="{{ list_path(l.list.id) }}">{{ l.list.name }}</a></dt>
|
||||||
<dd><span aria-label="mailing list description"{% if not l.list.description %} class="no-description"{% endif %}>{{ l.list.description if l.list.description else "no description" }}</span> | {{ l.posts|length }} post{{ l.posts|length|pluralize("","s") }}{% if l.newest %} | <time datetime="{{ l.newest }}">{{ l.newest }}</time>{% endif %}</dd>
|
<dd><span aria-label="mailing list description"{% if not l.list.description %} class="no-description"{% endif %}>{{ l.list.description if l.list.description else "no description" }}</span> | {{ l.posts|length }} post{{ l.posts|length|pluralize("","s") }}{% if l.newest %} | <time datetime="{{ l.newest }}">{{ l.newest }}</time>{% endif %}{% if l.list.topics|length > 0 %}<br aria-hidden="true"><br aria-hidden="true"><span><em>Topics</em>:</span> {{ l.list.topics() }}{% endif %}</dd>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
{% include "header.html" %}
|
{% include "header.html" %}
|
||||||
<div class="body">
|
<div class="body">
|
||||||
|
{% if list.topics|length > 0 %}<span><em>Topics</em>:</span> {{ list.topics() }}
|
||||||
|
<br aria-hidden="true">
|
||||||
|
<br aria-hidden="true">
|
||||||
|
{% endif %}
|
||||||
{% if list.description %}
|
{% if list.description %}
|
||||||
<p title="mailing list description">List description: {{ list.description }}</p>
|
<p title="mailing list description">List description: {{ list.description }}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
Loading…
Reference in New Issue