Author:
Hash:
Timestamp:
+1137 -15 +/-36 browse
Kevin Schoon [me@kevinschoon.com]
a4973e6b3eec73ebaee8d163347aad8633b45517
Fri, 02 May 2025 14:05:37 +0000 (2 months ago)
1 | diff --git a/Cargo.lock b/Cargo.lock |
2 | index de32164..a8737da 100644 |
3 | --- a/Cargo.lock |
4 | +++ b/Cargo.lock |
5 | @@ -172,6 +172,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" |
6 | checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" |
7 | |
8 | [[package]] |
9 | + name = "askama" |
10 | + version = "0.14.0" |
11 | + source = "registry+https://github.com/rust-lang/crates.io-index" |
12 | + checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" |
13 | + dependencies = [ |
14 | + "askama_derive", |
15 | + "itoa", |
16 | + "percent-encoding", |
17 | + "serde", |
18 | + "serde_json", |
19 | + ] |
20 | + |
21 | + [[package]] |
22 | + name = "askama_derive" |
23 | + version = "0.14.0" |
24 | + source = "registry+https://github.com/rust-lang/crates.io-index" |
25 | + checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" |
26 | + dependencies = [ |
27 | + "askama_parser", |
28 | + "basic-toml", |
29 | + "memchr", |
30 | + "proc-macro2", |
31 | + "quote", |
32 | + "rustc-hash 2.1.1", |
33 | + "serde", |
34 | + "serde_derive", |
35 | + "syn 2.0.100", |
36 | + ] |
37 | + |
38 | + [[package]] |
39 | + name = "askama_parser" |
40 | + version = "0.14.0" |
41 | + source = "registry+https://github.com/rust-lang/crates.io-index" |
42 | + checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" |
43 | + dependencies = [ |
44 | + "memchr", |
45 | + "serde", |
46 | + "serde_derive", |
47 | + "winnow", |
48 | + ] |
49 | + |
50 | + [[package]] |
51 | name = "async-convert" |
52 | version = "1.0.0" |
53 | source = "registry+https://github.com/rust-lang/crates.io-index" |
54 | @@ -359,6 +401,7 @@ name = "ayllu" |
55 | version = "0.2.1" |
56 | dependencies = [ |
57 | "anyhow", |
58 | + "askama", |
59 | "async-trait", |
60 | "axum", |
61 | "axum-extra", |
62 | @@ -581,6 +624,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" |
63 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" |
64 | |
65 | [[package]] |
66 | + name = "basic-toml" |
67 | + version = "0.1.10" |
68 | + source = "registry+https://github.com/rust-lang/crates.io-index" |
69 | + checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" |
70 | + dependencies = [ |
71 | + "serde", |
72 | + ] |
73 | + |
74 | + [[package]] |
75 | name = "bincode" |
76 | version = "1.3.3" |
77 | source = "registry+https://github.com/rust-lang/crates.io-index" |
78 | diff --git a/ayllu/Cargo.toml b/ayllu/Cargo.toml |
79 | index ab43c22..1f79949 100644 |
80 | --- a/ayllu/Cargo.toml |
81 | +++ b/ayllu/Cargo.toml |
82 | @@ -2,7 +2,7 @@ |
83 | name = "ayllu" |
84 | version = "0.2.1" |
85 | edition = "2021" |
86 | - rust-version = "1.70.0" |
87 | + rust-version = "1.86.0" |
88 | |
89 | [[bin]] |
90 | name = "ayllu" |
91 | @@ -57,6 +57,7 @@ include_dir = { version = "0.7.4", features = ["glob"] } |
92 | webfinger-rs = { version = "0.0.12", features = ["axum"] } |
93 | |
94 | quick-xml = { version = "0.37.5", features = ["encoding"] } |
95 | + askama = { version = "0.14.0" } |
96 | |
97 | [build-dependencies] |
98 | cc="*" |
99 | diff --git a/ayllu/src/web2/error.rs b/ayllu/src/web2/error.rs |
100 | index f0fce2c..86365f7 100644 |
101 | --- a/ayllu/src/web2/error.rs |
102 | +++ b/ayllu/src/web2/error.rs |
103 | @@ -62,3 +62,9 @@ impl From<IoError> for Error { |
104 | } |
105 | } |
106 | } |
107 | + |
108 | + impl From<askama::Error> for Error { |
109 | + fn from(value: askama::Error) -> Self { |
110 | + Error::Message(format!("Template Error: {:?}", value)) |
111 | + } |
112 | + } |
113 | diff --git a/ayllu/src/web2/mod.rs b/ayllu/src/web2/mod.rs |
114 | index e5ffca5..a40ff7c 100644 |
115 | --- a/ayllu/src/web2/mod.rs |
116 | +++ b/ayllu/src/web2/mod.rs |
117 | @@ -7,5 +7,6 @@ mod routes; |
118 | mod server; |
119 | mod terautil; |
120 | mod util; |
121 | + mod template; |
122 | |
123 | pub use server::serve; |
124 | diff --git a/ayllu/src/web2/routes/about.rs b/ayllu/src/web2/routes/about.rs |
125 | index 60dc0d0..0c0be6e 100644 |
126 | --- a/ayllu/src/web2/routes/about.rs |
127 | +++ b/ayllu/src/web2/routes/about.rs |
128 | @@ -1,28 +1,37 @@ |
129 | use comrak::{markdown_to_html_with_plugins, ComrakOptions, ComrakPlugins}; |
130 | - |
131 | use axum::{extract::Extension, response::Html}; |
132 | + use askama::Template; |
133 | |
134 | use crate::config::Config; |
135 | use crate::highlight::TreeSitterAdapter; |
136 | use crate::web2::error::Error; |
137 | - use crate::web2::middleware::template::Template; |
138 | + // use crate::web2::middleware::template::Template; |
139 | use crate::web2::navigation; |
140 | + use crate::web2::template::Options; |
141 | + |
142 | + #[derive(askama::Template)] |
143 | + #[template(path = "about.html")] |
144 | + struct Page { |
145 | + pub hello: String |
146 | + } |
147 | |
148 | pub async fn serve( |
149 | Extension(cfg): Extension<Config>, |
150 | Extension(adapter): Extension<TreeSitterAdapter>, |
151 | - Extension((templates, mut ctx)): Extension<Template>, |
152 | + Extension(opts): Extension<Options>, |
153 | ) -> Result<Html<String>, Error> { |
154 | - ctx.insert("title", "about"); |
155 | - ctx.insert( |
156 | - "nav_elements", |
157 | - &navigation::global("about", cfg.mail.is_some()), |
158 | - ); |
159 | - let options = ComrakOptions::default(); |
160 | - let mut plugins = ComrakPlugins::default(); |
161 | - plugins.render.codefence_syntax_highlighter = Some(&adapter); |
162 | - let blurb = markdown_to_html_with_plugins(&cfg.blurb, &options, &plugins); |
163 | - ctx.insert("blurb", &blurb); |
164 | - let body = templates.render("about.html", &ctx)?; |
165 | + let page = Page {hello: String::default()}; |
166 | + let x = page.render_with_values(&opts.values()); |
167 | + // ctx.insert("title", "about"); |
168 | + // ctx.insert( |
169 | + // "nav_elements", |
170 | + // &navigation::global("about", cfg.mail.is_some()), |
171 | + // ); |
172 | + // let options = ComrakOptions::default(); |
173 | + // let mut plugins = ComrakPlugins::default(); |
174 | + // plugins.render.codefence_syntax_highlighter = Some(&adapter); |
175 | + // let blurb = markdown_to_html_with_plugins(&cfg.blurb, &options, &plugins); |
176 | + // ctx.insert("blurb", &blurb); |
177 | + // let body = templates.render("about.html", &ctx)?; |
178 | Ok(Html(body)) |
179 | } |
180 | diff --git a/ayllu/src/web2/template.rs b/ayllu/src/web2/template.rs |
181 | new file mode 100644 |
182 | index 0000000..855f892 |
183 | --- /dev/null |
184 | +++ b/ayllu/src/web2/template.rs |
185 | @@ -0,0 +1,28 @@ |
186 | + use std::{any::Any, collections::HashMap}; |
187 | + |
188 | + use askama::Values; |
189 | + use serde::{Deserialize, Serialize}; |
190 | + |
191 | + /// top-level theme options available in all pages |
192 | + #[derive(Serialize, Deserialize, Debug, Default)] |
193 | + pub struct Options { |
194 | + pub origin: String, |
195 | + pub site_name: String, |
196 | + pub collection: Option<String>, |
197 | + pub name: Option<String>, |
198 | + pub url: String, |
199 | + pub path: String, |
200 | + pub fluid: bool, |
201 | + pub subpath_mode: bool, |
202 | + } |
203 | + |
204 | + impl Options { |
205 | + pub fn values(&self) -> impl Values { |
206 | + let mut values: HashMap<&str, Box<dyn Any>> = HashMap::new(); |
207 | + values.insert("origin", Box::new(self.origin.to_string())); |
208 | + values |
209 | + } |
210 | + } |
211 | + |
212 | + pub mod filters { |
213 | + } |
214 | diff --git a/ayllu/templates/404.html b/ayllu/templates/404.html |
215 | new file mode 100644 |
216 | index 0000000..ef22b82 |
217 | --- /dev/null |
218 | +++ b/ayllu/templates/404.html |
219 | @@ -0,0 +1,9 @@ |
220 | + {% extends "base.html" %} |
221 | + {% block content %} |
222 | + <section class="stretch"> |
223 | + <h1>Not Found ({{ status_code }})</h1> |
224 | + <p>Unable to find the resource you have requested, perhaps try looking somewhere else?</p> |
225 | + <h4>Error Message:</h4> |
226 | + <p>{{ error_message }}</p> |
227 | + </section> |
228 | + {% endblock %} |
229 | diff --git a/ayllu/templates/5xx.html b/ayllu/templates/5xx.html |
230 | new file mode 100644 |
231 | index 0000000..e0870d3 |
232 | --- /dev/null |
233 | +++ b/ayllu/templates/5xx.html |
234 | @@ -0,0 +1,9 @@ |
235 | + {% extends "base.html" %} |
236 | + {% block content %} |
237 | + <section class="strech"> |
238 | + <h1>Internal Service Error ({{ status_code }})</h1> |
239 | + <p>Something has gone wrong processing your request, please be patient.</p> |
240 | + <h4>Error Message:</h4> |
241 | + <p>{{ error_message }}</p> |
242 | + </section> |
243 | + {% endblock %} |
244 | diff --git a/ayllu/templates/about.html b/ayllu/templates/about.html |
245 | new file mode 100644 |
246 | index 0000000..652e78a |
247 | --- /dev/null |
248 | +++ b/ayllu/templates/about.html |
249 | @@ -0,0 +1,6 @@ |
250 | + {% extends "base.html" %} |
251 | + {% block content %} |
252 | + <section> |
253 | + <article>{{ blurb | safe }}</article> |
254 | + </section> |
255 | + {% endblock %} |
256 | diff --git a/ayllu/templates/authors.html b/ayllu/templates/authors.html |
257 | new file mode 100644 |
258 | index 0000000..1fe63c5 |
259 | --- /dev/null |
260 | +++ b/ayllu/templates/authors.html |
261 | @@ -0,0 +1,20 @@ |
262 | + {% extends "base.html" %} |
263 | + {% block content %} |
264 | + <header> |
265 | + <h1>Authors</h1> |
266 | + </header> |
267 | + {% for author in authors %} |
268 | + <article> |
269 | + <div class="wide"> |
270 | + <div> |
271 | + <a href="/{{ collection }}/{{ name }}/log?username={{ author.username | urlencode }}&email={{ author.email | urlencode }}">{{ author.username }}</a> |
272 | + </div> |
273 | + <div> |
274 | + <span class="positive">+{{ author.lines_added }}</span> |
275 | + <span class="negative">-{{ author.lines_removed }}</span> |
276 | + {{ author.percentage }}% ({{ author.count }}) |
277 | + </div> |
278 | + </div> |
279 | + </article> |
280 | + {% endfor %} |
281 | + {% endblock %} |
282 | diff --git a/ayllu/templates/badge.svg b/ayllu/templates/badge.svg |
283 | new file mode 100644 |
284 | index 0000000..895794b |
285 | --- /dev/null |
286 | +++ b/ayllu/templates/badge.svg |
287 | @@ -0,0 +1,29 @@ |
288 | + <svg xmlns="http://www.w3.org/2000/svg" |
289 | + xmlns:xlink="http://www.w3.org/1999/xlink" width="108" height="20" |
290 | + role="img" aria-label="{{key}}: {{value}}"> |
291 | + <title>{{key}}: {{value}}</title> |
292 | + <linearGradient id="s" x2="0" y2="100%"> |
293 | + <stop offset="0" stop-color="#bbb" stop-opacity=".1" /> |
294 | + <stop offset="1" stop-opacity=".1" /> |
295 | + </linearGradient> |
296 | + <clipPath id="r"> |
297 | + <rect width="108" height="20" rx="3" fill="#fff" /> |
298 | + </clipPath> |
299 | + <g clip-path="url(#r)"> |
300 | + <rect width="55" height="20" fill="#555" /> |
301 | + <rect x="55" width="53" height="20" fill="#007ec6" /> |
302 | + <rect width="108" height="20" fill="url(#s)" /> |
303 | + </g> |
304 | + <g fill="#fff" text-anchor="middle" |
305 | + font-family="monospace" |
306 | + text-rendering="geometricPrecision" font-size="110"> |
307 | + <text aria-hidden="true" x="285" y="150" fill="#010101" |
308 | + fill-opacity=".3" transform="scale(.1)" textLength="450">{{key}}</text> |
309 | + <text x="285" y="140" transform="scale(.1)" fill="#fff" |
310 | + textLength="450">{{key}}</text> |
311 | + <text aria-hidden="true" x="805" y="150" fill="#010101" |
312 | + fill-opacity=".3" transform="scale(.1)" textLength="430">{{value}}</text> |
313 | + <text x="805" y="140" transform="scale(.1)" fill="#fff" |
314 | + textLength="430">{{value}}</text> |
315 | + </g> |
316 | + </svg> |
317 | diff --git a/ayllu/templates/base.html b/ayllu/templates/base.html |
318 | new file mode 100644 |
319 | index 0000000..b71fcc3 |
320 | --- /dev/null |
321 | +++ b/ayllu/templates/base.html |
322 | @@ -0,0 +1,30 @@ |
323 | + <!DOCTYPE html> |
324 | + <html lang="en"> |
325 | + <meta name="description" content="{{ description }}"> |
326 | + <meta name="keywords" content="{{ keywords }}"> |
327 | + <head> |
328 | + <meta charset="utf-8"> |
329 | + <meta name="viewport" content="width=device-width, initial-scale=1"> |
330 | + <title> |
331 | + {% block title %}{{ title }}{% endblock %} |
332 | + </title> |
333 | + <link rel="stylesheet" href="/static/main.min.css" /> |
334 | + <link href="/static/logo.svg" rel="icon" type="image/svg+xml" /> |
335 | + {% block head %}{% endblock %} |
336 | + </head> |
337 | + <body> |
338 | + <!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1404468 --> |
339 | + <script>0</script> |
340 | + {% block navigation %} |
341 | + {% include "nav.html" %} |
342 | + {% endblock %} |
343 | + <main> |
344 | + <div class="container" style="max-width: {{ container_max_width }}"> |
345 | + {% block content %}{% endblock %} |
346 | + </div> |
347 | + </main> |
348 | + <footer> |
349 | + Rendered {%- if render_time %}in ({{ render_time }} ms){%- endif %} @ {{ current_time }} |
350 | + </footer> |
351 | + </body> |
352 | + </html> |
353 | diff --git a/ayllu/templates/blame.html b/ayllu/templates/blame.html |
354 | new file mode 100644 |
355 | index 0000000..7c80977 |
356 | --- /dev/null |
357 | +++ b/ayllu/templates/blame.html |
358 | @@ -0,0 +1,38 @@ |
359 | + {% import "macros.html" as macros %} |
360 | + {% extends "base.html" %} |
361 | + {% block content %} |
362 | + <section class="stretch"> |
363 | + <header> |
364 | + {{ macros::navigation(items=subnav_elements, title="Blame") }} |
365 | + </header> |
366 | + <section class="blame"> |
367 | + {% if is_renderable %} |
368 | + <article class="blame-left"> |
369 | + <table class="code"> |
370 | + <tbody> |
371 | + {%- for line in blame_lines -%} |
372 | + {%- set n_lines = line.end - line.start -%} |
373 | + <tr> |
374 | + <td> |
375 | + {{ line.author_name }} <a href="/{{ collection }}/{{ name }}/commit/{{ line.commit_id }}">{{ line.timestamp }}</a> |
376 | + </td> |
377 | + {%- for _ in range(end=n_lines-1) -%} |
378 | + <tr> |
379 | + <td> </td> |
380 | + <td></td> |
381 | + </tr> |
382 | + {%- endfor -%} |
383 | + </tr> |
384 | + {% endfor %} |
385 | + </tbody> |
386 | + </table> |
387 | + </article> |
388 | + <article class="blame-right">{{ content.1 | safe }}</article> |
389 | + {% else %} |
390 | + <article> |
391 | + <h2>This content is not blameable</h2> |
392 | + </article> |
393 | + {% endif %} |
394 | + </section> |
395 | + </section> |
396 | + {% endblock %} |
397 | diff --git a/ayllu/templates/blob.html b/ayllu/templates/blob.html |
398 | new file mode 100644 |
399 | index 0000000..e880df9 |
400 | --- /dev/null |
401 | +++ b/ayllu/templates/blob.html |
402 | @@ -0,0 +1,47 @@ |
403 | + {% import "macros.html" as macros %} |
404 | + {% extends "base.html" %} |
405 | + {% block content %} |
406 | + <section> |
407 | + {{ macros::navigation(items=subnav_elements, title="Blob") }} |
408 | + <section class="info-bar"> |
409 | + {%- if hint -%} |
410 | + <span class="hint" style="color: {{ color }}">{{ hint }}</span> |
411 | + {%- endif -%} |
412 | + <span>{{ file_name }}</span> |
413 | + <span class="right">{{ file_mode | filemode }} {{ file_size | human_bytes }}</span> |
414 | + </section> |
415 | + <div class="scrollable" style="max-width: {{ container_max_width }}"> |
416 | + {% if is_binary %} |
417 | + <div class="blob-preview"> |
418 | + {% if is_image %} |
419 | + <img height="1000px" |
420 | + width="1000px" |
421 | + alt="{{ file_name }}" |
422 | + src="{{ raw_url }}"> |
423 | + </img> |
424 | + {% elif is_video %} |
425 | + <video controls> |
426 | + <source src="{{ raw_url }}" type="{{ file_type }}" /> |
427 | + <p> |
428 | + <a href="{{ raw_url }}">raw url</a> |
429 | + </p> |
430 | + </video> |
431 | + {% elif is_audio %} |
432 | + <audio src="{{ raw_url }}" type="{{ file_type }}"></audio> |
433 | + {% else %} |
434 | + <center> |
435 | + <h3>Cannot render binary content</h3> |
436 | + </center> |
437 | + <a href="{{ raw_url }}">download</a> |
438 | + {% endif %} |
439 | + </div> |
440 | + {% else %} |
441 | + {% if is_markdown %} |
442 | + <div class="readme">{{ content | safe }}</div> |
443 | + {% else %} |
444 | + {{ content | safe }} |
445 | + {% endif %} |
446 | + {% endif %} |
447 | + </div> |
448 | + </section> |
449 | + {% endblock %} |
450 | diff --git a/ayllu/templates/build.html b/ayllu/templates/build.html |
451 | new file mode 100644 |
452 | index 0000000..b373e02 |
453 | --- /dev/null |
454 | +++ b/ayllu/templates/build.html |
455 | @@ -0,0 +1,31 @@ |
456 | + {% extends "base.html" %} |
457 | + {% block content %} |
458 | + <section> |
459 | + <article> |
460 | + <header> |
461 | + <h1>Build: {{ build.id }}</h1> |
462 | + </header> |
463 | + <table> |
464 | + <thead> |
465 | + <th>date</th> |
466 | + <th>runtime</th> |
467 | + <th>success</th> |
468 | + </thead> |
469 | + <tr> |
470 | + <td>{{ build.timestamp }}</td> |
471 | + <td>{{ build.runtime }}</td> |
472 | + <td>{{ build.success }}</td> |
473 | + </tr> |
474 | + </table> |
475 | + </article> |
476 | + {% for step in steps %} |
477 | + <article> |
478 | + <header> |
479 | + {{ step.0 }} |
480 | + </header> |
481 | + <code> {{ step.1 }} </code> |
482 | + <code> {{ step.2 }} </code> |
483 | + </article> |
484 | + {% endfor %} |
485 | + </section> |
486 | + {% endblock %} |
487 | diff --git a/ayllu/templates/builds.html b/ayllu/templates/builds.html |
488 | new file mode 100644 |
489 | index 0000000..4f83aaa |
490 | --- /dev/null |
491 | +++ b/ayllu/templates/builds.html |
492 | @@ -0,0 +1,28 @@ |
493 | + {% extends "base.html" %} |
494 | + {% block content %} |
495 | + <section> |
496 | + <article> |
497 | + <header> |
498 | + <h1>Builds</h1> |
499 | + </header> |
500 | + <table> |
501 | + <thead> |
502 | + <th>id</th> |
503 | + <th>date</th> |
504 | + <th>runtime</th> |
505 | + <th>success</th> |
506 | + </thead> |
507 | + {% for build in builds %} |
508 | + <tr> |
509 | + <td> |
510 | + <a href="/{{ collection }}/{{ name }}/builds/{{ build.id }}">{{ build.id }}</a> |
511 | + </td> |
512 | + <td>{{ build.timestamp }}</td> |
513 | + <td>{{ build.runtime }}</td> |
514 | + <td>{{ build.success }}</td> |
515 | + </tr> |
516 | + {% endfor %} |
517 | + </table> |
518 | + </article> |
519 | + </section> |
520 | + {% endblock %} |
521 | diff --git a/ayllu/templates/channel.html b/ayllu/templates/channel.html |
522 | new file mode 100644 |
523 | index 0000000..e49bdd7 |
524 | --- /dev/null |
525 | +++ b/ayllu/templates/channel.html |
526 | @@ -0,0 +1,27 @@ |
527 | + {% import "macros.html" as macros %} |
528 | + {% extends "base.html" %} |
529 | + {% block content %} |
530 | + <section> |
531 | + <article> |
532 | + <header> |
533 | + {{ macros::navigation(items=discnav, title=channel) }} |
534 | + </header> |
535 | + <table> |
536 | + <thead> |
537 | + <th>nick</th> |
538 | + <th>timestamp</th> |
539 | + <th>message</th> |
540 | + </thead> |
541 | + <tbody> |
542 | + {% for message in messages %} |
543 | + <tr> |
544 | + <td>{{ message.nickname }}</td> |
545 | + <td>{{ message.timestamp }}</td> |
546 | + <td>{{ message.body | escape }}</td> |
547 | + </tr> |
548 | + {% endfor %} |
549 | + </tbody> |
550 | + </table> |
551 | + </article> |
552 | + </section> |
553 | + {% endblock %} |
554 | diff --git a/ayllu/templates/channels.html b/ayllu/templates/channels.html |
555 | new file mode 100644 |
556 | index 0000000..8926e29 |
557 | --- /dev/null |
558 | +++ b/ayllu/templates/channels.html |
559 | @@ -0,0 +1,29 @@ |
560 | + {% import "macros.html" as macros %} |
561 | + {% extends "base.html" %} |
562 | + {% block content %} |
563 | + <section> |
564 | + <article> |
565 | + <header> |
566 | + {{ macros::navigation(items=discnav, title="XMPP Channels") }} |
567 | + </header> |
568 | + <table> |
569 | + <thead> |
570 | + <th>name</th> |
571 | + <th>online</th> |
572 | + <th>messages</th> |
573 | + </thead> |
574 | + <tbody> |
575 | + {% for channel in channels %} |
576 | + <tr> |
577 | + <td> |
578 | + <a href="/discuss/xmpp/{{ channel.name }}">{{ channel.name }}</a> |
579 | + </td> |
580 | + <td>{{ channel.n_users }}</td> |
581 | + <td>{{ channel.n_messages }}</td> |
582 | + </tr> |
583 | + {% endfor %} |
584 | + </tbody> |
585 | + </table> |
586 | + </article> |
587 | + </section> |
588 | + {% endblock %} |
589 | diff --git a/ayllu/templates/chart.html b/ayllu/templates/chart.html |
590 | new file mode 100644 |
591 | index 0000000..b8f2b26 |
592 | --- /dev/null |
593 | +++ b/ayllu/templates/chart.html |
594 | @@ -0,0 +1,10 @@ |
595 | + {% import "macros.html" as macros %} |
596 | + {% extends "base.html" %} |
597 | + {% block content %} |
598 | + <section> |
599 | + {{ macros::navigation(items=chartnav, title=chart_title) }} |
600 | + <section class="viewer"> |
601 | + {{ chart | safe }} |
602 | + </section> |
603 | + </section> |
604 | + {% endblock %} |
605 | diff --git a/ayllu/templates/collection.html b/ayllu/templates/collection.html |
606 | new file mode 100644 |
607 | index 0000000..b86aabf |
608 | --- /dev/null |
609 | +++ b/ayllu/templates/collection.html |
610 | @@ -0,0 +1,35 @@ |
611 | + {% extends "base.html" %} |
612 | + {% block content %} |
613 | + <section class="column"> |
614 | + <header> |
615 | + <h1> |
616 | + <a href="/{{ collection.name }}">{{ collection.name }}</a> |
617 | + {%- if is_hidden %} <span class="negative">[hidden]</span> {%- endif -%} |
618 | + </h1> |
619 | + {{ collection.description }} |
620 | + </header> |
621 | + <table> |
622 | + <thead> |
623 | + <tr> |
624 | + <th>Name</th> |
625 | + <th>Description</th> |
626 | + <th class="collapse">Last Updated</th> |
627 | + </tr> |
628 | + </thead> |
629 | + <tbody> |
630 | + {% for repo in repositories %} |
631 | + <tr> |
632 | + <td> |
633 | + <div class="name"> |
634 | + <a href="/{{ collection.name }}/{{ repo.name }}">{{ repo.name }}</a> |
635 | + {%- if repo.is_mirror %} <span class="tiny-highlight">[mirror]</span> {%- endif -%} |
636 | + </div> |
637 | + </td> |
638 | + <td>{{ repo.description }}</td> |
639 | + <td>{{ repo.age }}</td> |
640 | + </tr> |
641 | + {% endfor %} |
642 | + </tbody> |
643 | + </table> |
644 | + </section> |
645 | + {% endblock %} |
646 | diff --git a/ayllu/templates/commit.html b/ayllu/templates/commit.html |
647 | new file mode 100644 |
648 | index 0000000..33dfb78 |
649 | --- /dev/null |
650 | +++ b/ayllu/templates/commit.html |
651 | @@ -0,0 +1,66 @@ |
652 | + {% extends "base.html" %} |
653 | + {% import "macros.html" as macros %} |
654 | + {% block content %} |
655 | + <section> |
656 | + <h5>Commit</h5> |
657 | + <section> |
658 | + <span><b>Author:</b></span> |
659 | + <span class="right"> |
660 | + <a href="/{{ collection }}/{{ name }}/log?username={{ commit.author_name | urlencode }}&email={{ commit.author_email | urlencode }}">{{ commit.author_name }}</a> |
661 | + [<a href="mailto://{{ commit.author_email }}">{{ commit.author_email }}</a>] |
662 | + </span> |
663 | + </section> |
664 | + {% if distinct_author %} |
665 | + <section> |
666 | + <span><b>Committer:</b></span> |
667 | + <span class="right"> |
668 | + <a href="#">{{ commit.committer_name }}</a> |
669 | + [<a href="mailto://{{ commit.committer_email }}">{{ commit.committer_email }}</a>] |
670 | + {{ commit.committer_epoch | format_epoch }} |
671 | + </span> |
672 | + </section> |
673 | + {% endif %} |
674 | + <section> |
675 | + <span><b>Hash:</b></span> |
676 | + <span class="right {% if commit.is_verified -%} positive {%- else -%} negative {%- endif -%}">{{ commit.id }}</span> |
677 | + </section> |
678 | + <section> |
679 | + <span><b>Timestamp:</b></span> |
680 | + <span class="right">{{ commit.author_epoch | format_epoch }} ({{ commit.epoch | friendly_time }})</span> |
681 | + </section> |
682 | + <br /> |
683 | + <span class="positive">+{{ stats.insertions }}</span> |
684 | + <span class="negative">-{{ stats.deletions }}</span> |
685 | + <span>+/-{{ stats.files_changed }}</span> |
686 | + <span> |
687 | + <a href="/{{ collection }}/{{ name }}/tree/{{ commit_hash }}" |
688 | + role="button">browse</a> |
689 | + </span> |
690 | + <section> |
691 | + <b>{{ commit.summary }}</b> |
692 | + {% if extended_commit_message %} |
693 | + <div class="message"> |
694 | + <pre>{{ commit.message }}</pre> |
695 | + </div> |
696 | + {% endif %} |
697 | + {% if commit.has_note %} |
698 | + <h5>Note</h5> |
699 | + <section> |
700 | + <span><b>Author:</b></span> |
701 | + <span class="right"> |
702 | + <a href="/{{ collection }}/{{ name }}/log?username={{ note.author_name | urlencode }}&email={{ note.author_email | urlencode }}">{{ note.author_name }}</a> |
703 | + [<a href="mailto://{{ note.author_email }}">{{ commit.author_email }}</a>] |
704 | + </span> |
705 | + </section> |
706 | + <section> |
707 | + <span><b>Timestamp:</b></span> |
708 | + <span class="right">{{ note.author_epoch | format_epoch }} ({{ note.author_epoch | friendly_time }})</span> |
709 | + </section> |
710 | + <div class="message"> |
711 | + <pre>{{ note.message }}</pre> |
712 | + </div> |
713 | + {% endif %} |
714 | + </section> |
715 | + <div class="scrollable">{{ diff.1 | safe }}</div> |
716 | + </section> |
717 | + {% endblock %} |
718 | diff --git a/ayllu/templates/config.html b/ayllu/templates/config.html |
719 | new file mode 100644 |
720 | index 0000000..091630d |
721 | --- /dev/null |
722 | +++ b/ayllu/templates/config.html |
723 | @@ -0,0 +1,44 @@ |
724 | + {% extends "base.html" %} |
725 | + {% block content %} |
726 | + <section class="config-panel"> |
727 | + <header> |
728 | + <h1>Site Configuration</h1> |
729 | + </header> |
730 | + <form action="/config" method="post"> |
731 | + <label for="theme"> |
732 | + <h3>items-per-page</h3> |
733 | + </label> |
734 | + <select id="items_per_page" name="items_per_page" required> |
735 | + <option value="50" |
736 | + {%- if config.items_per_page == 50 -%} |
737 | + selected |
738 | + {%- endif -%}>50</option> |
739 | + <option value="100" |
740 | + {%- if config.items_per_page == 100 -%} |
741 | + selected |
742 | + {%- endif -%}>100</option> |
743 | + <option value="150" |
744 | + {%- if config.items_per_page == 150 -%} |
745 | + selected |
746 | + {%- endif -%}>150</option> |
747 | + <option value="200" |
748 | + {%- if config.items_per_page == 200 -%} |
749 | + selected |
750 | + {%- endif -%}>200</option> |
751 | + </select> |
752 | + <label for="theme"> |
753 | + <h3>theme</h3> |
754 | + </label> |
755 | + <select id="theme" name="theme" required> |
756 | + {% for theme in themes %} |
757 | + <option value="{{ theme }}" |
758 | + {%- if theme == config.theme -%} |
759 | + selected |
760 | + {%- endif -%}>{{ theme }}</option> |
761 | + {% endfor %} |
762 | + </select> |
763 | + <!-- Button --> |
764 | + <button type="submit">Submit</button> |
765 | + </form> |
766 | + </section> |
767 | + {% endblock %} |
768 | diff --git a/ayllu/templates/index.html b/ayllu/templates/index.html |
769 | new file mode 100644 |
770 | index 0000000..c316623 |
771 | --- /dev/null |
772 | +++ b/ayllu/templates/index.html |
773 | @@ -0,0 +1,46 @@ |
774 | + {% extends "base.html" %} |
775 | + {% block content %} |
776 | + <section id="index"> |
777 | + <section> |
778 | + <header> |
779 | + <h2>Collections</h2> |
780 | + <div class="rss-links"> |
781 | + {{ "feed.svg" | emoji | safe }} |
782 | + <p> |
783 | + [<a href="/rss/firehose.xml">*</a>, |
784 | + <a href="/rss/1d.xml">1d</a>, |
785 | + <a href="/rss/1w.xml">1w</a>, |
786 | + <a href="/rss/1m.xml">1m</a>] |
787 | + </p> |
788 | + </div> |
789 | + </header> |
790 | + </section> |
791 | + <section class="scrollable"> |
792 | + <table class="data-table"> |
793 | + {% for collection in collections %} |
794 | + <tbody id="{{ collection.name }}"> |
795 | + <tr class="group-label"> |
796 | + <th colspan="3"> |
797 | + <a class="collection" href="/{{ collection.name }}">{{ collection.name }}</a> |
798 | + </br> |
799 | + {{ collection.description }} |
800 | + </th> |
801 | + </tr> |
802 | + {% for repo in collection.repositories %} |
803 | + <tr> |
804 | + <td> |
805 | + <div class="name"> |
806 | + <a href="/{{ collection.name }}/{{ repo.name }}">{{ repo.name }}</a> |
807 | + {%- if repo.is_mirror %} <span class="tiny-highlight">[mirror]</span> {%- endif -%} |
808 | + </div> |
809 | + </td> |
810 | + <td>{{ repo.description | truncate(length=50, end="...") }}</td> |
811 | + <td>{{ repo.age }}</td> |
812 | + </tr> |
813 | + {% endfor %} |
814 | + </tbody> |
815 | + {% endfor %} |
816 | + </table> |
817 | + </section> |
818 | + </section> |
819 | + {% endblock %} |
820 | diff --git a/ayllu/templates/lists.html b/ayllu/templates/lists.html |
821 | new file mode 100644 |
822 | index 0000000..7075000 |
823 | --- /dev/null |
824 | +++ b/ayllu/templates/lists.html |
825 | @@ -0,0 +1,27 @@ |
826 | + {% import "macros.html" as macros %} |
827 | + {% extends "base.html" %} |
828 | + {% block content %} |
829 | + <h1>Mailing Lists</h1> |
830 | + <section> |
831 | + <table class="data-table"> |
832 | + <thead> |
833 | + <tr> |
834 | + <th>Name</th> |
835 | + <th>Description</th> |
836 | + <th>Address</th> |
837 | + </tr> |
838 | + </thead> |
839 | + <tbody> |
840 | + {% for list in lists %} |
841 | + <tr> |
842 | + <td> |
843 | + <a href="/mail/{{ list.name }}">{{ list.name }} [{{ list.address }}]</a> |
844 | + </td> |
845 | + <td>{{ list.description }}</td> |
846 | + <td>{{ list.address }}</td> |
847 | + </tr> |
848 | + {% endfor %} |
849 | + </tbody> |
850 | + </table> |
851 | + </section> |
852 | + {% endblock %} |
853 | diff --git a/ayllu/templates/log.html b/ayllu/templates/log.html |
854 | new file mode 100644 |
855 | index 0000000..0e1cd1a |
856 | --- /dev/null |
857 | +++ b/ayllu/templates/log.html |
858 | @@ -0,0 +1,46 @@ |
859 | + {% import "macros.html" as macros %} |
860 | + {% extends "base.html" %} |
861 | + {% block content %} |
862 | + <section> |
863 | + <h1>Log</h1> |
864 | + </section> |
865 | + <section class="scrollable"> |
866 | + <table class="data-table"> |
867 | + <thead> |
868 | + <tr> |
869 | + <th>ID</th> |
870 | + <th>Flags</th> |
871 | + <th>Age</th> |
872 | + <th class="collapse">Author</th> |
873 | + <th>Message</th> |
874 | + </tr> |
875 | + </thead> |
876 | + <tbody> |
877 | + {% for commit in commits %} |
878 | + <tr> |
879 | + <td> |
880 | + <span class="{%- if commit.is_verified -%}positive{%- else -%}negative {%- endif -%}"> |
881 | + <a href="/{{ collection }}/{{ name }}/commit/{{ commit.id }}">{{ commit.id | truncate(length=12, end="") }}</a> |
882 | + </span> |
883 | + </td> |
884 | + <td> |
885 | + {% if commit.has_note %}<div data-tooltip="Note">[N]</div>{% endif %} |
886 | + {% if commit.is_extended %}<div data-tooltip="Extended Commit">[E]</div>{% endif %} |
887 | + </td> |
888 | + <td>{{ commit.epoch | friendly_time }}</td> |
889 | + <td class="collapse"> |
890 | + <a href="/{{ collection }}/{{ name }}/log?username={{ commit.author_name | urlencode }}&email={{ commit.author_email | urlencode }}">{{ commit.author_name }}</a> |
891 | + </td> |
892 | + <td>{{ commit.summary | truncate(length=85, end="...") }}</td> |
893 | + </tr> |
894 | + {% endfor %} |
895 | + </tbody> |
896 | + </table> |
897 | + {% if has_more %} |
898 | + <footer class="pagination"> |
899 | + {%- set last_commit = commits | last -%} |
900 | + <span class="right"><a href="/{{ collection }}/{{ name }}/log/{{ last_commit.id }}"><b>next</b></a></span> |
901 | + </footer> |
902 | + {% endif %} |
903 | + </section> |
904 | + {% endblock %} |
905 | diff --git a/ayllu/templates/macros.html b/ayllu/templates/macros.html |
906 | new file mode 100644 |
907 | index 0000000..4d07b8c |
908 | --- /dev/null |
909 | +++ b/ayllu/templates/macros.html |
910 | @@ -0,0 +1,16 @@ |
911 | + {% macro navigation(items, title="") %} |
912 | + <nav class="subnav"> |
913 | + <ul> |
914 | + <h4>{{ title }}</h4> |
915 | + </ul> |
916 | + <ul> |
917 | + {% for item in items %} |
918 | + <li {% if item.2 %}class="active"{% endif %}> |
919 | + <a href="{{ item.1 }}">{{ item.0 }}</a> |
920 | + </li> |
921 | + {% endfor %} |
922 | + </ul> |
923 | + </nav> |
924 | + {% endmacro navigation %} |
925 | + {% macro commit_badge(commit, extended=false) %} |
926 | + {% endmacro commit_badge %} |
927 | diff --git a/ayllu/templates/nav.html b/ayllu/templates/nav.html |
928 | new file mode 100644 |
929 | index 0000000..5a502e6 |
930 | --- /dev/null |
931 | +++ b/ayllu/templates/nav.html |
932 | @@ -0,0 +1,12 @@ |
933 | + <nav> |
934 | + <a href="{%- if subpath_mode -%}/browse{%- else -%}/{%- endif -%}"> |
935 | + <div class="logo">{{ "logo.svg" | emoji | safe }}</div> |
936 | + </a> |
937 | + <ul> |
938 | + {% for item in nav_elements %} |
939 | + <li {% if item.2 %}class="active"{% endif %}> |
940 | + <a href="{{ item.1 }}">{{ item.0 }}</a> |
941 | + </li> |
942 | + {% endfor %} |
943 | + </ul> |
944 | + </nav> |
945 | diff --git a/ayllu/templates/post.html b/ayllu/templates/post.html |
946 | new file mode 100644 |
947 | index 0000000..ef9dc33 |
948 | --- /dev/null |
949 | +++ b/ayllu/templates/post.html |
950 | @@ -0,0 +1,25 @@ |
951 | + {% extends "base.html" %} |
952 | + {% block content %} |
953 | + <section class="stretch"> |
954 | + <article> |
955 | + <header> |
956 | + <h1>{{ message.message_id }}</h1> |
957 | + </br> |
958 | + <h4>Export Message</h4> |
959 | + <p> |
960 | + <a href="/mail/export/{{ list_id }}/{{ thread_id }}/{{ message.message_id }}">mbox</a> |
961 | + <p> |
962 | + <b>From: {{ message.from }}</b> |
963 | + </br> |
964 | + <b>Subject: {{ message.subject }}</b> |
965 | + </br> |
966 | + <span class="right">{{ message.timestamp | format_epoch }}</span> |
967 | + </header> |
968 | + {% if message.is_patch %} |
969 | + {{ diff.1 | safe }} |
970 | + {% else %} |
971 | + <pre>{{ message.text | safe }}</pre> |
972 | + {% endif %} |
973 | + </article> |
974 | + </section> |
975 | + {% endblock %} |
976 | diff --git a/ayllu/templates/refs.html b/ayllu/templates/refs.html |
977 | new file mode 100644 |
978 | index 0000000..9a6b19c |
979 | --- /dev/null |
980 | +++ b/ayllu/templates/refs.html |
981 | @@ -0,0 +1,89 @@ |
982 | + {% import "macros.html" as macros %} |
983 | + {% extends "base.html" %} |
984 | + {% block content %} |
985 | + <h1>Refs</h1> |
986 | + <section class="scrollable"> |
987 | + {% if tags %} |
988 | + <h4 class="minor-header">Tags</h4> |
989 | + <table class="data-table"> |
990 | + <thead> |
991 | + <tr> |
992 | + <th>Name</th> |
993 | + <th class="collapse">Age</th> |
994 | + <th class="collapse">Author</th> |
995 | + <th>Archive</th> |
996 | + </tr> |
997 | + </thead> |
998 | + <tbody> |
999 | + {% for tag in tags %} |
1000 | + <tr> |
1001 | + <td> |
1002 | + <a href="/{{ collection }}/{{ name }}/refs/tag/{{ tag.name }}">{{ tag.name }}</a> |
1003 | + </td> |
1004 | + <td class="collapse">{{ tag.commit.epoch | friendly_time }}</td> |
1005 | + <td class="collapse">{{ tag.author_name }}</td> |
1006 | + <td> |
1007 | + <a href="/{{ collection }}/{{ name }}/refs/archive/{{ tag.name }}.tar.gz" |
1008 | + role="button">{{ tag.name }}.tar.gz</a> |
1009 | + </td> |
1010 | + </tr> |
1011 | + {% endfor %} |
1012 | + </tbody> |
1013 | + </table> |
1014 | + {% endif %} |
1015 | + <h4 class="minor-header">Branches</h4> |
1016 | + <table class="data-table"> |
1017 | + <thead> |
1018 | + <tr> |
1019 | + <th>Name</th> |
1020 | + <th class="collapse">Age</th> |
1021 | + <th>Commit</th> |
1022 | + <th>Message</th> |
1023 | + </tr> |
1024 | + </thead> |
1025 | + <tbody> |
1026 | + {% for branch in branches %} |
1027 | + <tr> |
1028 | + <td> |
1029 | + <a href="/{{ collection }}/{{ name }}/tree/{{ branch.name | urlencode }}">{{ branch.name }}</a> |
1030 | + </td> |
1031 | + <td class="collapse">{{ branch.head.epoch | friendly_time }}</td> |
1032 | + <td> |
1033 | + <a href="/{{ collection }}/{{ name }}/commit/{{ branch.head.id }}"> |
1034 | + {{ branch.head.id | truncate(length=8, end="") }}</a> |
1035 | + </td> |
1036 | + <td>{{ branch.head.summary | truncate(length=85, end="...") }}</td> |
1037 | + </tr> |
1038 | + {% endfor %} |
1039 | + </tbody> |
1040 | + </table> |
1041 | + {% if notes %} |
1042 | + <h4 class="minor-header">Notes</h4> |
1043 | + <table class="data-table"> |
1044 | + <thead> |
1045 | + <tr> |
1046 | + <th>Commit</th> |
1047 | + <th>Author</th> |
1048 | + <th class="collapse">Age</th> |
1049 | + <th>Message</th> |
1050 | + </tr> |
1051 | + </thead> |
1052 | + <tbody> |
1053 | + {% for note in notes %} |
1054 | + <tr> |
1055 | + <td> |
1056 | + <a href="/{{ collection }}/{{ name }}/commit/{{ note.commit.id }}"> |
1057 | + {{ note.commit.id | truncate(length=8, end="") }}</a> |
1058 | + </td> |
1059 | + <td>{{ note.author_name }}</td> |
1060 | + <td class="collapse">{{ note.author_epoch | friendly_time }}</td> |
1061 | + <td> |
1062 | + <pre>{{ note.message | truncate(length=32, end="...") }}</pre> |
1063 | + </td> |
1064 | + </tr> |
1065 | + {% endfor %} |
1066 | + </tbody> |
1067 | + </table> |
1068 | + {% endif %} |
1069 | + </section> |
1070 | + {% endblock %} |
1071 | diff --git a/ayllu/templates/repo.html b/ayllu/templates/repo.html |
1072 | new file mode 100644 |
1073 | index 0000000..4dbc161 |
1074 | --- /dev/null |
1075 | +++ b/ayllu/templates/repo.html |
1076 | @@ -0,0 +1,171 @@ |
1077 | + {% extends "base.html" %} |
1078 | + {% block content %} |
1079 | + <section class="repo-view"> |
1080 | + <section class="pane-left"> |
1081 | + <section> |
1082 | + <span>{{ latest_commit.author_name }} {{ latest_commit.epoch | friendly_time }}</span> |
1083 | + </section> |
1084 | + <!--<section> |
1085 | + <span class="bold">FIXME commits</span> |
1086 | + </section>--> |
1087 | + {% if latest_commit.is_verified %} |
1088 | + <span class="positive"> |
1089 | + {% else %} |
1090 | + <span class="negative"> |
1091 | + {% endif %} |
1092 | + {{ latest_commit.id | truncate(length=8, end="") }} |
1093 | + </span> |
1094 | + </span> |
1095 | + <span class="right"> |
1096 | + <span class="bold yellow-badge">{{ refname }}</span> |
1097 | + </span> |
1098 | + <br /> |
1099 | + <span> |
1100 | + <a href="/{{ collection }}/{{ name }}/commit/{{ latest_commit.id }}"> |
1101 | + {{ latest_commit.summary | truncate(length=60) }} |
1102 | + </a> |
1103 | + </span> |
1104 | + <table class="tree"> |
1105 | + <thead> |
1106 | + <tr> |
1107 | + <th scope="col">File</th> |
1108 | + <th class="collapse" scope="col">Commit</th> |
1109 | + <th class="expand-xl" scope="col">Size</th> |
1110 | + <th class="expand-xl" scope="col">Mode</th> |
1111 | + <th scope="col">Time</th> |
1112 | + </tr> |
1113 | + </thead> |
1114 | + <tbody> |
1115 | + {% for item in tree %} |
1116 | + <tr> |
1117 | + {% if item.0.submodule %} |
1118 | + <td>{{ item.0.name }} @ {{ item.0.submodule }}</td> |
1119 | + {% else %} |
1120 | + <td> |
1121 | + <a href="{{ item.0.name | make_url(kind=item.0.kind) }}"> |
1122 | + {{ item.0.name }} |
1123 | + {% if item.0.kind == "Submodule" %}<span class="tiny">ref</span>{% endif %} |
1124 | + {% if item.0.kind == "Pointer" %}<span class="tiny">ptr</span>{% endif %} |
1125 | + </a> |
1126 | + </td> |
1127 | + {% endif %} |
1128 | + <td class="collapse"> |
1129 | + <a href="/{{ collection }}/{{ name }}/commit/{{ item.1.id }}">{{ item.1.summary | truncate(length=60) }}</a> |
1130 | + </td> |
1131 | + <td class="expand-xl">{{ item.0.size | human_bytes }}</td> |
1132 | + <td class="expand-xl">{{ item.0.mode | filemode }}</td> |
1133 | + <td> |
1134 | + <a href="/{{ collection }}/{{ name }}/commit/{{ item.1.id }}">{{ item.1.epoch | friendly_time }}</a> |
1135 | + </td> |
1136 | + </tr> |
1137 | + {% endfor %} |
1138 | + </tbody> |
1139 | + </table> |
1140 | + <section class="readme scrollable"> |
1141 | + {{ readme | safe }} |
1142 | + </section> |
1143 | + </section> |
1144 | + {% if show_details %} |
1145 | + <section class="pane-right"> |
1146 | + <section class="repo-section"> |
1147 | + <h3>Clone</h3> |
1148 | + <span class="bold">HTTP</span> |
1149 | + <section class="clone"> |
1150 | + <input type="text" value="{{ http_clone_url }}" readonly> |
1151 | + </section> |
1152 | + {% if git_clone_url %} |
1153 | + <section class="clone"> |
1154 | + <span class="bold">SSH</span> |
1155 | + <input type="text" value="{{ git_clone_url }}" readonly> |
1156 | + </section> |
1157 | + {% endif %} |
1158 | + </section> |
1159 | + {% if chat_links or email_links %} |
1160 | + <h3>Discussion</h3> |
1161 | + {% if chat_links %} |
1162 | + <h6>Chat</h6> |
1163 | + {% for chat in chat_links %} |
1164 | + <em>{{ chat.description }}, status:</em> |
1165 | + <b class="{%- if chat.users_online -%}" |
1166 | + " |
1167 | + positive |
1168 | + " |
1169 | + {%- else -%} |
1170 | + " |
1171 | + negative |
1172 | + " |
1173 | + {%- endif -%} |
1174 | + data-tooltip="{%- if chat.users_online -%} {{ chat.users_online }} Users Online {%- else -%} Offline {%- endif -%}"> |
1175 | + [{%- if chat.users_online -%}{{ chat.users_online }}{%- else -%}?{%- endif -%}] |
1176 | + </b> |
1177 | + <b>{{ chat.kind }}</b> |
1178 | + <input type="text" value="{{ chat.url }}" readonly> |
1179 | + {% endfor %} |
1180 | + {% endif %} |
1181 | + {% if email_links %} |
1182 | + <h6>Mailing Lists</h6> |
1183 | + {% for email in email_links %} |
1184 | + <em>{{ email.description }}, 100+ threads</em> |
1185 | + <b>mail</b> |
1186 | + <input type="text" value="{{ email.url }}" readonly> |
1187 | + {% endfor %} |
1188 | + {% endif %} |
1189 | + </section> |
1190 | + {% endif %} |
1191 | + <section> |
1192 | + <h3>Subscribe</h3> |
1193 | + <div class="rss-links"> |
1194 | + {{ "feed.svg" | emoji | safe }} |
1195 | + <p> |
1196 | + [<a href="{{ rss_link_all }}">*</a>, |
1197 | + <a href="{{ rss_link_1d }}">1d</a>, |
1198 | + <a href="{{ rss_link_1w }}">1w</a>, |
1199 | + <a href="{{ rss_link_1m }}">1m</a>] |
1200 | + </p> |
1201 | + </div> |
1202 | + </section> |
1203 | + {% if sites_url %} |
1204 | + <section class="repo-section"> |
1205 | + <div class="icon-header contrast"> |
1206 | + <h3>Homepage</h3> |
1207 | + </div> |
1208 | + <a href={{ sites_url }}>{{ sites_url }}</a> |
1209 | + </section> |
1210 | + {% endif %} |
1211 | + <section class="repo-section"> |
1212 | + <div class="icon-header contrast"> |
1213 | + <h3>License</h3> |
1214 | + </div> |
1215 | + <i><b>{{ license }}</b></i> |
1216 | + </section> |
1217 | + {% if has_author_data %} |
1218 | + <section> |
1219 | + <h3> |
1220 | + <a href="/{{ collection }}/{{ name }}/authors">Authors</a> |
1221 | + </h3> |
1222 | + {% if authors %} |
1223 | + {% for author in authors %} |
1224 | + <span>{{ author.0 }}:</span> <i> <span class="right">{{ author.2 }}% </i></span> |
1225 | + </br> |
1226 | + {% endfor %} |
1227 | + {% endif %} |
1228 | + {% endif %} |
1229 | + {% if has_chart_data %} |
1230 | + <h3>Analysis</h3> |
1231 | + <section class="charts"> |
1232 | + {% if has_contribution_data %} |
1233 | + <div class="chart"> |
1234 | + <a href="/{{ collection }}/{{ name }}/chart/activity/{{ latest_commit.id }}">{{ activity_chart | safe }}</a> |
1235 | + </div> |
1236 | + {% endif %} |
1237 | + {% if has_language_data %} |
1238 | + <div class="chart"> |
1239 | + <a href="/{{ collection }}/{{ name }}/chart/languages/{{ latest_commit.id }}">{{ language_chart | safe }}</a> |
1240 | + </div> |
1241 | + {% endif %} |
1242 | + </section> |
1243 | + {% endif %} |
1244 | + </section> |
1245 | + {% endif %} |
1246 | + </section> |
1247 | + {% endblock %} |
1248 | diff --git a/ayllu/templates/rss_summary.html b/ayllu/templates/rss_summary.html |
1249 | new file mode 100644 |
1250 | index 0000000..0b98b21 |
1251 | --- /dev/null |
1252 | +++ b/ayllu/templates/rss_summary.html |
1253 | @@ -0,0 +1,31 @@ |
1254 | + <h1>Summary from {{ start_date }} to {{ end_date }}</h1> |
1255 | + <h2> |
1256 | + {{ n_tags }} tags and {{ n_commits }} commits added |
1257 | + {% if entries | length > 1 %} |
1258 | + across {{ n_projects }} projects{%- endif -%} |
1259 | + </h2> |
1260 | + {% for entry in entries %} |
1261 | + <h2>Updates For {{ entry.name }}</h2> |
1262 | + {% if entry.tags | length > 0 %} |
1263 | + </br> |
1264 | + <h3> |
1265 | + <u>New Tags</u> |
1266 | + </h3> |
1267 | + {% endif %} |
1268 | + {% if entry.commits | length > 0 %} |
1269 | + </br> |
1270 | + <h3> |
1271 | + <u>New Commits</u> |
1272 | + </h3> |
1273 | + {% for commit in entry.commits %} |
1274 | + <article> |
1275 | + <header> |
1276 | + <h4> |
1277 | + <a href="{{ origin }}/{{ entry.name }}/commit/{{ commit.id }}">{{ commit.summary }} - {{ commit.author_name }}</a> |
1278 | + </h4> |
1279 | + </header> |
1280 | + <pre>{{commit.message}}</pre> |
1281 | + </article> |
1282 | + {% endfor %} |
1283 | + {% endif %} |
1284 | + {% endfor %} |
1285 | diff --git a/ayllu/templates/tag.html b/ayllu/templates/tag.html |
1286 | new file mode 100644 |
1287 | index 0000000..33aaa5f |
1288 | --- /dev/null |
1289 | +++ b/ayllu/templates/tag.html |
1290 | @@ -0,0 +1,33 @@ |
1291 | + {% import "macros.html" as macros %} |
1292 | + {% extends "base.html" %} |
1293 | + {% block content %} |
1294 | + <section class="stretch"> |
1295 | + <h1>{{ tag.name }}</h1> |
1296 | + <section> |
1297 | + <span><b>Author:</b></span> |
1298 | + <span class="right"> |
1299 | + <a href="/{{ collection }}/{{ name }}/log?username={{ tag.commit.author_name | urlencode }}&email={{ tag.commit.author_email | urlencode }}">{{ tag.commit.author_name }}</a> |
1300 | + [<a href="mailto://{{ tag.commit.author_email }}">{{ tag.commit.author_email }}</a>] |
1301 | + </span> |
1302 | + </section> |
1303 | + <section> |
1304 | + <span><b>Hash:</b></span> |
1305 | + <span class="right {% if tag.commit.is_verified -%} positive {%- else -%} negative {%- endif -%}">{{ tag.commit.id }}</span> |
1306 | + </section> |
1307 | + <section> |
1308 | + <span><b>Timestamp:</b></span> |
1309 | + <span class="right">{{ tag.commit.author_epoch | format_epoch }} ({{ tag.commit.epoch | friendly_time }})</span> |
1310 | + </section> |
1311 | + <section> |
1312 | + <span><b>Archive:</b></span> |
1313 | + <span class="right"> |
1314 | + <a href="/{{ collection }}/{{ name }}/refs/archive/{{ tag.name }}.tar.gz" |
1315 | + role="button">{{ tag.name }}.tar.gz</a> |
1316 | + </span> |
1317 | + </section> |
1318 | + <h4>Summary</h4> |
1319 | + <pre> |
1320 | + {{tag.summary}} |
1321 | + </pre> |
1322 | + </section> |
1323 | + {% endblock %} |
1324 | diff --git a/ayllu/templates/test.html b/ayllu/templates/test.html |
1325 | new file mode 100644 |
1326 | index 0000000..8fe25f9 |
1327 | --- /dev/null |
1328 | +++ b/ayllu/templates/test.html |
1329 | @@ -0,0 +1 @@ |
1330 | + {{ hello }} |
1331 | diff --git a/ayllu/templates/thread.html b/ayllu/templates/thread.html |
1332 | new file mode 100644 |
1333 | index 0000000..bdf31b1 |
1334 | --- /dev/null |
1335 | +++ b/ayllu/templates/thread.html |
1336 | @@ -0,0 +1,21 @@ |
1337 | + {% extends "base.html" %} |
1338 | + {% block content %} |
1339 | + <section class="stretch"> |
1340 | + <section class="message-header"> |
1341 | + <h6> {{ first_message.subject }} </h6> |
1342 | + <h6><a href="/mail/{{list_name}}">{{list_name}}</a></h6> |
1343 | + <h4>Export Thread</h4> |
1344 | + <a href="/mail/export/{{ list.name }}/{{ thread_id }}">mbox</a> |
1345 | + </section> |
1346 | + <section class="messages"> |
1347 | + {% for message in thread %} |
1348 | + <section class="message"> |
1349 | + <header class="message"> |
1350 | + From: {{message.mail_from}} | TODO: THE DATE |
1351 | + </header> |
1352 | + <pre> {{ message.content_body }} </pre> |
1353 | + </section> |
1354 | + {% endfor %} |
1355 | + </section> |
1356 | + </section> |
1357 | + {% endblock %} |
1358 | diff --git a/ayllu/templates/threads.html b/ayllu/templates/threads.html |
1359 | new file mode 100644 |
1360 | index 0000000..5ca4f06 |
1361 | --- /dev/null |
1362 | +++ b/ayllu/templates/threads.html |
1363 | @@ -0,0 +1,47 @@ |
1364 | + {% import "macros.html" as macros %} |
1365 | + {% extends "base.html" %} |
1366 | + {% block content %} |
1367 | + <section> |
1368 | + <header> |
1369 | + <h1>{{ list.name }}</h1> |
1370 | + <span class="right labels"> |
1371 | + {% for topic in list.topics %}<span class="yellow-badge">{{ topic }}</span>{% endfor %} |
1372 | + </span> |
1373 | + </header> |
1374 | + <div class="mailing-list-details"> |
1375 | + <h4>{{ list.description }}</h4> |
1376 | + </br> |
1377 | + <h4>Subscribe</h4> |
1378 | + <p> |
1379 | + Send an e-mail to <a href="mailto:{{ list.request_address }}?subject=subscribe">{{ list.request_address }}</a> with the following subject: <code>subscribe</code> |
1380 | + </p> |
1381 | + <h4>Unsubscribe</h4> |
1382 | + <p> |
1383 | + Send an e-mail to <a href="mailto:{{ list.request_address }}?subject=unsubscribe">{{ list.request_address }}</a> with the following subject: <code>unsubscribe</code> |
1384 | + </p> |
1385 | + <h4>Export List</h4> |
1386 | + <p> |
1387 | + <a href="/mail/export/{{ list.name }}">mbox</a> |
1388 | + </p> |
1389 | + </div> |
1390 | + <h4>Threads</h4> |
1391 | + <section class="scrollable"> |
1392 | + <table class="data-table"> |
1393 | + <thead> |
1394 | + <th scope="col">Subject</th> |
1395 | + <th scope="col">From</th> |
1396 | + <th scope="col">Replies</th> |
1397 | + </thead> |
1398 | + {% for thread in threads %} |
1399 | + <tr> |
1400 | + <td> |
1401 | + <a href="/mail/thread/{{list.name}}/{{thread.message_id}}">{{ thread.subject | truncate(length=90) }}</a> |
1402 | + </td> |
1403 | + <td> {{ thread.mail_from }} </td> |
1404 | + <td> {{ thread.reply_count }} </td> |
1405 | + </tr> |
1406 | + {% endfor %} |
1407 | + </table> |
1408 | + </section> |
1409 | + </section> |
1410 | + {% endblock %} |
1411 | diff --git a/ayllu/templates/user.html b/ayllu/templates/user.html |
1412 | new file mode 100644 |
1413 | index 0000000..311042b |
1414 | --- /dev/null |
1415 | +++ b/ayllu/templates/user.html |
1416 | @@ -0,0 +1,2 @@ |
1417 | + {% extends "base.html" %} |
1418 | + {% block content %}User Profile{% endblock %} |