@emdash-cms/admin 0.24.1 → 0.26.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/dist/{LocaleDirectionProvider-CK7aJ2Lb.js → LocaleDirectionProvider-elsAJo9B.js} +23 -11
- package/dist/LocaleDirectionProvider-elsAJo9B.js.map +1 -0
- package/dist/{config-CPRInh7U.d.ts → config-DpQrGzsu.d.ts} +1 -1
- package/dist/{config-CPRInh7U.d.ts.map → config-DpQrGzsu.d.ts.map} +1 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +178 -117
- package/dist/index.js.map +1 -1
- package/dist/locales/hu/messages.mjs +1 -0
- package/dist/locales/index.d.ts +1 -1
- package/dist/locales/index.js +1 -1
- package/dist/locales/tr/messages.mjs +1 -0
- package/dist/{messages-DjQX9PJY.js → messages-3sesjT8a.js} +1 -1
- package/dist/{messages-DjQX9PJY.js.map → messages-3sesjT8a.js.map} +1 -1
- package/dist/{messages-Bh2bSu3x.js → messages-BBhuGu6K.js} +1 -1
- package/dist/{messages-Bh2bSu3x.js.map → messages-BBhuGu6K.js.map} +1 -1
- package/dist/{messages-D6wHPGil.js → messages-C6_69h5z.js} +1 -1
- package/dist/{messages-D6wHPGil.js.map → messages-C6_69h5z.js.map} +1 -1
- package/dist/{messages-n6HQSjDA.js → messages-ChEF0PwF.js} +1 -1
- package/dist/{messages-n6HQSjDA.js.map → messages-ChEF0PwF.js.map} +1 -1
- package/dist/{messages-cWzWbWxk.js → messages-Cqpd51ck.js} +1 -1
- package/dist/{messages-cWzWbWxk.js.map → messages-Cqpd51ck.js.map} +1 -1
- package/dist/{messages-Crei9McK.js → messages-DBzgje1G.js} +1 -1
- package/dist/{messages-Crei9McK.js.map → messages-DBzgje1G.js.map} +1 -1
- package/dist/{messages-B43-WzBC.js → messages-DEC9v1nR.js} +1 -1
- package/dist/{messages-B43-WzBC.js.map → messages-DEC9v1nR.js.map} +1 -1
- package/dist/{messages-BTDhbVyJ.js → messages-DOJAmOSK.js} +1 -1
- package/dist/{messages-BTDhbVyJ.js.map → messages-DOJAmOSK.js.map} +1 -1
- package/dist/messages-DjTHn-jd.js +6 -0
- package/dist/messages-DjTHn-jd.js.map +1 -0
- package/dist/{messages-BdciNNnG.js → messages-KiGKwzQW.js} +1 -1
- package/dist/{messages-BdciNNnG.js.map → messages-KiGKwzQW.js.map} +1 -1
- package/dist/{messages-DlzFD1ts.js → messages-RWuknKyd.js} +1 -1
- package/dist/{messages-DlzFD1ts.js.map → messages-RWuknKyd.js.map} +1 -1
- package/dist/messages-itTyZdsM.js +6 -0
- package/dist/messages-itTyZdsM.js.map +1 -0
- package/package.json +2 -2
- package/dist/LocaleDirectionProvider-CK7aJ2Lb.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { c as fetchAuthMode, d as throwResponseError, i as fetchPlugins, l as fetchManifest, n as enablePlugin, o as API_BASE, r as fetchPlugin, s as apiFetch, t as disablePlugin, u as parseApiResponse } from "./plugins-G9Z9NQ7n.js";
|
|
2
|
-
import { a as SUPPORTED_LOCALES, i as DEFAULT_LOCALE, l as resolveLocale, n as useLocale, o as SUPPORTED_LOCALE_CODES, s as getLocaleDir, t as LocaleDirectionProvider } from "./LocaleDirectionProvider-
|
|
2
|
+
import { a as SUPPORTED_LOCALES, i as DEFAULT_LOCALE, l as resolveLocale, n as useLocale, o as SUPPORTED_LOCALE_CODES, s as getLocaleDir, t as LocaleDirectionProvider } from "./LocaleDirectionProvider-elsAJo9B.js";
|
|
3
3
|
import "./locales/index.js";
|
|
4
|
-
import { Autocomplete, Badge, Button, Checkbox, ClipboardText, CommandPalette, Dialog, Input, InputArea, Label, LinkButton, LinkProvider, Loader, Popover, Select, Sidebar as KumoSidebar, Switch, Tabs, Toast, Toasty, Tooltip, buttonVariants, useSidebar } from "@cloudflare/kumo";
|
|
4
|
+
import { Autocomplete, Badge, Button, Checkbox, ClipboardText, Combobox, CommandPalette, Dialog, Input, InputArea, Label, LinkButton, LinkProvider, Loader, Popover, Select, Sidebar as KumoSidebar, Switch, Tabs, Toast, Toasty, Tooltip, buttonVariants, useSidebar } from "@cloudflare/kumo";
|
|
5
5
|
import { i18n } from "@lingui/core";
|
|
6
6
|
import { I18nProvider, Trans, useLingui } from "@lingui/react";
|
|
7
7
|
import { QueryClient, QueryClientProvider, keepPreviousData, useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
@@ -3187,6 +3187,11 @@ function useDebouncedValue$1(value, delay) {
|
|
|
3187
3187
|
|
|
3188
3188
|
//#endregion
|
|
3189
3189
|
//#region src/lib/media-utils.ts
|
|
3190
|
+
/** Read a string value from an untyped `meta` bag, or undefined. */
|
|
3191
|
+
function metaString(meta, key) {
|
|
3192
|
+
const value = meta?.[key];
|
|
3193
|
+
return typeof value === "string" ? value : void 0;
|
|
3194
|
+
}
|
|
3190
3195
|
function providerItemToMediaItem(providerId, item) {
|
|
3191
3196
|
return {
|
|
3192
3197
|
id: item.id,
|
|
@@ -3196,6 +3201,8 @@ function providerItemToMediaItem(providerId, item) {
|
|
|
3196
3201
|
size: item.size || 0,
|
|
3197
3202
|
width: item.width,
|
|
3198
3203
|
height: item.height,
|
|
3204
|
+
blurhash: item.blurhash ?? metaString(item.meta, "blurhash"),
|
|
3205
|
+
dominantColor: item.dominantColor ?? metaString(item.meta, "dominantColor"),
|
|
3199
3206
|
alt: item.alt,
|
|
3200
3207
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3201
3208
|
provider: providerId,
|
|
@@ -4579,6 +4586,8 @@ function ImageFieldRenderer({ id, label, description, value, onChange, required,
|
|
|
4579
4586
|
alt: item.alt || "",
|
|
4580
4587
|
width: item.width,
|
|
4581
4588
|
height: item.height,
|
|
4589
|
+
blurhash: item.blurhash ?? metaString(item.meta, "blurhash"),
|
|
4590
|
+
dominantColor: item.dominantColor ?? metaString(item.meta, "dominantColor"),
|
|
4582
4591
|
meta: isLocalProvider ? {
|
|
4583
4592
|
...item.meta,
|
|
4584
4593
|
storageKey: item.storageKey
|
|
@@ -4990,18 +4999,26 @@ function SubFieldInput({ subField, value, onChange }) {
|
|
|
4990
4999
|
onChange: (e) => onChange(fromDatetimeLocalInputValue(e.target.value)),
|
|
4991
5000
|
required: subField.required
|
|
4992
5001
|
});
|
|
4993
|
-
case "select":
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
"":
|
|
5002
|
+
case "select": {
|
|
5003
|
+
const options = Array.isArray(subField.options) ? subField.options : [];
|
|
5004
|
+
return /* @__PURE__ */ jsxs(Combobox, {
|
|
5005
|
+
label: subField.label,
|
|
5006
|
+
value: typeof value === "string" && value ? value : null,
|
|
5007
|
+
onValueChange: (v) => onChange(typeof v === "string" ? v : ""),
|
|
5008
|
+
items: options,
|
|
5009
|
+
required: subField.required,
|
|
5010
|
+
children: [/* @__PURE__ */ jsx(Combobox.TriggerInput, { placeholder: _t3({
|
|
4999
5011
|
id: "O/7I0o",
|
|
5000
5012
|
message: "Select..."
|
|
5001
|
-
}),
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5013
|
+
}) }), /* @__PURE__ */ jsxs(Combobox.Content, { children: [/* @__PURE__ */ jsx(Combobox.Empty, { children: _t3({
|
|
5014
|
+
id: "Ev2r9A",
|
|
5015
|
+
message: "No results"
|
|
5016
|
+
}) }), /* @__PURE__ */ jsx(Combobox.List, { children: (opt) => /* @__PURE__ */ jsx(Combobox.Item, {
|
|
5017
|
+
value: opt,
|
|
5018
|
+
children: opt
|
|
5019
|
+
}, opt) })] })]
|
|
5020
|
+
});
|
|
5021
|
+
}
|
|
5005
5022
|
case "image": return /* @__PURE__ */ jsx(ImageFieldRenderer, {
|
|
5006
5023
|
label: subField.label,
|
|
5007
5024
|
value: value != null && typeof value === "object" ? value : typeof value === "string" && value ? value : void 0,
|
|
@@ -5105,6 +5122,8 @@ function ImageDetailPanel({ attributes, onUpdate, onReplace, onDelete, onClose,
|
|
|
5105
5122
|
mediaId: item.id,
|
|
5106
5123
|
width: item.width,
|
|
5107
5124
|
height: item.height,
|
|
5125
|
+
blurhash: item.blurhash,
|
|
5126
|
+
dominantColor: item.dominantColor,
|
|
5108
5127
|
caption: void 0,
|
|
5109
5128
|
title: void 0
|
|
5110
5129
|
});
|
|
@@ -6391,6 +6410,16 @@ function languageLabelDescriptor(value) {
|
|
|
6391
6410
|
* so that less common languages can still be used. Free-form input is
|
|
6392
6411
|
* sanitized to a single safe CSS class token via `normalizeLanguage` so the
|
|
6393
6412
|
* frontend's `language-{id}` class stays well-formed.
|
|
6413
|
+
*
|
|
6414
|
+
* The popover content is rendered through Kumo's `Popover`, which portals it
|
|
6415
|
+
* out of the editor's contentEditable DOM. That portal is load-bearing, not
|
|
6416
|
+
* cosmetic: a code block is a non-atom ProseMirror node with live editable
|
|
6417
|
+
* content, so if the picker's text input lived inside the node view, typing
|
|
6418
|
+
* would move the DOM selection into it. ProseMirror reads that selection,
|
|
6419
|
+
* dispatches a selection-correcting transaction, and the resulting node-view
|
|
6420
|
+
* redraw recreates this React component mid-edit, tearing the picker down --
|
|
6421
|
+
* the "language picker loses focus and closes when you type" bug (issue
|
|
6422
|
+
* #1200). Keeping the input outside the editor DOM avoids it entirely.
|
|
6394
6423
|
*/
|
|
6395
6424
|
function CodeBlockNodeView({ node, updateAttributes, selected }) {
|
|
6396
6425
|
const { _: _t } = useLingui();
|
|
@@ -6412,7 +6441,6 @@ function CodeBlockNodeView({ node, updateAttributes, selected }) {
|
|
|
6412
6441
|
return lang.aliases?.some((alias) => alias.toLowerCase().includes(searchText)) ?? false;
|
|
6413
6442
|
}, [findLanguageByDisplayLabel, _t]);
|
|
6414
6443
|
const [draft, setDraft] = React$1.useState(() => labelText(storedLanguage));
|
|
6415
|
-
const popoverRef = React$1.useRef(null);
|
|
6416
6444
|
React$1.useEffect(() => {
|
|
6417
6445
|
if (!isEditing) setDraft(labelText(storedLanguage));
|
|
6418
6446
|
}, [
|
|
@@ -6441,20 +6469,8 @@ function CodeBlockNodeView({ node, updateAttributes, selected }) {
|
|
|
6441
6469
|
if (e.key === "Enter") {
|
|
6442
6470
|
e.preventDefault();
|
|
6443
6471
|
commit();
|
|
6444
|
-
} else if (e.key === "Escape") {
|
|
6445
|
-
e.preventDefault();
|
|
6446
|
-
closePicker();
|
|
6447
6472
|
}
|
|
6448
6473
|
};
|
|
6449
|
-
React$1.useEffect(() => {
|
|
6450
|
-
if (!isEditing) return void 0;
|
|
6451
|
-
const onMouseDown = (event) => {
|
|
6452
|
-
const target = event.target instanceof Node ? event.target : null;
|
|
6453
|
-
if (popoverRef.current && target && !popoverRef.current.contains(target)) closePicker();
|
|
6454
|
-
};
|
|
6455
|
-
document.addEventListener("mousedown", onMouseDown);
|
|
6456
|
-
return () => document.removeEventListener("mousedown", onMouseDown);
|
|
6457
|
-
}, [isEditing, closePicker]);
|
|
6458
6474
|
const label = labelText(storedLanguage);
|
|
6459
6475
|
const chipPersistent = isEditing || Boolean(storedLanguage) || selected;
|
|
6460
6476
|
return /* @__PURE__ */ jsxs(NodeViewWrapper, {
|
|
@@ -6466,89 +6482,95 @@ function CodeBlockNodeView({ node, updateAttributes, selected }) {
|
|
|
6466
6482
|
}), /* @__PURE__ */ jsx("div", {
|
|
6467
6483
|
className: "absolute end-2 top-2 select-none",
|
|
6468
6484
|
contentEditable: false,
|
|
6469
|
-
children:
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
placeholder: _t({
|
|
6482
|
-
id: "vXIe7J",
|
|
6483
|
-
message: "Language"
|
|
6484
|
-
})
|
|
6485
|
-
}), /* @__PURE__ */ jsxs(Autocomplete.Content, {
|
|
6486
|
-
sideOffset: 4,
|
|
6487
|
-
children: [/* @__PURE__ */ jsx(Autocomplete.List, { children: (item) => /* @__PURE__ */ jsx(Autocomplete.Item, {
|
|
6488
|
-
value: item,
|
|
6489
|
-
children: item
|
|
6490
|
-
}, item) }), /* @__PURE__ */ jsx(Autocomplete.Empty, { children: _t({
|
|
6491
|
-
id: "4TVVsS",
|
|
6492
|
-
message: "No matches"
|
|
6493
|
-
}) })]
|
|
6494
|
-
})]
|
|
6485
|
+
children: /* @__PURE__ */ jsxs(Popover, {
|
|
6486
|
+
open: isEditing,
|
|
6487
|
+
onOpenChange: (open) => open ? openPicker() : closePicker(),
|
|
6488
|
+
children: [/* @__PURE__ */ jsx(Popover.Trigger, { render: /* @__PURE__ */ jsx("button", {
|
|
6489
|
+
type: "button",
|
|
6490
|
+
tabIndex: chipPersistent ? 0 : -1,
|
|
6491
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
6492
|
+
className: "rounded-md border bg-kumo-overlay/90 px-2 py-1 text-xs text-kumo-subtle opacity-0 transition-opacity hover:text-kumo-strong focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-kumo-brand group-hover:opacity-100 data-[persistent=true]:opacity-100",
|
|
6493
|
+
"data-persistent": chipPersistent ? "true" : "false",
|
|
6494
|
+
title: _t({
|
|
6495
|
+
id: "9cbOH7",
|
|
6496
|
+
message: "Set language"
|
|
6495
6497
|
}),
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
className: "h-7 w-7",
|
|
6501
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
6502
|
-
onClick: () => commit(),
|
|
6503
|
-
title: _t({
|
|
6504
|
-
id: "Ek42QX",
|
|
6505
|
-
message: "Apply language"
|
|
6506
|
-
}),
|
|
6507
|
-
"aria-label": _t({
|
|
6508
|
-
id: "Ek42QX",
|
|
6509
|
-
message: "Apply language"
|
|
6510
|
-
}),
|
|
6511
|
-
children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" })
|
|
6498
|
+
"aria-label": _t({
|
|
6499
|
+
id: "q/A3pF",
|
|
6500
|
+
message: "Set language (current: {label})",
|
|
6501
|
+
values: { label }
|
|
6512
6502
|
}),
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6503
|
+
"aria-hidden": chipPersistent ? void 0 : true,
|
|
6504
|
+
children: storedLanguage ? label : _t({
|
|
6505
|
+
id: "9cbOH7",
|
|
6506
|
+
message: "Set language"
|
|
6507
|
+
})
|
|
6508
|
+
}) }), /* @__PURE__ */ jsx(Popover.Content, {
|
|
6509
|
+
side: "bottom",
|
|
6510
|
+
className: "w-auto p-1",
|
|
6511
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
6512
|
+
className: "flex items-center gap-1",
|
|
6513
|
+
onKeyDown: handleKeyDown,
|
|
6514
|
+
children: [
|
|
6515
|
+
/* @__PURE__ */ jsxs(Autocomplete, {
|
|
6516
|
+
items: languageItems,
|
|
6517
|
+
value: draft,
|
|
6518
|
+
onValueChange: (next) => setDraft(next),
|
|
6519
|
+
filter: filterLanguages,
|
|
6520
|
+
children: [/* @__PURE__ */ jsx(Autocomplete.InputGroup, {
|
|
6521
|
+
size: "sm",
|
|
6522
|
+
placeholder: _t({
|
|
6523
|
+
id: "vXIe7J",
|
|
6524
|
+
message: "Language"
|
|
6525
|
+
})
|
|
6526
|
+
}), /* @__PURE__ */ jsxs(Autocomplete.Content, {
|
|
6527
|
+
sideOffset: 4,
|
|
6528
|
+
children: [/* @__PURE__ */ jsx(Autocomplete.List, { children: (item) => /* @__PURE__ */ jsx(Autocomplete.Item, {
|
|
6529
|
+
value: item,
|
|
6530
|
+
children: item
|
|
6531
|
+
}, item) }), /* @__PURE__ */ jsx(Autocomplete.Empty, { children: _t({
|
|
6532
|
+
id: "4TVVsS",
|
|
6533
|
+
message: "No matches"
|
|
6534
|
+
}) })]
|
|
6535
|
+
})]
|
|
6536
|
+
}),
|
|
6537
|
+
/* @__PURE__ */ jsx(Button, {
|
|
6538
|
+
type: "button",
|
|
6539
|
+
variant: "ghost",
|
|
6540
|
+
shape: "square",
|
|
6541
|
+
className: "h-7 w-7",
|
|
6542
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
6543
|
+
onClick: () => commit(),
|
|
6544
|
+
title: _t({
|
|
6545
|
+
id: "Ek42QX",
|
|
6546
|
+
message: "Apply language"
|
|
6547
|
+
}),
|
|
6548
|
+
"aria-label": _t({
|
|
6549
|
+
id: "Ek42QX",
|
|
6550
|
+
message: "Apply language"
|
|
6551
|
+
}),
|
|
6552
|
+
children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" })
|
|
6553
|
+
}),
|
|
6554
|
+
/* @__PURE__ */ jsx(Button, {
|
|
6555
|
+
type: "button",
|
|
6556
|
+
variant: "ghost",
|
|
6557
|
+
shape: "square",
|
|
6558
|
+
className: "h-7 w-7",
|
|
6559
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
6560
|
+
onClick: closePicker,
|
|
6561
|
+
title: _t({
|
|
6562
|
+
id: "dEgA5A",
|
|
6563
|
+
message: "Cancel"
|
|
6564
|
+
}),
|
|
6565
|
+
"aria-label": _t({
|
|
6566
|
+
id: "dEgA5A",
|
|
6567
|
+
message: "Cancel"
|
|
6568
|
+
}),
|
|
6569
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
6570
|
+
})
|
|
6571
|
+
]
|
|
6529
6572
|
})
|
|
6530
|
-
]
|
|
6531
|
-
}) : /* @__PURE__ */ jsx("button", {
|
|
6532
|
-
type: "button",
|
|
6533
|
-
tabIndex: chipPersistent ? 0 : -1,
|
|
6534
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
6535
|
-
onClick: openPicker,
|
|
6536
|
-
className: "rounded-md border bg-kumo-overlay/90 px-2 py-1 text-xs text-kumo-subtle opacity-0 transition-opacity hover:text-kumo-strong focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-kumo-brand group-hover:opacity-100 data-[persistent=true]:opacity-100",
|
|
6537
|
-
"data-persistent": chipPersistent ? "true" : "false",
|
|
6538
|
-
title: _t({
|
|
6539
|
-
id: "9cbOH7",
|
|
6540
|
-
message: "Set language"
|
|
6541
|
-
}),
|
|
6542
|
-
"aria-label": _t({
|
|
6543
|
-
id: "q/A3pF",
|
|
6544
|
-
message: "Set language (current: {label})",
|
|
6545
|
-
values: { label }
|
|
6546
|
-
}),
|
|
6547
|
-
"aria-hidden": chipPersistent ? void 0 : true,
|
|
6548
|
-
children: storedLanguage ? label : _t({
|
|
6549
|
-
id: "9cbOH7",
|
|
6550
|
-
message: "Set language"
|
|
6551
|
-
})
|
|
6573
|
+
})]
|
|
6552
6574
|
})
|
|
6553
6575
|
})]
|
|
6554
6576
|
});
|
|
@@ -7084,6 +7106,8 @@ function ImageNodeView({ node, updateAttributes, selected, deleteNode, editor })
|
|
|
7084
7106
|
mediaId: node.attrs.mediaId,
|
|
7085
7107
|
width: node.attrs.width,
|
|
7086
7108
|
height: node.attrs.height,
|
|
7109
|
+
blurhash: node.attrs.blurhash,
|
|
7110
|
+
dominantColor: node.attrs.dominantColor,
|
|
7087
7111
|
displayWidth: node.attrs.displayWidth,
|
|
7088
7112
|
displayHeight: node.attrs.displayHeight,
|
|
7089
7113
|
alignment: node.attrs.alignment
|
|
@@ -7309,6 +7333,8 @@ const ImageExtension = Node$2.create({
|
|
|
7309
7333
|
provider: { default: null },
|
|
7310
7334
|
width: { default: null },
|
|
7311
7335
|
height: { default: null },
|
|
7336
|
+
blurhash: { default: null },
|
|
7337
|
+
dominantColor: { default: null },
|
|
7312
7338
|
displayWidth: { default: null },
|
|
7313
7339
|
displayHeight: { default: null },
|
|
7314
7340
|
alignment: { default: null }
|
|
@@ -8028,6 +8054,8 @@ function convertPMNode(node) {
|
|
|
8028
8054
|
case "image": {
|
|
8029
8055
|
const attrs = node.attrs ?? {};
|
|
8030
8056
|
const provider = attrStr(attrs.provider);
|
|
8057
|
+
const blurhash = attrStr(attrs.blurhash);
|
|
8058
|
+
const dominantColor = attrStr(attrs.dominantColor);
|
|
8031
8059
|
return {
|
|
8032
8060
|
_type: "image",
|
|
8033
8061
|
_key: generateKey(),
|
|
@@ -8040,6 +8068,8 @@ function convertPMNode(node) {
|
|
|
8040
8068
|
caption: attrStr(attrs.caption) ?? attrStr(attrs.title),
|
|
8041
8069
|
width: attrNum(attrs.width),
|
|
8042
8070
|
height: attrNum(attrs.height),
|
|
8071
|
+
...blurhash ? { blurhash } : {},
|
|
8072
|
+
...dominantColor ? { dominantColor } : {},
|
|
8043
8073
|
displayWidth: attrNum(attrs.displayWidth),
|
|
8044
8074
|
displayHeight: attrNum(attrs.displayHeight),
|
|
8045
8075
|
alignment: attrStr(attrs.alignment)
|
|
@@ -8262,6 +8292,9 @@ function convertPTBlock(block) {
|
|
|
8262
8292
|
case "image": {
|
|
8263
8293
|
if (!isImageBlock(block)) return null;
|
|
8264
8294
|
const imageBlock = block;
|
|
8295
|
+
const meta = imageBlock.asset.meta;
|
|
8296
|
+
const blurhash = typeof imageBlock.blurhash === "string" ? imageBlock.blurhash : typeof meta?.blurhash === "string" ? meta.blurhash : null;
|
|
8297
|
+
const dominantColor = typeof imageBlock.dominantColor === "string" ? imageBlock.dominantColor : typeof meta?.dominantColor === "string" ? meta.dominantColor : null;
|
|
8265
8298
|
return {
|
|
8266
8299
|
type: "image",
|
|
8267
8300
|
attrs: {
|
|
@@ -8272,6 +8305,8 @@ function convertPTBlock(block) {
|
|
|
8272
8305
|
mediaId: imageBlock.asset._ref,
|
|
8273
8306
|
width: imageBlock.width,
|
|
8274
8307
|
height: imageBlock.height,
|
|
8308
|
+
blurhash,
|
|
8309
|
+
dominantColor,
|
|
8275
8310
|
displayWidth: imageBlock.displayWidth,
|
|
8276
8311
|
displayHeight: imageBlock.displayHeight,
|
|
8277
8312
|
alignment: imageBlock.alignment
|
|
@@ -9297,28 +9332,49 @@ function DynamicSelect({ field, pluginId, value, onChange }) {
|
|
|
9297
9332
|
}
|
|
9298
9333
|
})] });
|
|
9299
9334
|
}
|
|
9335
|
+
const WORDS_PER_MINUTE = 200;
|
|
9336
|
+
const CJK_CHARACTERS_PER_MINUTE = 500;
|
|
9337
|
+
const WHITESPACE_REGEX$1 = /\s+/;
|
|
9338
|
+
const CJK_CHARACTER_REGEX = /\p{Script=Han}|\p{Script=Hangul}|\p{Script=Hiragana}|\p{Script=Katakana}/gu;
|
|
9339
|
+
function countCjkCharacters(text) {
|
|
9340
|
+
return text.match(CJK_CHARACTER_REGEX)?.length ?? 0;
|
|
9341
|
+
}
|
|
9342
|
+
function countNonCjkWords(text) {
|
|
9343
|
+
return text.replace(CJK_CHARACTER_REGEX, " ").split(WHITESPACE_REGEX$1).filter(Boolean).length;
|
|
9344
|
+
}
|
|
9345
|
+
/**
|
|
9346
|
+
* Word count for the editor footer. CJK characters are counted individually
|
|
9347
|
+
* because they are not delimited by spaces; other scripts are counted by word.
|
|
9348
|
+
* Used as the `wordCounter` for the CharacterCount extension, whose default
|
|
9349
|
+
* (`text.split(' ')`) reports a spaceless CJK paragraph as a single word.
|
|
9350
|
+
*/
|
|
9351
|
+
function countWords(text) {
|
|
9352
|
+
return countNonCjkWords(text) + countCjkCharacters(text);
|
|
9353
|
+
}
|
|
9300
9354
|
/**
|
|
9301
|
-
* Calculate reading time in minutes based
|
|
9302
|
-
*
|
|
9355
|
+
* Calculate reading time in minutes for the given text. Word-based scripts are
|
|
9356
|
+
* read at WORDS_PER_MINUTE and CJK characters at CJK_CHARACTERS_PER_MINUTE.
|
|
9357
|
+
* Returns 0 for an empty document.
|
|
9303
9358
|
*/
|
|
9304
|
-
function calculateReadingTime(
|
|
9305
|
-
return Math.ceil(
|
|
9359
|
+
function calculateReadingTime(text) {
|
|
9360
|
+
return Math.ceil(countNonCjkWords(text) / WORDS_PER_MINUTE + countCjkCharacters(text) / CJK_CHARACTERS_PER_MINUTE);
|
|
9306
9361
|
}
|
|
9307
9362
|
/**
|
|
9308
9363
|
* Editor footer showing writing metrics (word count, character count, reading time)
|
|
9309
9364
|
*/
|
|
9310
9365
|
function EditorFooter({ editor }) {
|
|
9311
|
-
const { words, characters } = useEditorState({
|
|
9366
|
+
const { words, characters, text } = useEditorState({
|
|
9312
9367
|
editor,
|
|
9313
9368
|
selector: (ctx) => {
|
|
9314
9369
|
const storage = ctx.editor.storage.characterCount;
|
|
9315
9370
|
return {
|
|
9316
9371
|
words: storage.words(),
|
|
9317
|
-
characters: storage.characters()
|
|
9372
|
+
characters: storage.characters(),
|
|
9373
|
+
text: ctx.editor.getText()
|
|
9318
9374
|
};
|
|
9319
9375
|
}
|
|
9320
9376
|
});
|
|
9321
|
-
const readingTime = calculateReadingTime(
|
|
9377
|
+
const readingTime = calculateReadingTime(text);
|
|
9322
9378
|
return /* @__PURE__ */ jsxs("div", {
|
|
9323
9379
|
className: "border-t px-4 py-2 flex items-center gap-4 text-xs text-kumo-subtle",
|
|
9324
9380
|
children: [
|
|
@@ -9501,7 +9557,7 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
|
|
|
9501
9557
|
onStateChange: setSlashMenuState,
|
|
9502
9558
|
getState: () => slashMenuStateRef.current
|
|
9503
9559
|
}),
|
|
9504
|
-
CharacterCount,
|
|
9560
|
+
CharacterCount.configure({ wordCounter: countWords }),
|
|
9505
9561
|
Focus.configure({
|
|
9506
9562
|
className: "has-focus",
|
|
9507
9563
|
mode: "all"
|
|
@@ -9575,7 +9631,9 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
|
|
|
9575
9631
|
mediaId: item.id,
|
|
9576
9632
|
provider: item.provider || "local",
|
|
9577
9633
|
width: item.width,
|
|
9578
|
-
height: item.height
|
|
9634
|
+
height: item.height,
|
|
9635
|
+
blurhash: item.blurhash,
|
|
9636
|
+
dominantColor: item.dominantColor
|
|
9579
9637
|
}).run();
|
|
9580
9638
|
setMediaPickerOpen(false);
|
|
9581
9639
|
}, [editor]);
|
|
@@ -10009,7 +10067,9 @@ function EditorToolbar({ editor, focusMode, onFocusModeChange }) {
|
|
|
10009
10067
|
alt: item.alt || item.filename,
|
|
10010
10068
|
mediaId: item.id,
|
|
10011
10069
|
width: item.width,
|
|
10012
|
-
height: item.height
|
|
10070
|
+
height: item.height,
|
|
10071
|
+
blurhash: item.blurhash,
|
|
10072
|
+
dominantColor: item.dominantColor
|
|
10013
10073
|
}).run();
|
|
10014
10074
|
}, [editor]);
|
|
10015
10075
|
const handleKeyDown = React$1.useCallback((e) => {
|
|
@@ -30744,7 +30804,7 @@ function Header() {
|
|
|
30744
30804
|
/* @__PURE__ */ jsx("hr", { className: "my-1" }),
|
|
30745
30805
|
/* @__PURE__ */ jsxs("button", {
|
|
30746
30806
|
onClick: handleLogout,
|
|
30747
|
-
className: "flex items-center gap-2 rounded-md px-3 py-2 text-sm text-kumo-danger hover:bg-kumo-danger/10 w-full text-start",
|
|
30807
|
+
className: "flex items-center gap-2 rounded-md px-3 py-2 text-sm text-kumo-danger hover:bg-kumo-danger/10 w-full text-start cursor-pointer",
|
|
30748
30808
|
children: [/* @__PURE__ */ jsx(SignOut, { className: "h-4 w-4" }), _t({
|
|
30749
30809
|
id: "FgAxTj",
|
|
30750
30810
|
message: "Log out"
|
|
@@ -39546,6 +39606,7 @@ function ContentListPage() {
|
|
|
39546
39606
|
return data?.pages.flatMap((page) => page.items) || [];
|
|
39547
39607
|
}, [data]);
|
|
39548
39608
|
const total = data?.pages[0]?.total ?? items.length;
|
|
39609
|
+
const handleLoadMore = React$1.useCallback(() => void fetchNextPage(), [fetchNextPage]);
|
|
39549
39610
|
if (!manifest) return /* @__PURE__ */ jsx(LoadingScreen, {});
|
|
39550
39611
|
const collectionConfig = manifest.collections[collection];
|
|
39551
39612
|
if (!collectionConfig) return /* @__PURE__ */ jsx(NotFoundPage, { message: `Collection "${collection}" not found` });
|
|
@@ -39565,7 +39626,7 @@ function ContentListPage() {
|
|
|
39565
39626
|
isLoading: isLoading || isFetchingNextPage,
|
|
39566
39627
|
isTrashedLoading,
|
|
39567
39628
|
hasMore: !!hasNextPage,
|
|
39568
|
-
onLoadMore:
|
|
39629
|
+
onLoadMore: handleLoadMore,
|
|
39569
39630
|
trashedCount: trashedData?.items?.length || 0,
|
|
39570
39631
|
onDelete: (id) => deleteMutation.mutate(id),
|
|
39571
39632
|
onRestore: (id) => restoreMutation.mutate(id),
|