@geekity/cms 0.37.0 → 0.39.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.
Files changed (65) hide show
  1. package/admin/components/admin-bar.njk +1 -2
  2. package/admin/components/button.njk +3 -2
  3. package/admin/components/card.njk +4 -2
  4. package/admin/components/dropdown.njk +3 -3
  5. package/admin/layouts/base.njk +1 -1
  6. package/admin/pages/dashboard/home.njk +69 -11
  7. package/admin/pages/documents/editor.njk +6 -6
  8. package/admin/pages/federation/followers.njk +1 -1
  9. package/admin/pages/media/file.njk +1 -1
  10. package/admin/pages/media/library.njk +4 -4
  11. package/admin/pages/plugins/add.njk +46 -0
  12. package/admin/pages/plugins/installed.njk +5 -32
  13. package/admin/pages/settings/general.njk +1 -1
  14. package/admin/pages/tools/export.njk +1 -1
  15. package/admin/pages/tools/maintenance.njk +1 -1
  16. package/admin/pages/users/edit.njk +1 -1
  17. package/admin/src/admin.css +1 -0
  18. package/admin/static/admin.css +24 -1
  19. package/admin/static/dashboard.js +109 -0
  20. package/dist/admin/admin-bar.js +1 -2
  21. package/dist/admin/admin-bar.js.map +1 -1
  22. package/dist/admin/dashboard.d.ts +13 -0
  23. package/dist/admin/dashboard.d.ts.map +1 -0
  24. package/dist/admin/dashboard.js +137 -0
  25. package/dist/admin/dashboard.js.map +1 -0
  26. package/dist/admin/plugins.d.ts.map +1 -1
  27. package/dist/admin/plugins.js +27 -13
  28. package/dist/admin/plugins.js.map +1 -1
  29. package/dist/admin/routes.d.ts.map +1 -1
  30. package/dist/admin/routes.js +5 -46
  31. package/dist/admin/routes.js.map +1 -1
  32. package/dist/admin/templates.d.ts +6 -0
  33. package/dist/admin/templates.d.ts.map +1 -1
  34. package/dist/admin/templates.js +12 -0
  35. package/dist/admin/templates.js.map +1 -1
  36. package/dist/admin/widgets.d.ts +2 -0
  37. package/dist/admin/widgets.d.ts.map +1 -1
  38. package/dist/admin/widgets.js +4 -0
  39. package/dist/admin/widgets.js.map +1 -1
  40. package/dist/cms/server-error.d.ts.map +1 -1
  41. package/dist/cms/server-error.js +1 -2
  42. package/dist/cms/server-error.js.map +1 -1
  43. package/dist/site/dashboard-layout.d.ts +48 -0
  44. package/dist/site/dashboard-layout.d.ts.map +1 -0
  45. package/dist/site/dashboard-layout.js +95 -0
  46. package/dist/site/dashboard-layout.js.map +1 -0
  47. package/dist/site/users.d.ts +15 -0
  48. package/dist/site/users.d.ts.map +1 -1
  49. package/dist/site/users.js +12 -0
  50. package/dist/site/users.js.map +1 -1
  51. package/dist/web/archive.d.ts +2 -0
  52. package/dist/web/archive.d.ts.map +1 -1
  53. package/dist/web/archive.js +6 -1
  54. package/dist/web/archive.js.map +1 -1
  55. package/dist/web/markdown-page.d.ts +5 -0
  56. package/dist/web/markdown-page.d.ts.map +1 -1
  57. package/dist/web/markdown-page.js.map +1 -1
  58. package/dist/web/markdown-representation.js +3 -3
  59. package/dist/web/markdown-representation.js.map +1 -1
  60. package/dist/web/render.d.ts +4 -1
  61. package/dist/web/render.d.ts.map +1 -1
  62. package/dist/web/render.js +27 -7
  63. package/dist/web/render.js.map +1 -1
  64. package/package.json +12 -12
  65. package/themes/default/partials/markdown-footer.md.njk +16 -1
@@ -6,7 +6,6 @@
6
6
  - `barScheme`, `adminColorScheme` of the user's admin theme; `auto` puts no
7
7
  data-scheme on the host.
8
8
  - `cspNonce`, on the admin only.
9
- - `assetPrefix`, where static/admin-bar.js is served from.
10
9
 
11
10
  WordPress's "Howdy," menu, greeting the way this site's owner does. A
