crieur 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of crieur might be problematic. Click here for more details.

@@ -0,0 +1,39 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <h2><a href="../..">{{ numero.name }}</a></h2>
5
+
6
+ <article>
7
+ <header>
8
+ <h3>{{ article.title_f }}</h3>
9
+ <h4>{{ article.subtitle_f }}</h4>
10
+
11
+ {% if article.authors %}
12
+ <div>
13
+ {% for author in article.authors %}
14
+ <details>
15
+ <summary role="button"><em>{{ author.forname }} {{ author.surname }}</em></summary>
16
+ {{ author.biography|markdown }}
17
+ </details>
18
+ {% endfor %}
19
+ </div>
20
+ {% endif %}
21
+
22
+ {% for keyword in article.keywords %}
23
+ <a href="/mot-clef/{{ keyword.slug }}/">#{{ keyword.name }}</a>({{ keyword.articles|length }}){%- if not loop.last -%}, {% endif %}
24
+ {% endfor %}
25
+ </header>
26
+
27
+ <div>
28
+ {% if article.abstract %}
29
+ {% for abstract in article.abstract %}
30
+ {% if abstract.lang == 'fr' %}
31
+ <blockquote>{{ abstract.text_f|markdown }}</blockquote>
32
+ {% endif %}
33
+ {% endfor %}
34
+ {% endif %}
35
+
36
+ {{ article.content_md|markdown }}
37
+ </div>
38
+ </article>
39
+ {% endblock content %}
@@ -0,0 +1,39 @@
1
+ <!DOCTYPE html><!-- This is a valid HTML5 document. -->
2
+ <!-- Screen readers, SEO, extensions and so on. -->
3
+ <html lang="fr">
4
+ <!-- Has to be within the first 1024 bytes, hence before the <title>
5
+ See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
6
+ <meta charset="utf-8" />
7
+ <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
8
+ <!-- The viewport meta is quite crowded and we are responsible for that.
9
+ See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
10
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
11
+ <!-- Prevent access via referrers, only the domain will be available. -->
12
+ <meta content="origin-when-cross-origin" name="referrer" />
13
+ <!-- Required to make a valid HTML5 document. -->
14
+ <title>{{ title }}</title>
15
+ <!-- Lightest blank gif, avoids an extra query to the server. -->
16
+ <link rel="icon" href="data:;base64,iVBORw0KGgo=" />
17
+ <link rel="stylesheet"
18
+ href="/statics/pico.css" />
19
+ <style>
20
+ h1 {
21
+ text-align: center;
22
+ }
23
+ </style>
24
+ {% block extra_head %}
25
+ {% endblock extra_head %}
26
+
27
+ <body>
28
+ <main class="container">
29
+ <div class="content">
30
+ <h1><a href="/">{{ title }}</a></h1>
31
+ {% block content %}
32
+ {% endblock content %}
33
+ </div>
34
+ </main>
35
+ {% block extra_body %}
36
+ {% endblock extra_body %}
37
+
38
+ </body>
39
+ </html>
@@ -0,0 +1,90 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block extra_head %}
4
+ <style type="text/css">
5
+ :root {
6
+ --pico-spacing: 0.25rem;
7
+
8
+ /* Grid adjustments, see
9
+ https://css-tricks.com/an-auto-filling-css-grid-with-max-columns/
10
+ */
11
+ /**
12
+ * User input values.
13
+ */
14
+ --grid-layout-gap: 10px;
15
+ --grid-column-count: 1;
16
+ --grid-item--min-width: 100px;
17
+
18
+ /**
19
+ * Calculated values.
20
+ */
21
+ --gap-count: calc(var(--grid-column-count) - 1);
22
+ --total-gap-width: calc(var(--gap-count) * var(--grid-layout-gap));
23
+ --grid-item--max-width: calc((100% - var(--total-gap-width)) / var(--grid-column-count));
24
+ }
25
+
26
+ @media (min-width: 576px) {
27
+ :root {
28
+ --grid-column-count: 1;
29
+ }
30
+ }
31
+
32
+ @media (min-width: 768px) {
33
+ :root {
34
+ --grid-column-count: 2;
35
+ }
36
+ }
37
+
38
+ @media (min-width: 992px) {
39
+ :root {
40
+ --grid-column-count: 3;
41
+ }
42
+ }
43
+
44
+ .content {
45
+ width: 100%;
46
+ }
47
+
48
+ .grid {
49
+ grid-template-columns: repeat(auto-fill, minmax(max(var(--grid-item--min-width), var(--grid-item--max-width)), 1fr));
50
+ grid-gap: var(--grid-layout-gap);
51
+ }
52
+
53
+ .grid article header {
54
+ text-align: center;
55
+ }
56
+ </style>
57
+ {% endblock extra_head %}
58
+
59
+ {% block content %}
60
+ {% for slug, keyword in keywords.items() %}
61
+ {% if loop.index < 20 %}
62
+ <a href="/mot-clef/{{ keyword.slug }}/">#{{ keyword.name }}</a>({{ keyword.articles|length }}){%- if not loop.last -%}, {% endif %}
63
+ {% endif %}
64
+ {% endfor %}…
65
+ <details>
66
+ <summary role="button">Voir plus de mot-clés :</summary>
67
+ {% for slug, keyword in keywords.items() %}
68
+ {% if loop.index >= 20 %}
69
+ <a href="/mot-clef/{{ keyword.slug }}/">#{{ keyword.name }}</a>({{ keyword.articles|length }}){%- if not loop.last -%}, {% endif %}
70
+ {% endif %}
71
+ {% endfor %}
72
+ </details>
73
+ <div class="grid">
74
+ {% for numero in numeros %}
75
+ <article>
76
+ <header>
77
+ <hgroup>
78
+ <h2><a href="/numero/{{ numero.name }}/">{{ numero.name }}</a></h2>
79
+ <p>Le {{ numero.articles.0.date.strftime('%d %B %Y') }}</p>
80
+ </hgroup>
81
+ </header>
82
+ <ul>
83
+ {% for article in numero.articles %}
84
+ <li><a href="/numero/{{ numero.name }}/article/{{ article.id }}/">{{ article.title_f }}</a></li>
85
+ {% endfor %}
86
+ </ul>
87
+ </article>
88
+ {% endfor %}
89
+ </div>
90
+ {% endblock content %}
@@ -0,0 +1,17 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <article>
5
+ <header>
6
+ <h2>{{ keyword.name }} ({{ keyword.articles|length }})</h2>
7
+ </header>
8
+
9
+ <div>
10
+ <ul>
11
+ {% for article in keyword.articles %}
12
+ <li><a href="/numero/{{ article.numero.name }}/article/{{ article.id }}/">{{ article.title_f }}</a></li>
13
+ {% endfor %}
14
+ </ul>
15
+ </div>
16
+ </article>
17
+ {% endblock content %}
@@ -0,0 +1,77 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block extra_head %}
4
+ <style type="text/css">
5
+ :root {
6
+ --pico-spacing: 0.25rem;
7
+
8
+ /* Grid adjustments, see
9
+ https://css-tricks.com/an-auto-filling-css-grid-with-max-columns/
10
+ */
11
+ /**
12
+ * User input values.
13
+ */
14
+ --grid-layout-gap: 10px;
15
+ --grid-column-count: 1;
16
+ --grid-item--min-width: 100px;
17
+
18
+ /**
19
+ * Calculated values.
20
+ */
21
+ --gap-count: calc(var(--grid-column-count) - 1);
22
+ --total-gap-width: calc(var(--gap-count) * var(--grid-layout-gap));
23
+ --grid-item--max-width: calc((100% - var(--total-gap-width)) / var(--grid-column-count));
24
+ }
25
+
26
+ @media (min-width: 576px) {
27
+ :root {
28
+ --grid-column-count: 1;
29
+ }
30
+ }
31
+
32
+ @media (min-width: 768px) {
33
+ :root {
34
+ --grid-column-count: 2;
35
+ }
36
+ }
37
+
38
+ @media (min-width: 992px) {
39
+ :root {
40
+ --grid-column-count: 3;
41
+ }
42
+ }
43
+
44
+ .content {
45
+ width: 100%;
46
+ }
47
+
48
+ .grid {
49
+ grid-template-columns: repeat(auto-fill, minmax(max(var(--grid-item--min-width), var(--grid-item--max-width)), 1fr));
50
+ grid-gap: var(--grid-layout-gap);
51
+ }
52
+ </style>
53
+ {% endblock extra_head %}
54
+
55
+
56
+ {% block content %}
57
+ <h2>{{ numero.name }}</h2>
58
+ <div class="grid">
59
+ {% for article in numero.articles %}
60
+ <article>
61
+ <header>
62
+ <h3><a href="/numero/{{ numero.name }}/article/{{ article.id }}/">{{ article.title_f }}</a></h3>
63
+ </header>
64
+ {{ article.subtitle_f|markdown }}
65
+ {% if article.authors %}
66
+ <footer>
67
+ <p>
68
+ {%- for author in article.authors -%}
69
+ <em>{{ author.forname }} {{ author.surname }}{%- if not loop.last -%}, {% endif %}</em>
70
+ {%- endfor -%}
71
+ </p>
72
+ </footer>
73
+ {% endif %}
74
+ </article>
75
+ {% endfor %}
76
+ </div>
77
+ {% endblock content %}
crieur/utils.py ADDED
@@ -0,0 +1,56 @@
1
+ import re
2
+ from pathlib import Path
3
+
4
+ html_comments_re = re.compile(r"<!--.*?-->")
5
+ html_tags_re = re.compile(r"<[^>]*>")
6
+
7
+
8
+ def strip_html_comments(value):
9
+ if not value:
10
+ return ""
11
+ return html_comments_re.sub("", value)
12
+
13
+
14
+ def strip_html_tags(value):
15
+ if not value:
16
+ return ""
17
+ return html_tags_re.sub("", value)
18
+
19
+
20
+ def each_file_from(source_dir, pattern="*.html", exclude=None):
21
+ """Walk across the `source_dir` and return the html file paths."""
22
+ for path in _each_path_from(source_dir, pattern=pattern, exclude=exclude):
23
+ if path.is_file():
24
+ yield path
25
+
26
+
27
+ def each_folder_from(source_dir, exclude=None):
28
+ """Walk across the `source_dir` and return the folder paths."""
29
+ for path in _each_path_from(source_dir, exclude=exclude):
30
+ if path.is_dir():
31
+ yield path
32
+
33
+
34
+ def _each_path_from(source_dir, pattern="*", exclude=None):
35
+ for path in sorted(Path(source_dir).glob(pattern)):
36
+ if exclude is not None and path.name in exclude:
37
+ continue
38
+ yield path
39
+
40
+
41
+ def neighborhood(iterable, first=None, last=None):
42
+ """
43
+ Yield the (index, previous, current, next) items given an iterable.
44
+
45
+ You can specify a `first` and/or `last` item for bounds.
46
+ """
47
+ index = 1
48
+ iterator = iter(iterable)
49
+ previous = first
50
+ current = next(iterator) # Throws StopIteration if empty.
51
+ for next_ in iterator:
52
+ yield (index, previous, current, next_)
53
+ previous = current
54
+ index += 1
55
+ current = next_
56
+ yield (index, previous, current, last)