@crvouga/mockingbird-service-payload-cms 1.6.0 → 1.6.1

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/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # Changelog — @crvouga/mockingbird-service-payload-cms
2
2
 
3
- ## 1.6.0 (2026-09-30)
3
+ ## 1.6.1 (2026-09-30)
4
+
5
+ ### Fixes and improvements
6
+
7
+ - keep admin buttons pressed until the action finishes ([0aabfcb](https://github.com/crvouga/mockingbird/commit/0aabfcb5f392aa51e193f9c3f817d5877d92bc6a))
8
+ - size admin select fields like the text inputs beside them ([0fb3ef2](https://github.com/crvouga/mockingbird/commit/0fb3ef2ddbf43376c93a2ae6d87c6c9bf890dafc))
9
+ - keep admin section tabs wired when boot is renamed ([4eda25e](https://github.com/crvouga/mockingbird/commit/4eda25eacd59da048d196f7cc8369d7a02b47bfc))
10
+
11
+ ## 1.6.0 (2026-09-29)
4
12
 
5
13
  ### Features
6
14
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createRuntime
3
- } from "./chunk-XOIML4HJ.js";
3
+ } from "./chunk-T55IEFBD.js";
4
4
 
5
5
  // src/server.ts
6
6
  import { readFile as readFile2 } from "node:fs/promises";
@@ -351,4 +351,4 @@ export {
351
351
  createServer2 as createServer,
352
352
  serveTarget
353
353
  };
354
- //# sourceMappingURL=chunk-OJEHJQZW.js.map
354
+ //# sourceMappingURL=chunk-KCYZ4ISN.js.map
@@ -2110,6 +2110,50 @@ function bootAdmin(config) {
2110
2110
  if (render)
2111
2111
  await render();
2112
2112
  }
2113
+ const delay = (ms) => new Promise((resolve) => {
2114
+ window.setTimeout(resolve, ms);
2115
+ });
2116
+ const confirmAction = async (button, pending, done, work) => {
2117
+ if (button.dataset.pending === "1")
2118
+ return;
2119
+ const label = button.textContent ?? "";
2120
+ const width = button.offsetWidth;
2121
+ button.dataset.pending = "1";
2122
+ button.classList.add("pressed");
2123
+ button.setAttribute("aria-busy", "true");
2124
+ button.style.minWidth = `${width}px`;
2125
+ button.textContent = pending;
2126
+ try {
2127
+ await work();
2128
+ button.textContent = done;
2129
+ await delay(1e3);
2130
+ } catch (error) {
2131
+ showError(error);
2132
+ } finally {
2133
+ button.textContent = label;
2134
+ button.style.minWidth = "";
2135
+ button.classList.remove("pressed");
2136
+ button.removeAttribute("aria-busy");
2137
+ delete button.dataset.pending;
2138
+ }
2139
+ };
2140
+ document.addEventListener("click", (event) => {
2141
+ const target = event.target;
2142
+ if (!(target instanceof Element))
2143
+ return;
2144
+ const button = target.closest("button");
2145
+ if (!(button instanceof HTMLButtonElement) || button.dataset.pending === "1")
2146
+ return;
2147
+ button.classList.add("pressed");
2148
+ const token = String(Date.now());
2149
+ button.dataset.press = token;
2150
+ window.setTimeout(() => {
2151
+ if (button.dataset.press !== token || button.dataset.pending === "1")
2152
+ return;
2153
+ button.classList.remove("pressed");
2154
+ delete button.dataset.press;
2155
+ }, 450);
2156
+ });
2113
2157
  el("namespace", HTMLSelectElement).addEventListener("change", () => {
2114
2158
  state.namespace = el("namespace", HTMLSelectElement).value;
2115
2159
  refresh().catch(showError);
@@ -2120,7 +2164,7 @@ function bootAdmin(config) {
2120
2164
  refresh().catch(showError);
2121
2165
  });
2122
2166
  el("refresh", HTMLButtonElement).addEventListener("click", () => {
2123
- refresh().catch(showError);
2167
+ confirmAction(el("refresh", HTMLButtonElement), "Refreshing...", "Updated", () => refresh()).catch(showError);
2124
2168
  });
2125
2169
  el("collections", HTMLElement).addEventListener("click", (event) => {
2126
2170
  const target = event.target;
@@ -2243,10 +2287,10 @@ function bootAdmin(config) {
2243
2287
  }).then(() => renderFaults()).catch(showError);
2244
2288
  });
2245
2289
  el("fault-clear", HTMLButtonElement).addEventListener("click", () => {
2246
- api("DELETE", "/faults").then(() => renderFaults()).catch(showError);
2290
+ confirmAction(el("fault-clear", HTMLButtonElement), "Clearing...", "Cleared", () => api("DELETE", "/faults").then(() => renderFaults())).catch(showError);
2247
2291
  });
2248
2292
  el("journal-clear", HTMLButtonElement).addEventListener("click", () => {
2249
- api("DELETE", "/requests").then(() => renderJournal()).catch(showError);
2293
+ confirmAction(el("journal-clear", HTMLButtonElement), "Clearing...", "Cleared", () => api("DELETE", "/requests").then(() => renderJournal())).catch(showError);
2250
2294
  });
2251
2295
  el("route-list", HTMLElement).addEventListener("click", (event) => {
2252
2296
  const target = event.target;
@@ -2361,9 +2405,13 @@ function bootAdmin(config) {
2361
2405
  var clientPrelude = [isRecord2, mountAdminBrand, startAdminBrand, faultPresetList, bootAdmin].map((fn) => fn.toString()).join("\n");
2362
2406
  var adminClientSource = (config) => {
2363
2407
  const payload = JSON.stringify(config).replace(/</g, "\\u003c");
2408
+ const entry = bootAdmin.name;
2409
+ if (!/^[A-Za-z_$][\w$]*$/.test(entry)) {
2410
+ throw new Error("admin client cannot call its boot function");
2411
+ }
2364
2412
  return `<script>
2365
2413
  ${clientPrelude}
2366
- bootAdmin(${payload});
2414
+ ${entry}(${payload});
2367
2415
  </script>`;
2368
2416
  };
2369
2417
 
@@ -2577,9 +2625,24 @@ var renderAdminDocument = (service) => {
2577
2625
  .controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
2578
2626
  label.field { display: flex; flex-direction: column; gap: 2px; font-size: 11px; color: var(--faint); }
2579
2627
  label.field input, label.field select, .controls input[type="password"] {
2580
- background: var(--bg-inset); border: 1px solid var(--line); border-radius: 8px;
2581
- padding: 7px 8px; min-height: 36px;
2582
- }
2628
+ background-color: var(--bg-inset); border: 1px solid var(--line); border-radius: 8px;
2629
+ padding: 7px 8px; min-height: 36px; line-height: 1.2;
2630
+ }
2631
+ /* A native menu ignores min-height, so Preset rendered about half as tall as
2632
+ the text fields in the same form. Paint it like those fields. */
2633
+ label.field select {
2634
+ -webkit-appearance: none; appearance: none;
2635
+ padding-right: 28px;
2636
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%2371717a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M2.5 4.5 6 8l3.5-3.5'/%3E%3C/svg%3E");
2637
+ background-repeat: no-repeat; background-position: right 10px center; background-size: 12px 12px;
2638
+ }
2639
+ .stack > .field > input,
2640
+ .stack > .field > select,
2641
+ .stack > .field > textarea,
2642
+ dialog .field > input,
2643
+ dialog .field > select,
2644
+ dialog .field > textarea { width: 100%; }
2645
+ .icon-btn, .btn, .btn-primary, .btn-quiet, .btn-danger, nav.side button { cursor: pointer; }
2583
2646
  .icon-btn, .btn, .btn-primary, .btn-quiet, .btn-danger {
2584
2647
  border-radius: 9px; min-height: 36px; padding: 0 12px; border: 1px solid var(--line);
2585
2648
  background: var(--bg-elev);
@@ -2587,6 +2650,14 @@ var renderAdminDocument = (service) => {
2587
2650
  .btn-primary { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
2588
2651
  .btn-quiet { background: transparent; }
2589
2652
  .btn-danger { color: var(--err); }
2653
+ /* Held after mouseup. Clearing an empty journal changes nothing on screen,
2654
+ so the press itself has to stay visible. */
2655
+ .icon-btn:active, .btn:active, .btn-quiet:active, .btn-danger:active, nav.side button:active,
2656
+ .icon-btn.pressed, .btn.pressed, .btn-quiet.pressed, .btn-danger.pressed, nav.side button.pressed {
2657
+ background: var(--bg-inset); border-color: var(--line-strong); color: var(--ink);
2658
+ }
2659
+ .btn-danger:active, .btn-danger.pressed { background: var(--err-soft); color: var(--err); }
2660
+ .btn-primary:active, .btn-primary.pressed { filter: brightness(0.88); color: var(--accent-ink); }
2590
2661
  /* minmax(0, 1fr): a 1fr column will not shrink below its content, so a long
2591
2662
  record or the full nav row would widen the page past the viewport. */
2592
2663
  .layout {
@@ -2675,8 +2746,16 @@ var renderAdminDocument = (service) => {
2675
2746
  input, select, textarea { font-size: 16px; }
2676
2747
  .brand, .vendor, .controls { width: 100%; }
2677
2748
  label.field, label.field select, label.field input { flex: 1; min-width: 0; }
2678
- .layout { grid-template-columns: minmax(0, 1fr); }
2749
+ /* The layout fills the screen. A single-column grid stretches every auto
2750
+ row, so the tab bar grew with the leftover height and the buttons floated
2751
+ in the middle of it. The bar stays one row; the page below takes the rest. */
2752
+ .layout {
2753
+ grid-template-columns: minmax(0, 1fr);
2754
+ grid-template-rows: auto minmax(0, 1fr);
2755
+ align-content: start;
2756
+ }
2679
2757
  nav.side {
2758
+ align-self: start; height: auto;
2680
2759
  flex-direction: row; align-items: center; overflow-x: auto; min-width: 0;
2681
2760
  border-right: 0; border-bottom: 1px solid var(--line);
2682
2761
  padding: 8px;
@@ -3470,7 +3549,7 @@ var stateAdminRoutes = (routes) => {
3470
3549
  };
3471
3550
 
3472
3551
  // ../core/dist/version.js
3473
- var PACKAGE_VERSION = true ? "1.6.0" : UNRELEASED_VERSION;
3552
+ var PACKAGE_VERSION = true ? "1.6.1" : UNRELEASED_VERSION;
3474
3553
 
3475
3554
  // ../core/dist/webhooks.js
3476
3555
  var json4 = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
@@ -4637,4 +4716,4 @@ export {
4637
4716
  compileWhere,
4638
4717
  PayloadCmsAPI
4639
4718
  };
4640
- //# sourceMappingURL=chunk-XOIML4HJ.js.map
4719
+ //# sourceMappingURL=chunk-T55IEFBD.js.map