12
11
  popover rather than a script: the browser opens and closes it, shuts it on
@@ -45,4 +44,4 @@ html { margin-top: var(--geekity-admin-bar-height) !important; }
45
44
  </div>
46
45
  {% endif %}
47
46
  </nav>
48
- <script src="{{ assetPrefix }}admin-bar.js" defer></script></template></geekity-admin-bar>
47
+ <script src="{{ adminAsset('admin-bar.js') }}" defer></script></template></geekity-admin-bar>
@@ -14,7 +14,7 @@
14
14
  A value outside its set is a render error.
15
15
  `button` also takes `type` (button, unless it submits), `id`, `name`,
16
16
  `value`, `formaction`, `formtarget`, `formnovalidate`, `popovertarget`,
17
- `disabled` and `hidden`. The label is escaped. #}
17
+ `ariaLabel`, `disabled` and `hidden`. The label is escaped. #}
18
18
 
19
19
  {% set COLORS = {
20
20
  neutral: 'btn-neutral',
@@ -45,10 +45,11 @@
45
45
  formtarget='',
46
46
  formnovalidate=false,
47
47
  popovertarget='',
48
+ ariaLabel='',
48
49
  disabled=false,
49
50
  hidden=false
50
51
  ) -%}
51
- <button type="{{ type }}"{% if id %} id="{{ id }}"{% endif %} class="btn{{ COLORS | modifier(color) }}{{ STYLES | modifier(style) }}{{ SIZES | modifier(size) }}{{ SHAPES | modifier(shape) }}{% if active %} btn-active {%- endif %}"{% if name %} name="{{ name }}"{% endif %}{% if value %} value="{{ value }}"{% endif %}{% if formaction %} formaction="{{ formaction }}"{% endif %}{% if formtarget %} formtarget="{{ formtarget }}"{% endif %}{% if formnovalidate %} formnovalidate{% endif %}{% if popovertarget %} popovertarget="{{ popovertarget }}"{% endif %}{% if disabled %} disabled{% endif %}{% if hidden %} hidden{% endif %}>{{ label }}</button>
52
+ <button type="{{ type }}"{% if id %} id="{{ id }}"{% endif %} class="btn{{ COLORS | modifier(color) }}{{ STYLES | modifier(style) }}{{ SIZES | modifier(size) }}{{ SHAPES | modifier(shape) }}{% if active %} btn-active {%- endif %}"{% if name %} name="{{ name }}"{% endif %}{% if value %} value="{{ value }}"{% endif %}{% if formaction %} formaction="{{ formaction }}"{% endif %}{% if formtarget %} formtarget="{{ formtarget }}"{% endif %}{% if formnovalidate %} formnovalidate{% endif %}{% if popovertarget %} popovertarget="{{ popovertarget }}"{% endif %}{% if ariaLabel %} aria-label="{{ ariaLabel }}"{% endif %}{% if disabled %} disabled{% endif %}{% if hidden %} hidden{% endif %}>{{ label }}</button>
52
53
  {%- endmacro %}
53
54
 
54
55
  {% macro buttonLink(label, href, color=none, style=none, size='sm', shape=none, active=false) -%}
@@ -20,7 +20,9 @@
20
20
  A value outside its set is a render error.
21
21
 
22
22
  `{% call cardActions() %}…{% endcall %}`, inside a card's body, is the row
23
- of buttons at its foot: `<div class="card-actions justify-end">`. #}
23
+ of buttons at its foot: `<div class="card-actions mt-2 justify-end">`. The
24
+ margin is there because card-body's gap spaces only its own children, and
25
+ the row usually sits inside a form, under the last field. #}
24
26
 
25
27
  {% set SIZES = { xs: 'card-xs', sm: 'card-sm', md: 'card-md', lg: 'card-lg', xl: 'card-xl' } %}
26
28
  {% set STYLES = { border: 'card-border', dash: 'card-dash' } %}
@@ -38,5 +40,5 @@
38
40
  {%- endmacro %}
39
41
 
40
42
  {% macro cardActions() -%}
41
- <div class="card-actions justify-end">{{ caller() }}</div>
43
+ <div class="card-actions mt-2 justify-end">{{ caller() }}</div>
42
44
  {%- endmacro %}
@@ -10,7 +10,7 @@
10
10
  `id` must be unique on the page. The body is markup. The label is escaped.
