@geekity/cms 0.35.0 → 0.37.0
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.
- package/admin/components/blocks.njk +250 -0
- package/admin/components/card.njk +4 -2
- package/admin/components/job-status.njk +15 -10
- package/admin/components/upload.njk +26 -0
- package/admin/pages/comments/all.njk +1 -1
- package/admin/pages/dashboard/home.njk +33 -32
- package/admin/pages/documents/editor.njk +34 -19
- package/admin/pages/federation/followers.njk +3 -2
- package/admin/pages/media/file.njk +5 -4
- package/admin/pages/media/library.njk +7 -3
- package/admin/pages/plugins/screen.njk +5 -35
- package/admin/pages/settings/general.njk +4 -1
- package/admin/pages/tools/export.njk +54 -51
- package/admin/pages/tools/maintenance.njk +2 -1
- package/admin/pages/users/edit.njk +3 -0
- package/admin/src/admin.css +1 -0
- package/admin/static/admin.css +374 -0
- package/admin/static/job-status.js +158 -0
- package/admin/static/upload-drop.js +225 -0
- package/dist/admin/blocks.d.ts +133 -0
- package/dist/admin/blocks.d.ts.map +1 -0
- package/dist/admin/blocks.js +454 -0
- package/dist/admin/blocks.js.map +1 -0
- package/dist/admin/core-widgets.d.ts +3 -0
- package/dist/admin/core-widgets.d.ts.map +1 -0
- package/dist/admin/core-widgets.js +17 -0
- package/dist/admin/core-widgets.js.map +1 -0
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +0 -2
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/engagement.d.ts +16 -0
- package/dist/admin/engagement.d.ts.map +1 -0
- package/dist/admin/engagement.js +38 -0
- package/dist/admin/engagement.js.map +1 -0
- package/dist/admin/federation.d.ts +2 -0
- package/dist/admin/federation.d.ts.map +1 -1
- package/dist/admin/federation.js +2 -1
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/formatting.d.ts +1 -0
- package/dist/admin/formatting.d.ts.map +1 -1
- package/dist/admin/formatting.js +18 -0
- package/dist/admin/formatting.js.map +1 -1
- package/dist/admin/index.d.ts +2 -2
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +2 -2
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/job-status.d.ts +1 -0
- package/dist/admin/job-status.d.ts.map +1 -1
- package/dist/admin/job-status.js +1 -0
- package/dist/admin/job-status.js.map +1 -1
- package/dist/admin/media.d.ts +6 -9
- package/dist/admin/media.d.ts.map +1 -1
- package/dist/admin/media.js +85 -27
- package/dist/admin/media.js.map +1 -1
- package/dist/admin/posts-by-path.d.ts +11 -0
- package/dist/admin/posts-by-path.d.ts.map +1 -0
- package/dist/admin/posts-by-path.js +59 -0
- package/dist/admin/posts-by-path.js.map +1 -0
- package/dist/admin/routes.d.ts +0 -2
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +24 -12
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/templates.d.ts.map +1 -1
- package/dist/admin/templates.js +2 -0
- package/dist/admin/templates.js.map +1 -1
- package/dist/admin/tools.js +1 -1
- package/dist/admin/tools.js.map +1 -1
- package/dist/admin/uploads.d.ts +2 -1
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +5 -2
- package/dist/admin/uploads.js.map +1 -1
- package/dist/admin/widget-fediverse.d.ts +3 -0
- package/dist/admin/widget-fediverse.d.ts.map +1 -0
- package/dist/admin/widget-fediverse.js +49 -0
- package/dist/admin/widget-fediverse.js.map +1 -0
- package/dist/admin/widget-followers.d.ts +3 -0
- package/dist/admin/widget-followers.d.ts.map +1 -0
- package/dist/admin/widget-followers.js +37 -0
- package/dist/admin/widget-followers.js.map +1 -0
- package/dist/admin/widget-health.d.ts +3 -0
- package/dist/admin/widget-health.d.ts.map +1 -0
- package/dist/admin/widget-health.js +103 -0
- package/dist/admin/widget-health.js.map +1 -0
- package/dist/admin/widget-interactions.d.ts +4 -0
- package/dist/admin/widget-interactions.d.ts.map +1 -0
- package/dist/admin/widget-interactions.js +99 -0
- package/dist/admin/widget-interactions.js.map +1 -0
- package/dist/admin/widget-posting.d.ts +3 -0
- package/dist/admin/widget-posting.d.ts.map +1 -0
- package/dist/admin/widget-posting.js +111 -0
- package/dist/admin/widget-posting.js.map +1 -0
- package/dist/admin/widget-scheduled.d.ts +4 -0
- package/dist/admin/widget-scheduled.d.ts.map +1 -0
- package/dist/admin/widget-scheduled.js +30 -0
- package/dist/admin/widget-scheduled.js.map +1 -0
- package/dist/admin/widget-top-posts.d.ts +4 -0
- package/dist/admin/widget-top-posts.d.ts.map +1 -0
- package/dist/admin/widget-top-posts.js +55 -0
- package/dist/admin/widget-top-posts.js.map +1 -0
- package/dist/admin/widgets.d.ts +35 -0
- package/dist/admin/widgets.d.ts.map +1 -0
- package/dist/admin/widgets.js +103 -0
- package/dist/admin/widgets.js.map +1 -0
- package/dist/cms/app.d.ts.map +1 -1
- package/dist/cms/app.js +2 -1
- package/dist/cms/app.js.map +1 -1
- package/dist/cms/boot.d.ts.map +1 -1
- package/dist/cms/boot.js +3 -2
- package/dist/cms/boot.js.map +1 -1
- package/dist/cms/services.d.ts.map +1 -1
- package/dist/cms/services.js +19 -0
- package/dist/cms/services.js.map +1 -1
- package/dist/content/alt-text.d.ts +1 -0
- package/dist/content/alt-text.d.ts.map +1 -1
- package/dist/content/alt-text.js +26 -1
- package/dist/content/alt-text.js.map +1 -1
- package/dist/content/sqlite/catalog.d.ts.map +1 -1
- package/dist/content/sqlite/catalog.js +15 -2
- package/dist/content/sqlite/catalog.js.map +1 -1
- package/dist/content/store.d.ts +10 -0
- package/dist/content/store.d.ts.map +1 -1
- package/dist/content/store.js.map +1 -1
- package/dist/content/write.d.ts.map +1 -1
- package/dist/content/write.js +3 -1
- package/dist/content/write.js.map +1 -1
- package/dist/federation/backfill.d.ts +1 -1
- package/dist/federation/backfill.d.ts.map +1 -1
- package/dist/federation/backfill.js +5 -1
- package/dist/federation/backfill.js.map +1 -1
- package/dist/federation/follower-history.d.ts +16 -0
- package/dist/federation/follower-history.d.ts.map +1 -0
- package/dist/federation/follower-history.js +61 -0
- package/dist/federation/follower-history.js.map +1 -0
- package/dist/federation/inbox.d.ts.map +1 -1
- package/dist/federation/inbox.js +2 -1
- package/dist/federation/inbox.js.map +1 -1
- package/dist/federation/records.d.ts +1 -0
- package/dist/federation/records.d.ts.map +1 -1
- package/dist/federation/records.js +24 -6
- package/dist/federation/records.js.map +1 -1
- package/dist/files/data-files.d.ts +1 -0
- package/dist/files/data-files.d.ts.map +1 -1
- package/dist/files/data-files.js +6 -0
- package/dist/files/data-files.js.map +1 -1
- package/dist/jobs/queue.d.ts.map +1 -1
- package/dist/jobs/queue.js +5 -0
- package/dist/jobs/queue.js.map +1 -1
- package/dist/jobs/types.d.ts +7 -0
- package/dist/jobs/types.d.ts.map +1 -1
- package/dist/jobs/types.js.map +1 -1
- package/dist/media/library.d.ts +9 -0
- package/dist/media/library.d.ts.map +1 -1
- package/dist/media/library.js +25 -1
- package/dist/media/library.js.map +1 -1
- package/dist/plugin.d.ts +275 -21
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +9 -8
- package/dist/plugin.js.map +1 -1
- package/dist/plugins/fetch.d.ts +0 -5
- package/dist/plugins/fetch.d.ts.map +1 -1
- package/dist/plugins/fetch.js +31 -7
- package/dist/plugins/fetch.js.map +1 -1
- package/dist/plugins/host-api.d.ts +3 -0
- package/dist/plugins/host-api.d.ts.map +1 -0
- package/dist/plugins/host-api.js +8 -0
- package/dist/plugins/host-api.js.map +1 -0
- package/dist/plugins/install.d.ts.map +1 -1
- package/dist/plugins/install.js +4 -2
- package/dist/plugins/install.js.map +1 -1
- package/dist/plugins/page-tags.d.ts +8 -0
- package/dist/plugins/page-tags.d.ts.map +1 -0
- package/dist/plugins/page-tags.js +73 -0
- package/dist/plugins/page-tags.js.map +1 -0
- package/dist/plugins/registry.d.ts +4 -1
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +50 -9
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/site.js +1 -1
- package/dist/plugins/site.js.map +1 -1
- package/dist/store/admin-store.d.ts +2 -2
- package/dist/store/admin-store.d.ts.map +1 -1
- package/dist/store/admin-store.js.map +1 -1
- package/dist/store/comments.d.ts +7 -0
- package/dist/store/comments.d.ts.map +1 -1
- package/dist/store/comments.js +21 -0
- package/dist/store/comments.js.map +1 -1
- package/dist/store/deliveries.d.ts +1 -0
- package/dist/store/deliveries.d.ts.map +1 -1
- package/dist/store/deliveries.js +6 -0
- package/dist/store/deliveries.js.map +1 -1
- package/dist/store/inbox.d.ts +16 -0
- package/dist/store/inbox.d.ts.map +1 -1
- package/dist/store/inbox.js +62 -0
- package/dist/store/inbox.js.map +1 -1
- package/dist/store/queue-database.d.ts +6 -0
- package/dist/store/queue-database.d.ts.map +1 -1
- package/dist/store/queue-database.js +16 -1
- package/dist/store/queue-database.js.map +1 -1
- package/dist/store/webmentions.d.ts +1 -0
- package/dist/store/webmentions.d.ts.map +1 -1
- package/dist/store/webmentions.js +6 -0
- package/dist/store/webmentions.js.map +1 -1
- package/dist/web/env.d.ts +3 -0
- package/dist/web/env.d.ts.map +1 -1
- package/dist/web/feed-item.d.ts +4 -3
- package/dist/web/feed-item.d.ts.map +1 -1
- package/dist/web/feed-item.js +8 -2
- package/dist/web/feed-item.js.map +1 -1
- package/dist/web/listing-pages.d.ts.map +1 -1
- package/dist/web/listing-pages.js +7 -2
- package/dist/web/listing-pages.js.map +1 -1
- package/dist/web/page-tags.d.ts +4 -0
- package/dist/web/page-tags.d.ts.map +1 -0
- package/dist/web/page-tags.js +39 -0
- package/dist/web/page-tags.js.map +1 -0
- package/dist/web/render.d.ts +2 -0
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +14 -0
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts +2 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +3 -1
- package/dist/web/routes.js.map +1 -1
- package/package.json +6 -1
- package/themes/default/layouts/base.njk +6 -4
- package/dist/comments/routes.d.ts +0 -65
- package/dist/comments/routes.d.ts.map +0 -1
- package/dist/comments/routes.js +0 -235
- package/dist/comments/routes.js.map +0 -1
- package/dist/content/media.d.ts +0 -85
- package/dist/content/media.d.ts.map +0 -1
- package/dist/content/media.js +0 -237
- package/dist/content/media.js.map +0 -1
- package/dist/content/read-form.d.ts +0 -31
- package/dist/content/read-form.d.ts.map +0 -1
- package/dist/content/read-form.js +0 -157
- package/dist/content/read-form.js.map +0 -1
- package/dist/content/read.d.ts +0 -29
- package/dist/content/read.d.ts.map +0 -1
- package/dist/content/read.js +0 -82
- package/dist/content/read.js.map +0 -1
- package/dist/export/export-archives.d.ts +0 -29
- package/dist/export/export-archives.d.ts.map +0 -1
- package/dist/export/export-archives.js +0 -88
- package/dist/export/export-archives.js.map +0 -1
- package/dist/federation/mount.d.ts +0 -53
- package/dist/federation/mount.d.ts.map +0 -1
- package/dist/federation/mount.js +0 -344
- package/dist/federation/mount.js.map +0 -1
- package/dist/mail/credentials.d.ts +0 -62
- package/dist/mail/credentials.d.ts.map +0 -1
- package/dist/mail/credentials.js +0 -86
- package/dist/mail/credentials.js.map +0 -1
- package/dist/site/setting-rows.d.ts +0 -45
- package/dist/site/setting-rows.d.ts.map +0 -1
- package/dist/site/setting-rows.js +0 -361
- package/dist/site/setting-rows.js.map +0 -1
- package/dist/site/settings-form.d.ts +0 -30
- package/dist/site/settings-form.d.ts.map +0 -1
- package/dist/site/settings-form.js +0 -54
- package/dist/site/settings-form.js.map +0 -1
- package/dist/site/site-json.d.ts +0 -38
- package/dist/site/site-json.d.ts.map +0 -1
- package/dist/site/site-json.js +0 -69
- package/dist/site/site-json.js.map +0 -1
- package/dist/webmention/routes.d.ts +0 -37
- package/dist/webmention/routes.d.ts.map +0 -1
- package/dist/webmention/routes.js +0 -75
- package/dist/webmention/routes.js.map +0 -1
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
{% from "components/table.njk" import table %}
|
|
2
|
+
|
|
3
|
+
{% set SERIES = [
|
|
4
|
+
{ dash: 'none', marker: 'circle' },
|
|
5
|
+
{ dash: '6 4', marker: 'square' },
|
|
6
|
+
{ dash: '2 3', marker: 'triangle' },
|
|
7
|
+
{ dash: '10 3 2 3', marker: 'diamond' }
|
|
8
|
+
] %}
|
|
9
|
+
|
|
10
|
+
{% set TINTS = {
|
|
11
|
+
'0': 'fill-primary stroke-primary',
|
|
12
|
+
'1': 'fill-secondary stroke-secondary',
|
|
13
|
+
'2': 'fill-accent stroke-accent',
|
|
14
|
+
'3': 'fill-info stroke-info'
|
|
15
|
+
} %}
|
|
16
|
+
|
|
17
|
+
{% set TONES = { better: 'text-success', worse: 'text-error', 'none': '' } %}
|
|
18
|
+
|
|
19
|
+
{% macro text(parts) -%}
|
|
20
|
+
{%- for part in parts -%}
|
|
21
|
+
{%- if part.code is defined -%}<code>{{ part.code }}</code>{%- else -%}{{ part }}{%- endif -%}
|
|
22
|
+
{%- endfor -%}
|
|
23
|
+
{%- endmacro %}
|
|
24
|
+
|
|
25
|
+
{% macro marker(shape, x, y) -%}
|
|
26
|
+
{%- if shape == 'circle' -%}
|
|
27
|
+
<circle class="stroke-base-100" stroke-width="2" cx="{{ x }}" cy="{{ y }}" r="4" />
|
|
28
|
+
{%- elif shape == 'square' -%}
|
|
29
|
+
<rect class="stroke-base-100" stroke-width="2" x="{{ x - 4 }}" y="{{ y - 4 }}" width="8" height="8" />
|
|
30
|
+
{%- elif shape == 'triangle' -%}
|
|
31
|
+
<polygon class="stroke-base-100" stroke-width="2" points="{{ x }},{{ y - 5 }} {{ x + 5 }},{{ y + 4 }} {{ x - 5 }},{{ y + 4 }}" />
|
|
32
|
+
{%- else -%}
|
|
33
|
+
<polygon class="stroke-base-100" stroke-width="2" points="{{ x }},{{ y - 5 }} {{ x + 5 }},{{ y }} {{ x }},{{ y + 5 }} {{ x - 5 }},{{ y }}" />
|
|
34
|
+
{%- endif -%}
|
|
35
|
+
{%- endmacro %}
|
|
36
|
+
|
|
37
|
+
{% macro textures(id, count) -%}
|
|
38
|
+
<defs>
|
|
39
|
+
{% if count > 1 %}
|
|
40
|
+
<pattern id="{{ id }}-texture-1" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
|
|
41
|
+
<line class="stroke-base-100" x1="0" y1="0" x2="0" y2="6" stroke-width="2" />
|
|
42
|
+
</pattern>
|
|
43
|
+
{% endif %}
|
|
44
|
+
{% if count > 2 %}
|
|
45
|
+
<pattern id="{{ id }}-texture-2" width="5" height="5" patternUnits="userSpaceOnUse">
|
|
46
|
+
<circle class="fill-base-100" cx="2.5" cy="2.5" r="1.25" />
|
|
47
|
+
</pattern>
|
|
48
|
+
{% endif %}
|
|
49
|
+
{% if count > 3 %}
|
|
50
|
+
<pattern id="{{ id }}-texture-3" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(-45)">
|
|
51
|
+
<line class="stroke-base-100" x1="0" y1="0" x2="0" y2="6" stroke-width="2" />
|
|
52
|
+
</pattern>
|
|
53
|
+
{% endif %}
|
|
54
|
+
</defs>
|
|
55
|
+
{%- endmacro %}
|
|
56
|
+
|
|
57
|
+
{% macro numbers(view) -%}
|
|
58
|
+
{% if view.rows.length %}
|
|
59
|
+
<details class="text-sm">
|
|
60
|
+
<summary class="cursor-pointer text-base-content/70">Show the numbers</summary>
|
|
61
|
+
{% call table(view.description, inCard=true) %}
|
|
62
|
+
<thead>
|
|
63
|
+
<tr>{% for column in view.columns %}<th scope="col">{{ column }}</th>{% endfor %}</tr>
|
|
64
|
+
</thead>
|
|
65
|
+
<tbody>
|
|
66
|
+
{% for row in view.rows %}
|
|
67
|
+
<tr><th scope="row">{{ row.heading }}</th>{% for cell in row.cells %}<td>{{ cell }}</td>{% endfor %}</tr>
|
|
68
|
+
{% endfor %}
|
|
69
|
+
</tbody>
|
|
70
|
+
{% endcall %}
|
|
71
|
+
</details>
|
|
72
|
+
{% endif %}
|
|
73
|
+
{%- endmacro %}
|
|
74
|
+
|
|
75
|
+
{% macro timeSeries(view) -%}
|
|
76
|
+
<div class="grid gap-3">
|
|
77
|
+
<p id="{{ view.id }}" class="sr-only">{{ view.description }}</p>
|
|
78
|
+
{% if view.series.length > 1 %}
|
|
79
|
+
<ul class="flex flex-wrap gap-x-4 gap-y-1 text-sm" aria-hidden="true">
|
|
80
|
+
{% for entry in view.series %}
|
|
81
|
+
{% set look = SERIES[loop.index0] %}
|
|
82
|
+
<li class="flex items-center gap-2">
|
|
83
|
+
<svg class="h-3 w-7" viewBox="0 0 28 12">
|
|
84
|
+
<g class="{{ TINTS | modifier(loop.index0 | string) | trim }}">
|
|
85
|
+
<line x1="0" y1="6" x2="28" y2="6" stroke-width="2" stroke-dasharray="{{ look.dash }}" />
|
|
86
|
+
{{ marker(look.marker, 14, 6) }}
|
|
87
|
+
</g>
|
|
88
|
+
</svg>
|
|
89
|
+
<span>{{ entry.name }}</span></li>
|
|
90
|
+
{% endfor %}
|
|
91
|
+
</ul>
|
|
92
|
+
{% endif %}
|
|
93
|
+
<svg role="img" aria-labelledby="{{ view.id }}" viewBox="0 0 {{ view.width }} {{ view.height }}" class="h-auto w-full max-w-xl">
|
|
94
|
+
{% for tick in view.yTicks %}
|
|
95
|
+
<line class="{{ 'stroke-base-content/30' if loop.first else 'stroke-base-content/10' }}" x1="{{ view.plot.left }}" x2="{{ view.plot.right }}" y1="{{ tick.y }}" y2="{{ tick.y }}" stroke-width="1" />
|
|
96
|
+
<text class="fill-base-content/70" x="{{ view.plot.left - 6 }}" y="{{ tick.y + 4 }}" text-anchor="end" font-size="12">{{ tick.label }}</text>
|
|
97
|
+
{% endfor %}
|
|
98
|
+
{% for tick in view.xTicks %}
|
|
99
|
+
<text class="fill-base-content/70" x="{{ tick.x }}" y="{{ view.height - 8 }}" text-anchor="middle" font-size="12">{{ tick.label }}</text>
|
|
100
|
+
{% endfor %}
|
|
101
|
+
{% for entry in view.series %}
|
|
102
|
+
{% set look = SERIES[loop.index0] %}
|
|
103
|
+
<g class="{{ TINTS | modifier(loop.index0 | string) | trim }}">
|
|
104
|
+
<path class="fill-none" stroke-dasharray="{{ look.dash }}" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" d="{{ entry.path }}" />
|
|
105
|
+
</g>
|
|
106
|
+
{% endfor %}
|
|
107
|
+
{% for entry in view.series %}
|
|
108
|
+
{% set look = SERIES[loop.index0] %}
|
|
109
|
+
<g class="{{ TINTS | modifier(loop.index0 | string) | trim }}">{{ marker(look.marker, entry.end.x, entry.end.y) }}</g>
|
|
110
|
+
{% endfor %}
|
|
111
|
+
{% for band in view.bands %}
|
|
112
|
+
<rect class="fill-transparent" x="{{ band.x }}" y="{{ view.plot.top }}" width="{{ band.width }}" height="{{ view.plot.bottom - view.plot.top }}" pointer-events="all"><title>{{ band.title }}</title></rect>
|
|
113
|
+
{% endfor %}
|
|
114
|
+
</svg>
|
|
115
|
+
{{ numbers(view) }}
|
|
116
|
+
</div>
|
|
117
|
+
{%- endmacro %}
|
|
118
|
+
|
|
119
|
+
{% macro bars(view) -%}
|
|
120
|
+
<div class="grid gap-3">
|
|
121
|
+
<p id="{{ view.id }}" class="sr-only">{{ view.description }}</p>
|
|
122
|
+
{% if view.series.length > 1 %}
|
|
123
|
+
<ul class="flex flex-wrap gap-x-4 gap-y-1 text-sm" aria-hidden="true">
|
|
124
|
+
{% for name in view.series %}
|
|
125
|
+
<li class="flex items-center gap-2">
|
|
126
|
+
<svg class="size-3" viewBox="0 0 12 12">
|
|
127
|
+
<g class="{{ TINTS | modifier(loop.index0 | string) | trim }}"><rect width="12" height="12" rx="2" /></g>
|
|
128
|
+
{% if not loop.first %}<rect width="12" height="12" rx="2" fill="url(#{{ view.id }}-texture-{{ loop.index0 }})" />{% endif %}
|
|
129
|
+
</svg>
|
|
130
|
+
<span>{{ name }}</span></li>
|
|
131
|
+
{% endfor %}
|
|
132
|
+
</ul>
|
|
133
|
+
{% endif %}
|
|
134
|
+
<svg role="img" aria-labelledby="{{ view.id }}" viewBox="0 0 {{ view.width }} {{ view.height }}" class="h-auto w-full max-w-xl">
|
|
135
|
+
{{ textures(view.id, view.series.length) }}
|
|
136
|
+
{% for tick in view.yTicks %}
|
|
137
|
+
<line class="{{ 'stroke-base-content/30' if loop.first else 'stroke-base-content/10' }}" x1="{{ view.plot.left }}" x2="{{ view.plot.right }}" y1="{{ tick.y }}" y2="{{ tick.y }}" stroke-width="1" />
|
|
138
|
+
<text class="fill-base-content/70" x="{{ view.plot.left - 6 }}" y="{{ tick.y + 4 }}" text-anchor="end" font-size="12">{{ tick.label }}</text>
|
|
139
|
+
{% endfor %}
|
|
140
|
+
{% for bar in view.bars %}
|
|
141
|
+
{% for segment in bar.segments %}
|
|
142
|
+
<g class="{{ TINTS | modifier(segment.series | string) | trim }}"><rect x="{{ segment.x }}" y="{{ segment.y }}" width="{{ segment.width }}" height="{{ segment.height }}"><title>{{ segment.title }}</title></rect></g>
|
|
143
|
+
{% if segment.series > 0 %}<rect x="{{ segment.x }}" y="{{ segment.y }}" width="{{ segment.width }}" height="{{ segment.height }}" fill="url(#{{ view.id }}-texture-{{ segment.series }})" pointer-events="none" />{% endif %}
|
|
144
|
+
{% endfor %}
|
|
145
|
+
{% if bar.total %}
|
|
146
|
+
<text class="fill-base-content font-semibold" x="{{ bar.centerX }}" y="{{ bar.total.y }}" text-anchor="middle" font-size="11">{{ bar.total.text }}</text>
|
|
147
|
+
{% endif %}
|
|
148
|
+
{% if bar.tick %}
|
|
149
|
+
<text class="fill-base-content/70" x="{{ bar.centerX }}" y="{{ view.height - 8 }}" text-anchor="middle" font-size="12">{{ bar.tick }}</text>
|
|
150
|
+
{% endif %}
|
|
151
|
+
{% endfor %}
|
|
152
|
+
</svg>
|
|
153
|
+
{{ numbers(view) }}
|
|
154
|
+
</div>
|
|
155
|
+
{%- endmacro %}
|
|
156
|
+
|
|
157
|
+
{% macro calendar(view) -%}
|
|
158
|
+
<div class="grid gap-3">
|
|
159
|
+
<p id="{{ view.id }}" class="sr-only">{{ view.description }}</p>
|
|
160
|
+
<div class="flex flex-row-reverse overflow-x-auto">
|
|
161
|
+
<svg role="img" aria-labelledby="{{ view.id }}" viewBox="0 0 {{ view.width }} {{ view.height }}" width="{{ view.width * 1.25 }}" height="{{ view.height * 1.25 }}" class="mr-auto h-auto{% if view.width * 1.25 > 640 %} max-w-full min-w-160{% endif %} shrink-0">
|
|
162
|
+
{% for month in view.months %}
|
|
163
|
+
<text class="fill-base-content/70" x="{{ month.x }}" y="11" text-anchor="start" font-size="10">{{ month.label }}</text>
|
|
164
|
+
{% endfor %}
|
|
165
|
+
{% for day in view.weekdays %}
|
|
166
|
+
<text class="fill-base-content/70" x="24" y="{{ day.y }}" text-anchor="end" font-size="9">{{ day.label }}</text>
|
|
167
|
+
{% endfor %}
|
|
168
|
+
{% for cell in view.cells %}
|
|
169
|
+
<rect class="{% if cell.level == 0 %}fill-base-content/10{% elif cell.level == 1 %}fill-primary/25{% elif cell.level == 2 %}fill-primary/50{% elif cell.level == 3 %}fill-primary/75{% else %}fill-primary{% endif %}" x="{{ cell.x }}" y="{{ cell.y }}" width="{{ view.cell }}" height="{{ view.cell }}" rx="2"><title>{{ cell.title }}</title></rect>
|
|
170
|
+
{% endfor %}
|
|
171
|
+
</svg>
|
|
172
|
+
</div>
|
|
173
|
+
<div class="flex items-center gap-1 text-xs text-base-content/70" aria-hidden="true">
|
|
174
|
+
<span>Less</span>
|
|
175
|
+
<svg class="h-3 w-[4.25rem]" viewBox="0 0 68 12">
|
|
176
|
+
<rect class="fill-base-content/10" x="0" y="0" width="12" height="12" rx="2" />
|
|
177
|
+
<rect class="fill-primary/25" x="14" y="0" width="12" height="12" rx="2" />
|
|
178
|
+
<rect class="fill-primary/50" x="28" y="0" width="12" height="12" rx="2" />
|
|
179
|
+
<rect class="fill-primary/75" x="42" y="0" width="12" height="12" rx="2" />
|
|
180
|
+
<rect class="fill-primary" x="56" y="0" width="12" height="12" rx="2" />
|
|
181
|
+
</svg>
|
|
182
|
+
<span>More</span>
|
|
183
|
+
</div>
|
|
184
|
+
{{ numbers(view) }}
|
|
185
|
+
</div>
|
|
186
|
+
{%- endmacro %}
|
|
187
|
+
|
|
188
|
+
{% macro block(data) -%}
|
|
189
|
+
{% set view = data | drawn %}
|
|
190
|
+
{% if view.kind == 'paragraph' %}
|
|
191
|
+
<p class="text-sm">{{ text(view.parts) }}</p>
|
|
192
|
+
{% elif view.kind == 'table' %}
|
|
193
|
+
{% call table(view.table.caption, inCard=true) %}
|
|
194
|
+
<thead>
|
|
195
|
+
<tr>
|
|
196
|
+
{% for column in view.table.columns %}<th scope="col">{{ column }}</th>{% endfor %}
|
|
197
|
+
</tr>
|
|
198
|
+
</thead>
|
|
199
|
+
<tbody>
|
|
200
|
+
{% for row in view.table.rows %}
|
|
201
|
+
<tr>
|
|
202
|
+
{% for cell in row %}
|
|
203
|
+
{% if cell.time is defined %}
|
|
204
|
+
<td class="whitespace-nowrap">{% if cell.time %}{{ cell.time | date('readable') }}{% else %}Never{% endif %}</td>
|
|
205
|
+
{% elif cell.text is defined %}
|
|
206
|
+
<td class="wrap-anywhere">{% if cell.href %}<a class="link" href="{{ cell.href }}">{{ cell.text }}</a>{% else %}{{ cell.text }}{% endif %}</td>
|
|
207
|
+
{% else %}
|
|
208
|
+
<td class="wrap-anywhere">{{ text([cell]) }}</td>
|
|
209
|
+
{% endif %}
|
|
210
|
+
{% endfor %}
|
|
211
|
+
</tr>
|
|
212
|
+
{% endfor %}
|
|
213
|
+
</tbody>
|
|
214
|
+
{% endcall %}
|
|
215
|
+
{% elif view.kind == 'stats' %}
|
|
216
|
+
<div class="stats flex flex-wrap gap-px bg-base-content/10 shadow">
|
|
217
|
+
{% for stat in view.stats %}
|
|
218
|
+
<div class="stat w-auto flex-auto border-0 bg-base-100">
|
|
219
|
+
<div class="stat-title">{{ stat.label }}</div>
|
|
220
|
+
<div class="stat-value">{{ stat.value }}</div>
|
|
221
|
+
{% if stat.change %}
|
|
222
|
+
<div class="stat-desc{{ TONES | modifier(stat.change.tone) }}">{% if stat.change.arrow %}<span aria-hidden="true">{{ stat.change.arrow }}</span> {% endif %}{{ stat.change.text }}</div>
|
|
223
|
+
{% endif %}
|
|
224
|
+
</div>
|
|
225
|
+
{% endfor %}
|
|
226
|
+
</div>
|
|
227
|
+
{% elif view.kind == 'timeSeries' %}
|
|
228
|
+
{{ timeSeries(view) }}
|
|
229
|
+
{% elif view.kind == 'ranked' %}
|
|
230
|
+
<ol aria-label="{{ view.caption }}" class="grid gap-3 text-sm">
|
|
231
|
+
{% for item in view.items %}
|
|
232
|
+
<li class="grid grid-cols-[minmax(0,1fr)_auto] gap-x-3 gap-y-1">
|
|
233
|
+
<span class="truncate">{% if item.href %}<a class="link" href="{{ item.href }}">{{ item.label }}</a>{% else %}{{ item.label }}{% endif %}</span>
|
|
234
|
+
<span class="tabular-nums">{{ item.value }}</span>
|
|
235
|
+
<svg class="col-span-2 h-1.5 w-full" viewBox="0 0 100 6" preserveAspectRatio="none" aria-hidden="true">
|
|
236
|
+
<rect class="fill-base-content/10" width="100" height="6" />
|
|
237
|
+
<rect class="fill-primary" width="{{ item.widthPercent }}" height="6" />
|
|
238
|
+
</svg>
|
|
239
|
+
</li>
|
|
240
|
+
{% endfor %}
|
|
241
|
+
</ol>
|
|
242
|
+
{% elif view.kind == 'bars' %}
|
|
243
|
+
{{ bars(view) }}
|
|
244
|
+
{% elif view.kind == 'calendar' %}
|
|
245
|
+
{{ calendar(view) }}
|
|
246
|
+
{% else %}
|
|
247
|
+
{% if view.caption %}<p class="text-sm font-semibold">{{ view.caption }}</p>{% endif %}
|
|
248
|
+
<p class="text-sm text-base-content/70">No data to show.</p>
|
|
249
|
+
{% endif %}
|
|
250
|
+
{%- endmacro %}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
size xs, sm, md, lg, xl
|
|
17
17
|
style border, dash
|
|
18
|
+
tone warning, a warning-coloured border for a card that flags a problem
|
|
18
19
|
|
|
19
20
|
A value outside its set is a render error.
|
|
20
21
|
|
|
@@ -23,9 +24,10 @@
|
|
|
23
24
|
|
|
24
25
|
{% set SIZES = { xs: 'card-xs', sm: 'card-sm', md: 'card-md', lg: 'card-lg', xl: 'card-xl' } %}
|
|
25
26
|
{% set STYLES = { border: 'card-border', dash: 'card-dash' } %}
|
|
27
|
+
{% set TONES = { warning: 'border-2 border-warning' } %}
|
|
26
28
|
|
|
27
|
-
{% macro card(title='', size=none, style=none) -%}
|
|
28
|
-
<div class="card bg-base-100 shadow-sm{{ SIZES | modifier(size) }}{{ STYLES | modifier(style) }}">
|
|
29
|
+
{% macro card(title='', size=none, style=none, tone=none) -%}
|
|
30
|
+
<div class="card bg-base-100 shadow-sm{{ SIZES | modifier(size) }}{{ STYLES | modifier(style) }}{{ TONES | modifier(tone) }}">
|
|
29
31
|
<div class="card-body">
|
|
30
32
|
{% if title %}
|
|
31
33
|
<h2 class="card-title">{{ title }}</h2>
|
|
@@ -8,38 +8,43 @@
|
|
|
8
8
|
failed the error, in an alert
|
|
9
9
|
interrupted that restarts or crashes cut it off and it will not run again
|
|
10
10
|
|
|
11
|
-
While it is queued or running, `refreshUrl`
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
While it is queued or running, the box names `refreshUrl` in
|
|
12
|
+
`data-job-refresh`. A page that loads static/job-status.js has it fetch
|
|
13
|
+
that page every few seconds and swap in its box with the same
|
|
14
|
+
`data-job-status` until the job ends. It swaps the closest
|
|
15
|
+
`data-job-region` around the box instead when there is one, so a page can
|
|
16
|
+
redraw the controls it hides while the job runs. Without JavaScript,
|
|
17
|
+
`refreshUrl` is a Check again link. `verb` and `unit` word the progress.
|
|
18
|
+
The error and every word passed in are escaped. #}
|
|
14
19
|
{% from "components/alert.njk" import alert %}
|
|
15
20
|
{% from "components/badge.njk" import status %}
|
|
16
21
|
{% from "components/button.njk" import buttonLink %}
|
|
17
22
|
|
|
18
23
|
{% macro jobStatus(job, refreshUrl, verb='Done', unit='items') -%}
|
|
19
|
-
<div class="flex flex-col gap-3">
|
|
24
|
+
<div class="flex flex-col gap-3" data-job-status="{{ job.name }}" data-job-state="{{ job.state }}" data-job-label="{{ job.label }}"{% if job.active %} data-job-refresh="{{ refreshUrl }}"{% endif %}>
|
|
20
25
|
<p class="flex flex-wrap items-center gap-2">
|
|
21
26
|
{{ status(job.state, job.label) }}
|
|
22
27
|
<span class="text-sm"><time datetime="{{ job.at }}">{{ job.at | date('readable') }}</time></span>
|
|
23
28
|
</p>
|
|
24
29
|
{% if job.state == 'queued' %}
|
|
25
|
-
<p>Waiting for the worker to start it.{% if job.requeued %} A restart cut off the last try, so it is queued again as try {{ job.attempt }}.{% endif %}</p>
|
|
30
|
+
<p data-job-message>Waiting for the worker to start it.{% if job.requeued %} A restart cut off the last try, so it is queued again as try {{ job.attempt }}.{% endif %}</p>
|
|
26
31
|
{% elif job.state == 'running' %}
|
|
27
32
|
{% if job.progress and job.progress.total %}
|
|
28
33
|
<progress class="progress progress-primary w-full max-w-md" value="{{ job.progress.done }}" max="{{ job.progress.total }}" aria-label="{{ verb }} {{ job.progress.done }} of {{ job.progress.total }} {{ unit }}"></progress>
|
|
29
|
-
<p>{{ verb }} {{ job.progress.done }} of {{ job.progress.total }} {{ unit }}.{% if job.progress.note %} {{ job.progress.note }}{% endif %}</p>
|
|
34
|
+
<p data-job-message>{{ verb }} {{ job.progress.done }} of {{ job.progress.total }} {{ unit }}.{% if job.progress.note %} {{ job.progress.note }}{% endif %}</p>
|
|
30
35
|
{% else %}
|
|
31
36
|
<progress class="progress progress-primary w-full max-w-md" aria-label="Starting"></progress>
|
|
32
|
-
<p>Starting.</p>
|
|
37
|
+
<p data-job-message>Starting.</p>
|
|
33
38
|
{% endif %}
|
|
34
39
|
{% elif job.state == 'finished' %}
|
|
35
40
|
{% if caller %}{{ caller() }}{% endif %}
|
|
36
41
|
{% elif job.state == 'failed' %}
|
|
37
|
-
{% call alert(color='error', style='soft') %}<span>{{ job.error }}</span>{% endcall %}
|
|
42
|
+
{% call alert(color='error', style='soft') %}<span data-job-message>{{ job.error }}</span>{% endcall %}
|
|
38
43
|
{% elif job.state == 'interrupted' %}
|
|
39
|
-
<p>Restarts or crashes cut it off {{ job.attempt }} times, so it is not run again on its own.</p>
|
|
44
|
+
<p data-job-message>Restarts or crashes cut it off {{ job.attempt }} times, so it is not run again on its own.</p>
|
|
40
45
|
{% endif %}
|
|
41
46
|
{% if job.active %}
|
|
42
|
-
<div>{{ buttonLink('Check again', refreshUrl, style='outline') }}</div>
|
|
47
|
+
<div data-job-check-again>{{ buttonLink('Check again', refreshUrl, style='outline') }}</div>
|
|
43
48
|
{% endif %}
|
|
44
49
|
</div>
|
|
45
50
|
{%- endmacro %}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{# An upload in place: a file picker beside a box, grid or menu that wants a
|
|
2
|
+
file, so nobody has to leave a post for the media library and come back
|
|
3
|
+
with an address (TASK-439).
|
|
4
|
+
|
|
5
|
+
`uploadControl(kind, target, url)` emits a `hidden` block that
|
|
6
|
+
`static/upload-drop.js` reveals, so a page with no script shows nothing that
|
|
7
|
+
does nothing. The script posts each file to `url` and hands the answer to
|
|
8
|
+
the `kind`'s handler, which fills the element whose id is `target`:
|
|
9
|
+
|
|
10
|
+
photos adds a ticked tile to the photo grid; `name` is the prefix of
|
|
11
|
+
the grid's checkbox names
|
|
12
|
+
field sets the text box's value; `preview` names an <img> to show it
|
|
13
|
+
select adds the file to the menu and chooses it
|
|
14
|
+
library reloads the page once the files have landed
|
|
15
|
+
|
|
16
|
+
Dropping files on the target, or on the field around it, does the same.
|
|
17
|
+
`images` asks the server to refuse anything that is not an image. #}
|
|
18
|
+
|
|
19
|
+
{% macro uploadControl(kind, target, url, images=false, accept='', name='', preview='') -%}
|
|
20
|
+
<div class="mt-1 flex flex-wrap items-center gap-2" data-upload-drop="{{ kind }}" data-upload-url="{{ url }}" data-upload-target="{{ target }}"{% if images %} data-upload-images{% endif %}{% if name %} data-upload-name="{{ name }}"{% endif %}{% if preview %} data-upload-preview="{{ preview }}"{% endif %} hidden>
|
|
21
|
+
<label class="text-xs" for="{{ target }}-upload">Upload</label>
|
|
22
|
+
<input id="{{ target }}-upload" type="file" class="file-input file-input-xs w-auto max-w-full"{% if images %} accept="image/*"{% elif accept %} accept="{{ accept }}"{% endif %}{% if kind == 'photos' or kind == 'library' %} multiple{% endif %} data-upload-input />
|
|
23
|
+
<span class="text-xs text-base-content/70">or drop {% if kind == 'photos' or kind == 'library' %}files{% else %}a file{% endif %} here</span>
|
|
24
|
+
<p class="w-full text-xs empty:hidden" role="status" aria-live="polite" data-upload-status></p>
|
|
25
|
+
</div>
|
|
26
|
+
{%- endmacro %}
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
{% else %}
|
|
32
32
|
<ul class="mb-6 flex max-w-3xl flex-col gap-4">
|
|
33
33
|
{% for row in rows %}
|
|
34
|
-
<li>
|
|
34
|
+
<li id="comment-{{ row.id }}">
|
|
35
35
|
{% call card() %}
|
|
36
36
|
<p class="flex flex-wrap items-center gap-x-3 gap-y-1">
|
|
37
37
|
<span class="font-semibold">{{ row.author }}</span>
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
{% extends "layouts/shell.njk" %}
|
|
2
2
|
{% from "components/stat.njk" import stats, stat %}
|
|
3
3
|
{% from "components/card.njk" import card %}
|
|
4
|
-
{% from "components/
|
|
5
|
-
{% from "components/
|
|
4
|
+
{% from "components/badge.njk" import badge %}
|
|
5
|
+
{% from "components/blocks.njk" import block %}
|
|
6
|
+
{% from "components/tabs.njk" import tabs %}
|
|
6
7
|
|
|
7
8
|
{% block title %}Dashboard{% endblock %}
|
|
8
9
|
|
|
10
|
+
{% macro widgetCard(widget, tone=none) -%}
|
|
11
|
+
{% call card(title=widget.title, tone=tone) %}
|
|
12
|
+
{% if widget.status == 'stale' %}
|
|
13
|
+
<p class="text-sm">{{ badge('Stale', color='warning') }} The latest load failed. These figures are from {{ widget.loadedAt }}.</p>
|
|
14
|
+
{% elif widget.status == 'unavailable' %}
|
|
15
|
+
<p>These stats are unavailable right now.</p>
|
|
16
|
+
{% endif %}
|
|
17
|
+
{% for data in widget.blocks %}{{ block(data) }}{% endfor %}
|
|
18
|
+
{% endcall %}
|
|
19
|
+
{%- endmacro %}
|
|
20
|
+
|
|
9
21
|
{% block content %}
|
|
10
22
|
<h1 class="mb-6 text-2xl font-bold">Dashboard</h1>
|
|
11
23
|
|
|
@@ -27,34 +39,23 @@
|
|
|
27
39
|
</div>
|
|
28
40
|
</section>
|
|
29
41
|
|
|
30
|
-
{%
|
|
31
|
-
{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{{ status('published', 'Published') }}
|
|
50
|
-
{% endif %}
|
|
51
|
-
</td>
|
|
52
|
-
</tr>
|
|
53
|
-
{% endfor %}
|
|
54
|
-
</tbody>
|
|
55
|
-
{% endcall %}
|
|
56
|
-
{% else %}
|
|
57
|
-
<p>Nothing written yet.</p>
|
|
58
|
-
{% endif %}
|
|
59
|
-
{% endcall %}
|
|
42
|
+
{% for widget in alerts %}
|
|
43
|
+
<section class="mb-8">{{ widgetCard(widget, tone='warning') }}</section>
|
|
44
|
+
{% endfor %}
|
|
45
|
+
|
|
46
|
+
{% if widgets.length %}
|
|
47
|
+
<div class="@container">
|
|
48
|
+
<div class="mb-3 flex flex-wrap items-center justify-between gap-3">
|
|
49
|
+
<h2 class="text-lg font-semibold">Activity</h2>
|
|
50
|
+
{{ tabs(periods, 'Period', size='sm') }}
|
|
51
|
+
</div>
|
|
52
|
+
<div class="grid grid-cols-1 gap-6 @3xl:grid-cols-2">
|
|
53
|
+
{% for widget in widgets %}
|
|
54
|
+
<div class="min-w-0{% if widget.width == 'full' %} @3xl:col-span-2{% endif %}">
|
|
55
|
+
{{ widgetCard(widget) }}
|
|
56
|
+
</div>
|
|
57
|
+
{% endfor %}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
{% endif %}
|
|
60
61
|
{% endblock %}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
{% from "components/card.njk" import card, cardActions %}
|
|
14
14
|
{% from "components/collapse.njk" import collapse %}
|
|
15
15
|
{% from "components/dropdown.njk" import dropdown %}
|
|
16
|
+
{% from "components/upload.njk" import uploadControl %}
|
|
16
17
|
|
|
17
18
|
{% set ACTION_COLORS = { 'publish': 'primary', 'update': 'primary', 'trash': 'error' } %}
|
|
18
19
|
{% set ACTION_STYLES = { 'trash': 'ghost' } %}
|
|
@@ -20,6 +21,14 @@
|
|
|
20
21
|
|
|
21
22
|
{% set ICON_SIZES = { md: 'size-6', sm: 'size-4' } %}
|
|
22
23
|
|
|
24
|
+
{% macro photoTile(name, url, thumbnail, alt) -%}
|
|
25
|
+
<label class="relative cursor-pointer">
|
|
26
|
+
<input class="peer sr-only" type="checkbox" name="{{ name }}" value="{{ url }}" />
|
|
27
|
+
<img class="aspect-square w-full rounded-box object-cover ring-primary ring-offset-2 ring-offset-base-100 peer-checked:ring-2 peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-base-content" src="{{ thumbnail }}" alt="{{ alt }}" loading="lazy" />
|
|
28
|
+
<span class="badge badge-primary badge-xs absolute end-1 top-1 hidden peer-checked:inline-flex" aria-hidden="true">✓</span>
|
|
29
|
+
</label>
|
|
30
|
+
{%- endmacro %}
|
|
31
|
+
|
|
23
32
|
{% macro icon(path, size='md') -%}
|
|
24
33
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.6" stroke="currentColor" class="shrink-0{{ ICON_SIZES | modifier(size) }}" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="{{ path }}"/></svg>
|
|
25
34
|
{%- endmacro %}
|
|
@@ -152,22 +161,21 @@
|
|
|
152
161
|
</div>
|
|
153
162
|
</div>
|
|
154
163
|
{% endfor %}
|
|
155
|
-
|
|
156
|
-
<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
{
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
{% endif %}
|
|
164
|
+
<fieldset class="fieldset rounded-box">
|
|
165
|
+
<legend class="fieldset-legend">Add from the media library</legend>
|
|
166
|
+
<div class="grid grid-cols-3 gap-2 sm:grid-cols-6" id="editor-photo-picks">
|
|
167
|
+
{% for pick in photos.picks %}
|
|
168
|
+
{{ photoTile(photoFields.url + pick.index, pick.url, pick.thumbnail, pick.alt or pick.url) }}
|
|
169
|
+
{% endfor %}
|
|
170
|
+
</div>
|
|
171
|
+
<template data-upload-tile="editor-photo-picks">{{ photoTile('', '', '', '') }}</template>
|
|
172
|
+
{% if not photos.picks | length %}
|
|
173
|
+
<p class="text-sm" data-upload-empty>The media library has no images yet.</p>
|
|
174
|
+
{% endif %}
|
|
175
|
+
{{ uploadControl('photos', 'editor-photo-picks', uploadsUrl, images=true, name=photoFields.url) }}
|
|
176
|
+
<p class="label block whitespace-normal">A ticked photo is added when you save, with the media library’s alt text. Add them now to write alt text of your own first.</p>
|
|
177
|
+
<div{% if not photos.picks | length %} hidden data-upload-reveal{% endif %}>{{ button('Add the ticked photos', type='submit', name='switch-kind', value=postKind, style='soft', formnovalidate=true) }}</div>
|
|
178
|
+
</fieldset>
|
|
171
179
|
<div class="grid gap-x-4 sm:grid-cols-2">
|
|
172
180
|
{{ field.text('editor-photo-url-' + photos.blank, photoFields.url + photos.blank, 'Or a web address', value='', list='editor-photo-uploads', autocomplete='off', error=(error if errorField == ('editor-photo-url-' + photos.blank) else '')) }}
|
|
173
181
|
{{ field.text('editor-photo-alt-' + photos.blank, photoFields.alt + photos.blank, 'Its alt text', value='') }}
|
|
@@ -224,15 +232,19 @@
|
|
|
224
232
|
{{ placeFields(true) }}
|
|
225
233
|
|
|
226
234
|
{% elif name == 'episode' %}
|
|
227
|
-
{% call field.select('editor-enclosure-url', enclosureFields.url, 'Audio or video file', error=(error if errorField == 'editor-enclosure-url' else ''), hint='
|
|
235
|
+
{% call field.select('editor-enclosure-url', enclosureFields.url, 'Audio or video file', error=(error if errorField == 'editor-enclosure-url' else ''), hint='Feeds carry it as the post’s enclosure and the post page plays it. None removes the recording, its transcript and its other versions.', hintId='editor-enclosure-url-hint') %}
|
|
228
236
|
<option value=""{% if form.enclosure.url == "" %} selected{% endif %}>None</option>
|
|
229
237
|
{% for choice in enclosureChoices.media %}
|
|
230
238
|
<option value="{{ choice.url }}"{% if choice.url == form.enclosure.url %} selected{% endif %}>{{ choice.label }}</option>
|
|
231
239
|
{% endfor %}
|
|
232
240
|
{% endcall %}
|
|
241
|
+
{{ uploadControl('select', 'editor-enclosure-url', uploadsUrl, accept='audio/*,video/*') }}
|
|
233
242
|
<div class="grid gap-x-4 sm:grid-cols-2">
|
|
234
243
|
{{ field.text('editor-enclosure-duration', enclosureFields.duration, 'Duration', value=form.enclosure.duration, inputmode='numeric', autocomplete='off', error=(error if errorField == 'editor-enclosure-duration' else ''), hint='Seconds, or 30:34, or 1:02:03. Leave it empty if you do not know.', hintId='editor-enclosure-duration-hint') }}
|
|
235
|
-
|
|
244
|
+
<div>
|
|
245
|
+
{{ field.text('editor-enclosure-transcript', enclosureFields.transcriptUrl, 'Transcript or captions', value=form.enclosure.transcriptUrl, list='editor-transcript-uploads', autocomplete='off', error=(error if errorField == 'editor-enclosure-transcript' else ''), hintId='editor-enclosure-transcript-hint') }}
|
|
246
|
+
{{ uploadControl('field', 'editor-enclosure-transcript', uploadsUrl, accept='.vtt,.srt,.txt') }}
|
|
247
|
+
</div>
|
|
236
248
|
</div>
|
|
237
249
|
<datalist id="editor-transcript-uploads">
|
|
238
250
|
{% for url in enclosureChoices.transcripts %}
|
|
@@ -256,6 +268,7 @@
|
|
|
256
268
|
{% set n = loop.index0 %}
|
|
257
269
|
{% call collapse(('Version ' + loop.index) if row.url else 'Add a version', row.url, fields=true) %}
|
|
258
270
|
{{ field.text('editor-alternate-url-' + n, enclosureFields.alternate.url + n, 'Address', value=row.url, list='editor-media-uploads', autocomplete='off', error=(error if errorField == ('editor-alternate-url-' + n) else '')) }}
|
|
271
|
+
{{ uploadControl('field', 'editor-alternate-url-' + n, uploadsUrl, accept='audio/*,video/*') }}
|
|
259
272
|
{{ field.text('editor-alternate-type-' + n, enclosureFields.alternate.type + n, 'Type', value=row.type, placeholder='video/mp4', autocomplete='off', spellcheck='false', error=(error if errorField == ('editor-alternate-type-' + n) else '')) }}
|
|
260
273
|
{{ field.text('editor-alternate-title-' + n, enclosureFields.alternate.title + n, 'Title', value=row.title, maxlength='32', error=(error if errorField == ('editor-alternate-title-' + n) else '')) }}
|
|
261
274
|
{{ field.text('editor-alternate-height-' + n, enclosureFields.alternate.height + n, 'Height', value=row.height, inputmode='numeric', autocomplete='off', error=(error if errorField == ('editor-alternate-height-' + n) else '')) }}
|
|
@@ -364,6 +377,7 @@
|
|
|
364
377
|
<img class="h-24 w-16 shrink-0 rounded-box object-cover" id="editor-item-photo-preview"{% if reviewPhotoThumbnail %} src="{{ reviewPhotoThumbnail }}"{% else %} hidden{% endif %} alt="" loading="lazy" />
|
|
365
378
|
<div class="flex min-w-0 flex-1 flex-col">
|
|
366
379
|
{{ field.text('editor-item-photo', reviewFields.photo, '', labelHtml=itemWord('picture'), value=form.review.photo, list='editor-photo-uploads', autocomplete='off', error=(error if errorField == 'editor-item-photo' else ''), hint='An image in the media library or a web address. It is the item’s picture, not a photo for the post: it shows beside the item’s details.', hintId='editor-item-photo-hint') }}
|
|
380
|
+
{{ uploadControl('field', 'editor-item-photo', uploadsUrl, images=true, preview='editor-item-photo-preview') }}
|
|
367
381
|
{{ field.text('editor-item-photo-alt', reviewFields.photoAlt, '', labelHtml=itemWord('picture', ' alt text'), value=form.review.photoAlt) }}
|
|
368
382
|
</div>
|
|
369
383
|
</div>
|
|
@@ -478,7 +492,7 @@
|
|
|
478
492
|
class="flex flex-wrap items-center gap-2"
|
|
479
493
|
id="editor-enhance"
|
|
480
494
|
data-preview-url="{{ previewUrl }}"
|
|
481
|
-
data-upload-url="{{
|
|
495
|
+
data-upload-url="{{ uploadsUrl }}"
|
|
482
496
|
data-kind="{{ kind.type }}"
|
|
483
497
|
>
|
|
484
498
|
{{ button('Preview', type='submit', id='editor-preview-fallback', style='soft', formaction=previewUrl, formtarget='_blank', formnovalidate=true) }}
|
|
@@ -667,6 +681,7 @@
|
|
|
667
681
|
{# The slug and permalink auto-fill, in a file of its own so the policy never
|
|
668
682
|
has to allow an inline script. #}
|
|
669
683
|
<script defer src="{{ assetPrefix }}slug.js"></script>
|
|
684
|
+
<script defer src="{{ assetPrefix }}upload-drop.js"></script>
|
|
670
685
|
{% if kind.type == 'post' %}
|
|
671
686
|
<script defer src="{{ assetPrefix }}location.js"></script>
|
|
672
687
|
{% endif %}
|
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
{% endif %}
|
|
176
176
|
</section>
|
|
177
177
|
|
|
178
|
-
<section id="resend" class="mb-10 max-w-2xl" aria-labelledby="resend-heading">
|
|
178
|
+
<section id="resend" class="mb-10 max-w-2xl" aria-labelledby="resend-heading" data-job-region>
|
|
179
179
|
{% call card() %}
|
|
180
180
|
<h2 id="resend-heading" class="card-title">Resend</h2>
|
|
181
181
|
<p class="max-w-prose">
|
|
@@ -226,7 +226,7 @@
|
|
|
226
226
|
{% endcall %}
|
|
227
227
|
</section>
|
|
228
228
|
|
|
229
|
-
<section>
|
|
229
|
+
<section id="delivery">
|
|
230
230
|
<h2 class="mb-3 text-lg font-semibold">Delivery</h2>
|
|
231
231
|
{% if posts.length %}
|
|
232
232
|
{% call table('Delivery') %}
|
|
@@ -295,4 +295,5 @@
|
|
|
295
295
|
<p>No post has been announced to the fediverse yet.</p>
|
|
296
296
|
{% endif %}
|
|
297
297
|
</section>
|
|
298
|
+
<script defer src="{{ assetPrefix }}job-status.js"></script>
|
|
298
299
|
{% endblock %}
|
|
@@ -44,15 +44,15 @@
|
|
|
44
44
|
{% call card(title='Delete ' + confirm.url + '?', style='border') %}
|
|
45
45
|
<p>
|
|
46
46
|
{{ confirm.references.length }}
|
|
47
|
-
{% if confirm.references.length == 1 %}
|
|
48
|
-
|
|
47
|
+
{% if confirm.references.length == 1 %}thing still uses{% else %}things still use{% endif %}
|
|
48
|
+
it. Deleting the file does not change them, so they will point at nothing.
|
|
49
49
|
</p>
|
|
50
50
|
<ul class="list-disc pl-6">
|
|
51
51
|
{% for reference in confirm.references %}
|
|
52
52
|
<li>
|
|
53
53
|
<a class="link" href="{{ reference.editUrl }}">{{ reference.title }}</a>
|
|
54
54
|
{% if reference.trashed %}{{ status('trashed', 'Trash') }}{% endif %}
|
|
55
|
-
<code>{{ reference.
|
|
55
|
+
<code>{{ reference.where }}</code>
|
|
56
56
|
</li>
|
|
57
57
|
{% endfor %}
|
|
58
58
|
</ul>
|
|
@@ -120,11 +120,12 @@
|
|
|
120
120
|
<li>
|
|
121
121
|
<a class="link link-hover" href="{{ reference.editUrl }}">{{ reference.title }}</a>
|
|
122
122
|
{% if reference.trashed %}{{ status('trashed', 'Trash') }}{% endif %}
|
|
123
|
+
<span class="text-base-content/70">{{ reference.where }}</span>
|
|
123
124
|
</li>
|
|
124
125
|
{% endfor %}
|
|
125
126
|
</ul>
|
|
126
127
|
{% else %}
|
|
127
|
-
<p class="text-sm">Nothing
|
|
128
|
+
<p class="text-sm">Nothing uses it.</p>
|
|
128
129
|
{% endif %}
|
|
129
130
|
</div>
|
|
130
131
|
|