+48 -12 +/-4 browse
1 | diff --git a/web/src/templates/css.html b/web/src/templates/css.html |
2 | index f3bd033..5192df5 100644 |
3 | --- a/web/src/templates/css.html |
4 | +++ b/web/src/templates/css.html |
5 | @@ -763,6 +763,21 @@ |
6 | |
7 | dl.lists dt { |
8 | font-weight: bold; |
9 | + font-size: 1.2rem; |
10 | + padding-bottom: .3em; |
11 | + background: #88929d36; |
12 | + padding: .2rem .2rem; |
13 | + border-radius: .2rem; |
14 | + } |
15 | + |
16 | + dl.lists dd > * + * { |
17 | + margin-top: 1rem; |
18 | + } |
19 | + |
20 | + dl.lists dd .list-topics, |
21 | + dl.lists dd .list-posts-dates { |
22 | + display: block; |
23 | + width: 100%; |
24 | } |
25 | |
26 | dl.lists dl, |
27 | @@ -775,9 +790,10 @@ |
28 | margin-bottom: 1rem; |
29 | margin-block-start: 0.3rem; |
30 | margin-block-end: 1rem; |
31 | + line-height: 1.5; |
32 | } |
33 | |
34 | - dl.lists dd.no-description { |
35 | + dl.lists .no-description { |
36 | color: var(--text-faded); |
37 | } |
38 | |
39 | @@ -1061,4 +1077,9 @@ |
40 | border-inline-start: 1px solid var(--graphical-fg); |
41 | color: var(--muted-fg); |
42 | } |
43 | + |
44 | + time, .tabular-nums { |
45 | + font-family: var(--grotesque-system-stack); |
46 | + font-variant-numeric: tabular-nums slashed-zero; |
47 | + } |
48 | </style> |
49 | diff --git a/web/src/templates/lists.html b/web/src/templates/lists.html |
50 | index a6d5698..25656b1 100644 |
51 | --- a/web/src/templates/lists.html |
52 | +++ b/web/src/templates/lists.html |
53 | @@ -5,7 +5,7 @@ |
54 | <dl class="lists" aria-label="list of mailing lists"> |
55 | {% for l in lists %} |
56 | <dt aria-label="mailing list name"><a href="{{ list_path(l.list.id) }}">{{ l.list.name }}</a></dt> |
57 | - <dd><span aria-label="mailing list description"{% if not l.list.description %} class="no-description"{% endif %}>{{ l.list.description if l.list.description else "<p>no description</p>"|safe }}</span><br />{{ 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> |
58 | + <dd><span aria-label="mailing list description"{% if not l.list.description %} class="no-description"{% endif %}>{{ l.list.description if l.list.description else "<p>no description</p>"|safe }}</span><span class="list-posts-dates tabular-nums">{{ l.posts|length }} post{{ l.posts|length|pluralize("","s") }}{% if l.newest %} | <time datetime="{{ l.newest }}">{{ l.newest }}</time>{% endif %}</span>{% if l.list.topics|length > 0 %}<span class="list-topics"><span>Topics:</span> {{ l.list.topics() }}</span>{% endif %}</dd> |
59 | {% endfor %} |
60 | </dl> |
61 | </div> |
62 | diff --git a/web/src/templates/topics.html b/web/src/templates/topics.html |
63 | index cb5e38a..a34216c 100644 |
64 | --- a/web/src/templates/topics.html |
65 | +++ b/web/src/templates/topics.html |
66 | @@ -1,12 +1,13 @@ |
67 | {% include "header.html" %} |
68 | <div class="body"> |
69 | - <p>Results for <em>{{ term }}</em></p> |
70 | + <p style="margin-block-end: 1rem;">Results for <em>{{ term }}</em></p> |
71 | <div class="entry"> |
72 | - <ul> |
73 | - {% for r in results %} |
74 | - <li><a href="{{ list_path(r.pk) }}">{{ r.id }}</a>. {% if r.topics|length > 0 %}<br aria-hidden="true"><br aria-hidden="true"><span><em>Topics</em>:</span> {{ r.topics_html() }}{% endif %} |
75 | + <dl class="lists" aria-label="list of mailing lists"> |
76 | + {% for list in results %} |
77 | + <dt aria-label="mailing list name"><a href="{{ list_path(list.id) }}">{{ list.id }}</a></dt> |
78 | + <dd><span aria-label="mailing list description"{% if not list.description %} class="no-description"{% endif %}>{{ list.description if list.description else "<p>no description</p>"|safe }}</span>{% if list.topics|length > 0 %}<span class="list-topics"><span>Topics:</span> {{ list.topics_html() }}</span>{% endif %}</dd> |
79 | {% endfor %} |
80 | - </ul> |
81 | + </dl> |
82 | </div> |
83 | </div> |
84 | {% include "footer.html" %} |
85 | diff --git a/web/src/topics.rs b/web/src/topics.rs |
86 | index 5047e1b..13c2b9a 100644 |
87 | --- a/web/src/topics.rs |
88 | +++ b/web/src/topics.rs |
89 | @@ -28,6 +28,7 @@ pub struct SearchTerm { |
90 | pub struct SearchResult { |
91 | pk: i64, |
92 | id: String, |
93 | + description: Option<String>, |
94 | topics: Vec<String>, |
95 | } |
96 | |
97 | @@ -63,13 +64,19 @@ impl minijinja::value::StructObject for SearchResult { |
98 | match name { |
99 | "pk" => Some(Value::from_serializable(&self.pk)), |
100 | "id" => Some(Value::from_serializable(&self.id)), |
101 | + "description" => Some( |
102 | + self.description |
103 | + .clone() |
104 | + .map(Value::from_safe_string) |
105 | + .unwrap_or_else(|| Value::from_serializable(&self.description)), |
106 | + ), |
107 | "topics" => Some(Value::from_serializable(&self.topics)), |
108 | _ => None, |
109 | } |
110 | } |
111 | |
112 | fn static_fields(&self) -> Option<&'static [&'static str]> { |
113 | - Some(&["pk", "id", "topics"][..]) |
114 | + Some(&["pk", "id", "description", "topics"][..]) |
115 | } |
116 | } |
117 | pub async fn list_topics( |
118 | @@ -84,14 +91,20 @@ pub async fn list_topics( |
119 | let results: Vec<Value> = { |
120 | if let Some(term) = term.as_ref() { |
121 | let mut stmt = db.connection.prepare( |
122 | - "SELECT DISTINCT list.pk, list.id, list.topics FROM list, json_each(list.topics) \ |
123 | - WHERE json_each.value IS ?;", |
124 | + "SELECT DISTINCT list.pk, list.id, list.description, list.topics FROM list, \ |
125 | + json_each(list.topics) WHERE json_each.value IS ?;", |
126 | )?; |
127 | let iter = stmt.query_map([&term], |row| { |
128 | let pk = row.get(0)?; |
129 | let id = row.get(1)?; |
130 | - let topics = mailpot::models::MailingList::topics_from_json_value(row.get(2)?)?; |
131 | - Ok(Value::from_object(SearchResult { pk, id, topics })) |
132 | + let description = row.get(2)?; |
133 | + let topics = mailpot::models::MailingList::topics_from_json_value(row.get(3)?)?; |
134 | + Ok(Value::from_object(SearchResult { |
135 | + pk, |
136 | + id, |
137 | + description, |
138 | + topics, |
139 | + })) |
140 | })?; |
141 | let mut ret = vec![]; |
142 | for el in iter { |
143 | @@ -106,6 +119,7 @@ pub async fn list_topics( |
144 | .map(|l| SearchResult { |
145 | pk: l.pk, |
146 | id: l.id, |
147 | + description: l.description, |
148 | topics: l.topics, |
149 | }) |
150 | .map(Value::from_object) |