11
11
 
12
12
  The trigger is `button` from `components/button.njk` and takes its
13
- `color`, `style` and `size` (sm by default). `placement` is start, center,
13
+ `color`, `style`, `size` (sm by default) and `ariaLabel`. `placement` is start, center,
14
14
  end, top, bottom, left or right, each mapping to its `dropdown-*` class. A
15
15
  value outside its set is a render error. #}
16
16
 
@@ -26,7 +26,7 @@
26
26
  right: 'dropdown-right'
27
27
  } %}
28
28
 
29
- {% macro dropdown(id, label, color=none, style=none, size='sm', placement=none) -%}
30
- {{ button(label, color=color, style=style, size=size, popovertarget=id) }}
29
+ {% macro dropdown(id, label, color=none, style=none, size='sm', placement=none, ariaLabel='') -%}
30
+ {{ button(label, color=color, style=style, size=size, popovertarget=id, ariaLabel=ariaLabel) }}
31
31
  <div class="dropdown rounded-box bg-base-100 z-1 w-52 shadow-sm{{ PLACEMENTS | modifier(placement) }}" popover id="{{ id }}">{{ caller() }}</div>
32
32
  {%- endmacro %}
@@ -8,7 +8,7 @@
8
8
  <meta name="viewport" content="width=device-width, initial-scale=1" />
9
9
  <title>{% block title %}Admin{% endblock %}{% if site.title %} · {{ site.title }}{% endif %}</title>
10
10
  <meta name="robots" content="noindex, nofollow" />
11
- <link rel="stylesheet" href="{{ assetPrefix }}admin.css" />
11
+ <link rel="stylesheet" href="{{ adminAsset('admin.css') }}" />
12
12
  </head>
13
13
  <body class="min-h-screen bg-base-200 text-base-content">
14
14
  {# First on every screen, so a keyboard gets past the bar and the menu in
@@ -4,20 +4,53 @@
4
4
  {% from "components/badge.njk" import badge %}
5
5
  {% from "components/blocks.njk" import block %}
6
6
  {% from "components/tabs.njk" import tabs %}
7
+ {% from "components/button.njk" import button %}
8
+ {% from "components/dropdown.njk" import dropdown %}
7
9
 
8
10
  {% block title %}Dashboard{% endblock %}
9
11
 
12
+ {% macro widgetBody(widget) -%}
13
+ {% if widget.status == 'stale' %}
14
+ <p class="text-sm">{{ badge('Stale', color='warning') }} The latest load failed. These figures are from {{ widget.loadedAt }}.</p>
15
+ {% elif widget.status == 'unavailable' %}
16
+ <p>These stats are unavailable right now.</p>
17
+ {% endif %}
18
+ {% for data in widget.blocks %}{{ block(data) }}{% endfor %}
19
+ {%- endmacro %}
20
+
10
21
  {% macro widgetCard(widget, tone=none) -%}
11
22
  {% 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 %}
23
+ {{ widgetBody(widget) }}
18
24
  {% endcall %}
19
25
  {%- endmacro %}
20
26
 
27
+ {% macro arrangedCard(widget) -%}
28
+ <div class="card bg-base-100 shadow-sm">
29
+ <div class="card-body">
30
+ <div class="flex flex-wrap items-start justify-between gap-2">
31
+ <h2 class="card-title">{{ widget.title }}</h2>
32
+ <form method="post" action="{{ layoutUrl }}" class="flex shrink-0 items-center gap-1">
33
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
34
+ <input type="hidden" name="widget" value="{{ widget.key }}" />
35
+ {% if period %}<input type="hidden" name="period" value="{{ period }}" />{% endif %}
36
+ {% for key in widget.shown %}<input type="hidden" name="shown" value="{{ key }}" />{% endfor %}
37
+ {{ button('↑', type='submit', name='action', value='earlier', style='ghost', size='xs', shape='square', ariaLabel='Move ' + widget.title + ' earlier', disabled=widget.first) }}
38
+ {{ button('↓', type='submit', name='action', value='later', style='ghost', size='xs', shape='square', ariaLabel='Move ' + widget.title + ' later', disabled=widget.last) }}
39
+ {% if widget.collapsed %}
40
+ {{ button('+', type='submit', name='action', value='expand', style='ghost', size='xs', shape='square', ariaLabel='Expand ' + widget.title) }}
41
+ {% else %}
42
+ {{ button('−', type='submit', name='action', value='collapse', style='ghost', size='xs', shape='square', ariaLabel='Collapse ' + widget.title) }}
43
+ {% endif %}
44
+ {{ button('✕', type='submit', name='action', value='remove', style='ghost', size='xs', shape='square', ariaLabel='Remove ' + widget.title) }}
45
+ </form>
46
+ </div>
47
+ {% if not widget.collapsed %}
48
+ {{ widgetBody(widget) }}
49
+ {% endif %}
50
+ </div>
51
+ </div>
52
+ {%- endmacro %}
53
+
21
54
  {% block content %}
22
55
  <h1 class="mb-6 text-2xl font-bold">Dashboard</h1>
23
56
 
@@ -43,19 +76,44 @@
43
76
  <section class="mb-8">{{ widgetCard(widget, tone='warning') }}</section>
44
77
  {% endfor %}
45
78
 
46
- {% if widgets.length %}
79
+ {% if arrangeable %}
47
80
  <div class="@container">
48
81
  <div class="mb-3 flex flex-wrap items-center justify-between gap-3">
49
82
  <h2 class="text-lg font-semibold">Activity</h2>
50
- {{ tabs(periods, 'Period', size='sm') }}
83
+ <div class="flex items-center gap-2">
84
+ {{ tabs(periods, 'Period', size='sm') }}
85
+ {% call dropdown('dashboard-cards', '⚙', style='ghost', placement='end', ariaLabel='Removed cards') %}
86
+ <div class="p-3">
87
+ <p class="mb-2 text-sm font-semibold">Removed cards</p>
88
+ {% if removed.length %}
89
+ <ul class="space-y-2">
90
+ {% for card in removed %}
91
+ <li>
92
+ <form method="post" action="{{ layoutUrl }}" class="flex items-center justify-between gap-2">
93
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
94
+ <input type="hidden" name="widget" value="{{ card.key }}" />
95
+ {% if period %}<input type="hidden" name="period" value="{{ period }}" />{% endif %}
96
+ <span class="min-w-0 text-sm">{{ card.title }}</span>
97
+ {{ button('Add back', type='submit', name='action', value='restore', size='xs', ariaLabel='Add back ' + card.title) }}
98
+ </form>
99
+ </li>
100
+ {% endfor %}
101
+ </ul>
102
+ {% else %}
103
+ <p class="text-sm">No cards are removed.</p>
104
+ {% endif %}
105
+ </div>
106
+ {% endcall %}
107
+ </div>
51
108
  </div>
52
- <div class="grid grid-cols-1 gap-6 @3xl:grid-cols-2">
109
+ <div class="grid grid-cols-1 gap-6 @3xl:grid-cols-2" data-dashboard-cards data-layout-url="{{ layoutUrl }}">
53
110
  {% for widget in widgets %}
54
- <div class="min-w-0{% if widget.width == 'full' %} @3xl:col-span-2{% endif %}">
55
- {{ widgetCard(widget) }}
111
+ <div class="min-w-0{% if widget.width == 'full' %} @3xl:col-span-2{% endif %}" data-dashboard-card="{{ widget.key }}">
112
+ {{ arrangedCard(widget) }}
56
113
  </div>
57
114
  {% endfor %}
58
115
  </div>
59
116
  </div>
117
+ <script defer src="{{ adminAsset('dashboard.js') }}"></script>
60
118
  {% endif %}
61
119
  {% endblock %}
@@ -674,21 +674,21 @@
674
674
  <script
675
675
  type="module"
676
676
  id="editor-script"
677
- src="{{ assetPrefix }}editor.js"
677
+ src="{{ adminAsset('editor.js') }}"
678
678
  nonce="{{ cspNonce }}"
679
679
  ></script>
680
680
 
681
681
  {# The slug and permalink auto-fill, in a file of its own so the policy never
682
682
  has to allow an inline script. #}
683
- <script defer src="{{ assetPrefix }}slug.js"></script>
684
- <script defer src="{{ assetPrefix }}upload-drop.js"></script>
683
+ <script defer src="{{ adminAsset('slug.js') }}"></script>
684
+ <script defer src="{{ adminAsset('upload-drop.js') }}"></script>
685
685
  {% if kind.type == 'post' %}
686
- <script defer src="{{ assetPrefix }}location.js"></script>
686
+ <script defer src="{{ adminAsset('location.js') }}"></script>
687
687
  {% endif %}
688
688
  {% if editorActions | length %}
689
- <script defer src="{{ assetPrefix }}editor-actions.js"></script>
689
+ <script defer src="{{ adminAsset('editor-actions.js') }}"></script>
690
690
  {% endif %}
691
691
  {% if sections and sections.shown.review %}
692
- <script defer src="{{ assetPrefix }}item-lookup.js"></script>
692
+ <script defer src="{{ adminAsset('item-lookup.js') }}"></script>
693
693
  {% endif %}
694
694
  {% endblock %}
@@ -295,5 +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
+ <script defer src="{{ adminAsset('job-status.js') }}"></script>
299
299
  {% endblock %}
@@ -139,5 +139,5 @@
139
139
  </div>
140
140
  </div>
141
141
 
142
- <script defer src="{{ assetPrefix }}copy.js"></script>
142
+ <script defer src="{{ adminAsset('copy.js') }}"></script>
143
143
  {% endblock %}
@@ -130,8 +130,8 @@
130
130
  </p>
131
131
  {% endif %}
132
132
 
133
- <script defer src="{{ assetPrefix }}copy.js"></script>
134
- <script defer src="{{ assetPrefix }}upload-drop.js"></script>
135
- <script defer src="{{ assetPrefix }}media.js"></script>
136
- <script defer src="{{ assetPrefix }}job-status.js"></script>
133
+ <script defer src="{{ adminAsset('copy.js') }}"></script>
134
+ <script defer src="{{ adminAsset('upload-drop.js') }}"></script>
135
+ <script defer src="{{ adminAsset('media.js') }}"></script>
136
+ <script defer src="{{ adminAsset('job-status.js') }}"></script>
137
137
  {% endblock %}
@@ -0,0 +1,46 @@
1
+ {# /admin/plugins/add: install a plugin from the npm registry (TASK-466).
2
+
3
+ Reached from the Add plugin button on the Plugins screen. A refused or
4
+ failed install comes back here with what was typed still in the boxes. #}
5
+ {% extends "layouts/shell.njk" %}
6
+ {% from "components/button.njk" import button %}
7
+ {% from "components/card.njk" import card, cardActions %}
8
+ {% import "components/fields.njk" as fields %}
9
+
10
+ {% block title %}Add plugin{% endblock %}
11
+
12
+ {% block content %}
13
+ <h1 class="mb-6 text-2xl font-bold">Add plugin</h1>
14
+
15
+ <div class="flex max-w-2xl flex-col gap-6">
16
+ {% call card() %}
17
+ <p class="text-sm">
18
+ A plugin runs as the site, with access to everything under <code>data/</code>,
19
+ the accounts and keys and other plugins' secrets. Add only plugins you trust.
20
+ </p>
21
+ {% if problems.package or problems.password %}
22
+ {% call fields.summary('Nothing was installed. Fix the fields marked below and try again.') %}
23
+ {{ fields.problem('plugin-package', problems.package) }}
24
+ {{ fields.problem('plugin-add-password', problems.password) }}
25
+ {% endcall %}
26
+ {% endif %}
27
+ <form id="plugin-add" method="post" action="{{ addUrl }}">
28
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
29
+ {{ fields.text('plugin-package', 'package', 'Package', value=package,
30
+ hint='An npm package name, such as @geekity/plugin-llm.', error=problems.package,
31
+ required=true,
32
+ spellcheck='false', autocomplete='off') }}
33
+ {{ fields.text('plugin-version', 'version', 'Version (optional)', value=version,
34
+ hint='A version, a range or a dist-tag. Empty takes latest.', spellcheck='false',
35
+ autocomplete='off') }}
36
+ {{ fields.password('plugin-add-password', 'password', 'Your password',
37
+ error=problems.password, autocomplete='current-password', required=true) }}
38
+ {% call cardActions() %}
39
+ {{ button('Add plugin', type='submit', color='primary') }}
40
+ {% endcall %}
41
+ </form>
42
+ {% endcall %}
43
+
44
+ <p class="text-sm"><a class="link" href="{{ backUrl }}">Back to Plugins</a></p>
45
+ </div>
46
+ {% endblock %}
@@ -8,16 +8,17 @@
8
8
  (TASK-288). #}
9
9
  {% extends "layouts/shell.njk" %}
10
10
  {% from "components/badge.njk" import status %}
11
- {% from "components/button.njk" import button %}
11
+ {% from "components/button.njk" import button, buttonLink %}
12
12
  {% from "components/card.njk" import card, cardActions %}
13
- {% from "components/button.njk" import buttonLink %}
14
- {% import "components/fields.njk" as fields %}
15
13
  {% from "components/table.njk" import table %}
16
14
 
17
15
  {% block title %}Plugins{% endblock %}
18
16
 
19
17
  {% block content %}
20
- <h1 class="mb-6 text-2xl font-bold">Plugins</h1>
18
+ <div class="mb-6 flex flex-wrap items-center gap-4">
19
+ <h1 class="text-2xl font-bold">Plugins</h1>
20
+ {% if installer == 'on' %}{{ buttonLink('Add plugin', addUrl, color='primary') }}{% endif %}
21
+ </div>
21
22
 
22
23
  {% if reloaded %}
23
24
  <div role="status" class="alert alert-success mb-6"><span>Plugins reloaded.</span></div>
@@ -55,34 +56,6 @@
55
56
 
56
57
  {% if installer == 'on' %}
57
58
  <div class="mb-8 grid grid-cols-1 items-start gap-6 xl:grid-cols-2">
58
- {% call card(title="Add plugin") %}
59
- <p class="text-sm">
60
- A plugin runs as the site, with access to everything under <code>data/</code>,
61
- the accounts and keys and other plugins' secrets. Add only plugins you trust.
62
- </p>
63
- {% if addProblems.package or addProblems.password %}
64
- {% call fields.summary('Nothing was installed. Fix the fields marked below and try again.') %}
65
- {{ fields.problem('plugin-package', addProblems.package) }}
66
- {{ fields.problem('plugin-add-password', addProblems.password) }}
67
- {% endcall %}
68
- {% endif %}
69
- <form id="plugin-add" method="post" action="{{ add.url }}">
70
- <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
71
- {{ fields.text('plugin-package', 'package', 'Package', value=add.package,
72
- hint='An npm package name, such as @geekity/plugin-llm.', error=addProblems.package,
73
- required=true,
74
- spellcheck='false', autocomplete='off') }}
75
- {{ fields.text('plugin-version', 'version', 'Version (optional)', value=add.version,
76
- hint='A version, a range or a dist-tag. Empty takes latest.', spellcheck='false',
77
- autocomplete='off') }}
78
- {{ fields.password('plugin-add-password', 'password', 'Your password',
79
- error=addProblems.password, autocomplete='current-password', required=true) }}
80
- {% call cardActions() %}
81
- {{ button('Add plugin', type='submit', color='primary') }}
82
- {% endcall %}
83
- </form>
84
- {% endcall %}
85
-
86
59
  {% call card(title="Updates") %}
87
60
  <p class="text-sm">
88
61
  {% if checkedAt %}Last checked {{ checkedAt }}.{% else %}Not checked since this server started.{% endif %}
@@ -54,7 +54,7 @@
54
54
  {{ field.text('settings-icon', fields.icon, 'Site icon', form.icon,
55
55
  error=problems.icon, hintHtml=iconHint) }}
56
56
  {{ uploadControl('field', 'settings-icon', uploadsUrl, images=true) }}
57
- <script defer src="{{ assetPrefix }}upload-drop.js"></script>
57
+ <script defer src="{{ adminAsset('upload-drop.js') }}"></script>
58
58
 
59
59
  <div class="flex items-center gap-4">
60
60
  {% if iconPreview %}
@@ -88,5 +88,5 @@
88
88
  {% endif %}
89
89
  </div>
90
90
  </div>
91
- <script defer src="{{ assetPrefix }}job-status.js"></script>
91
+ <script defer src="{{ adminAsset('job-status.js') }}"></script>
92
92
  {% endblock %}
@@ -96,5 +96,5 @@
96
96
  {% endcall %}
97
97
  </section>
98
98
  </div>
99
- <script defer src="{{ assetPrefix }}job-status.js"></script>
99
+ <script defer src="{{ adminAsset('job-status.js') }}"></script>
100
100
  {% endblock %}
@@ -282,5 +282,5 @@
282
282
  {% endif %}
283
283
  {% endcall %}
284
284
  </div>
285
- <script defer src="{{ assetPrefix }}upload-drop.js"></script>
285
+ <script defer src="{{ adminAsset('upload-drop.js') }}"></script>
286
286
  {% endblock %}
@@ -5,6 +5,7 @@
5
5
  @source '../../editor/look.ts';
6
6
  @source '../static/media.js';
7
7
  @source '../static/upload-drop.js';
8
+ @source '../static/dashboard.js';
8
9
 
9
10
  @plugin 'daisyui' {
10
11
  themes:
@@ -7500,6 +7500,10 @@
7500
7500
  rotate: 45deg;
7501
7501
  }
7502
7502
 
7503
+ .cursor-grab {
7504
+ cursor: grab;
7505
+ }
7506
+
7503
7507
  .cursor-pointer {
7504
7508
  cursor: pointer;
7505
7509
  }
@@ -7998,7 +8002,17 @@
7998
8002
  white-space: pre-wrap;
7999
8003
  }
8000
8004
 
8001
- .text-base-content, .text-base-content\/70 {
8005
+ .text-base-content, .text-base-content\/60 {
8006
+ color: var(--color-base-content);
8007
+ }
8008
+
8009
+ @supports (color: color-mix(in lab, red, red)) {
8010
+ .text-base-content\/60 {
8011
+ color: color-mix(in oklab, var(--color-base-content) 60%, transparent);
8012
+ }
8013
+ }
8014
+
8015
+ .text-base-content\/70 {
8002
8016
  color: var(--color-base-content);
8003
8017
  }
8004
8018
 
@@ -8029,6 +8043,10 @@
8029
8043
  font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );
8030
8044
  }
8031
8045
 
8046
+ .opacity-50 {
8047
+ opacity: .5;
8048
+ }
8049
+
8032
8050
  .opacity-70 {
8033
8051
  opacity: .7;
8034
8052
  }
@@ -8097,6 +8115,11 @@
8097
8115
  outline-style: dashed;
8098
8116
  }
8099
8117
 
8118
+ .select-none {
8119
+ -webkit-user-select: none;
8120
+ user-select: none;
8121
+ }
8122
+
8100
8123
  :is(.\*\:align-top > *) {
8101
8124
  vertical-align: top;
8102
8125
  }
@@ -0,0 +1,109 @@
1
+ (function () {
2
+ var grid = document.querySelector('[data-dashboard-cards]');
3
+ if (!grid) return;
4
+ var url = grid.getAttribute('data-layout-url');
5
+
6
+ var live = document.createElement('div');
7
+ live.className = 'sr-only';
8
+ live.setAttribute('role', 'status');
9
+ document.body.appendChild(live);
10
+
11
+ var dragged = null;
12
+ var before = '';
13
+
14
+ Array.prototype.forEach.call(cards(), function (card) {
15
+ var title = card.querySelector('.card-title');
16
+ var handle = document.createElement('span');
17
+ handle.className = 'cursor-grab select-none text-base-content/60';
18
+ handle.setAttribute('aria-hidden', 'true');
19
+ handle.setAttribute('title', 'Drag to move');
20
+ handle.textContent = '⠿';
21
+ title.insertBefore(handle, title.firstChild);
22
+
23
+ /* Only the handle starts a drag, so text in the card still selects. */
24
+ handle.addEventListener('pointerdown', function () {
25
+ card.draggable = true;
26
+ });
27
+ card.addEventListener('dragstart', function (event) {
28
+ dragged = card;
29
+ before = order().join('\n');
30
+ event.dataTransfer.effectAllowed = 'move';
31
+ event.dataTransfer.setData('text/plain', card.getAttribute('data-dashboard-card'));
32
+ card.classList.add('opacity-50');
33
+ });
34
+ card.addEventListener('dragend', function () {
35
+ card.draggable = false;
36
+ card.classList.remove('opacity-50');
37
+ dragged = null;
38
+ if (order().join('\n') !== before) save(card);
39
+ });
40
+ });
41
+
42
+ grid.addEventListener('dragover', function (event) {
43
+ if (!dragged) return;
44
+ event.preventDefault();
45
+ var over = event.target.closest('[data-dashboard-card]');
46
+ if (!over || over === dragged) return;
47
+ var past = isPastDiagonal(over.getBoundingClientRect(), event);
48
+ if (past && over.nextElementSibling !== dragged) over.after(dragged);
49
+ else if (!past && over.previousElementSibling !== dragged) over.before(dragged);
50
+ });
51
+ grid.addEventListener('drop', function (event) {
52
+ if (dragged) event.preventDefault();
53
+ });
54
+
55
+ function isPastDiagonal(box, event) {
56
+ return (event.clientX - box.left) / box.width + (event.clientY - box.top) / box.height > 1;
57
+ }
58
+
59
+ function cards() {
60
+ return Array.prototype.slice.call(grid.querySelectorAll('[data-dashboard-card]'));
61
+ }
62
+
63
+ function order() {
64
+ return cards().map(function (card) {
65
+ return card.getAttribute('data-dashboard-card');
66
+ });
67
+ }
68
+
69
+ function save(card) {
70
+ var form = card.querySelector('form');
71
+ var body = new URLSearchParams();
72
+ body.append('csrf_token', form.elements['csrf_token'].value);
73
+ body.append('action', 'order');
74
+ order().forEach(function (key) {
75
+ body.append('order', key);
76
+ });
77
+ fetch(url, {
78
+ method: 'POST',
79
+ body: body,
80
+ credentials: 'same-origin',
81
+ redirect: 'manual',
82
+ })
83
+ .then(function (response) {
84
+ if (response.type !== 'opaqueredirect' && !response.ok) {
85
+ throw new Error(String(response.status));
86
+ }
87
+ moveButtons();
88
+ var all = cards();
89
+ live.textContent =
90
+ card.querySelector('.card-title').textContent.replace('⠿', '').trim() +
91
+ ' moved to position ' +
92
+ String(all.indexOf(card) + 1) +
93
+ ' of ' +
94
+ String(all.length) +
95
+ '.';
96
+ })
97
+ .catch(function () {
98
+ window.location.reload();
99
+ });
100
+ }
101
+
102
+ function moveButtons() {
103
+ var all = cards();
104
+ all.forEach(function (card, index) {
105
+ card.querySelector('button[value="earlier"]').disabled = index === 0;
106
+ card.querySelector('button[value="later"]').disabled = index === all.length - 1;
107
+ });
108
+ }
109
+ })();
@@ -1,5 +1,5 @@
1
1
  import { adminColorScheme } from '../site/admin-theme.js';
2
- import { ADMIN_ASSET_PREFIX, ADMIN_PREFIX, editUserPath } from '../site/admin-paths.js';
2
+ import { ADMIN_PREFIX, editUserPath } from '../site/admin-paths.js';
3
3
  import { editorPath, newEditorPath, PAGE_SCREENS, POST_SCREENS } from './documents.js';
4
4
  import { LOGOUT_PATH } from './routes.js';
5
5
  import { ADMIN_TEMPLATES, createAdminTemplateEnvironment } from './templates.js';
@@ -85,7 +85,6 @@ function renderBar(c, account) {
85
85
  ],
86
86
  me: { name: user.profile?.displayName ?? user.username, url: editUserPath(user.id) },
87
87
  barScheme: adminColorScheme(user.adminTheme),
88
- assetPrefix: ADMIN_ASSET_PREFIX,
89
88
  logoutUrl: LOGOUT_PATH,
90
89
  csrfToken: account.csrfToken,
91
90
  notice: shown === undefined ? undefined : unpublishedNotice(c, shown),
@@ -1 +1 @@
1
- {"version":3,"file":"admin-bar.js","sourceRoot":"","sources":["../../src/admin/admin-bar.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"admin-bar.js","sourceRoot":"","sources":["../../src/admin/admin-bar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Hono } from 'hono';
2
+ import type { GeekityEnv } from '../web/env.ts';
3
+ import type { AdminRender } from './documents.ts';
4
+ export declare const DASHBOARD_LAYOUT_PATH = "/admin/dashboard/layout";
5
+ /**
6
+ * The dashboard: the stat tiles, the alert cards, and the activity cards in
7
+ * the order the signed-in user arranged them. Collapsed and removed cards are
8
+ * never handed to the widget board, so their widgets do not load.
9
+ */
10
+ export declare function mountDashboard(app: Hono<GeekityEnv>, options: {
11
+ render: AdminRender;
12
+ }): void;
13
+ //# sourceMappingURL=dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/admin/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,MAAM,CAAC;AAG1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAahD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAelD,eAAO,MAAM,qBAAqB,4BAAqC,CAAC;AAExE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GAAG,IAAI,CA2F5F"}