@emdash-cms/admin 0.1.1 → 0.3.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/config-Dku9rWu6.d.ts +34 -0
- package/dist/config-Dku9rWu6.d.ts.map +1 -0
- package/dist/index.d.ts +50 -33
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1511 -682
- package/dist/index.js.map +1 -1
- package/dist/locales/de/messages.mjs +1 -0
- package/dist/locales/en/messages.mjs +1 -0
- package/dist/locales/fr/messages.mjs +1 -0
- package/dist/locales/index.d.ts +8 -0
- package/dist/locales/index.d.ts.map +1 -0
- package/dist/locales/index.js +20 -0
- package/dist/locales/index.js.map +1 -0
- package/dist/messages-2jYesPAq.js +6 -0
- package/dist/messages-2jYesPAq.js.map +1 -0
- package/dist/messages-BfrdxD3Y.js +6 -0
- package/dist/messages-BfrdxD3Y.js.map +1 -0
- package/dist/messages-CtrDoZ_2.js +6 -0
- package/dist/messages-CtrDoZ_2.js.map +1 -0
- package/dist/plugins-XhZqfegd.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/useLocale-CXsoFCFt.js +80 -0
- package/dist/useLocale-CXsoFCFt.js.map +1 -0
- package/package.json +19 -5
package/dist/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { c as fetchManifest, i as fetchPlugins, l as parseApiResponse, n as enablePlugin, o as API_BASE, r as fetchPlugin, s as apiFetch, t as disablePlugin, u as throwResponseError } from "./plugins-XhZqfegd.js";
|
|
2
|
+
import { i as SUPPORTED_LOCALE_CODES, n as DEFAULT_LOCALE, o as resolveLocale, r as SUPPORTED_LOCALES, t as useLocale } from "./useLocale-CXsoFCFt.js";
|
|
3
|
+
import "./locales/index.js";
|
|
2
4
|
import { Badge, Button, Checkbox, CommandPalette, Dialog, Input, InputArea, Label, LinkButton, Loader, Popover, Select, Sidebar as KumoSidebar, Switch, Tabs, Toast, Toasty, Tooltip, buttonVariants, useSidebar } from "@cloudflare/kumo";
|
|
5
|
+
import { i18n } from "@lingui/core";
|
|
6
|
+
import { I18nProvider, Trans, useLingui } from "@lingui/react";
|
|
3
7
|
import { QueryClient, QueryClientProvider, useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
8
|
import { Link, Link as Link$1, Outlet, RouterProvider, createRootRouteWithContext, createRoute, createRouter, useLocation, useNavigate, useNavigate as useNavigate$1, useParams, useParams as useParams$1, useSearch } from "@tanstack/react-router";
|
|
5
9
|
import * as React from "react";
|
|
@@ -200,9 +204,11 @@ function getMutationError(error) {
|
|
|
200
204
|
/** Inline error banner for use inside dialogs. */
|
|
201
205
|
function DialogError({ message, className }) {
|
|
202
206
|
if (!message) return null;
|
|
207
|
+
const lines = message.split("\n");
|
|
203
208
|
return /* @__PURE__ */ jsx("div", {
|
|
209
|
+
role: "alert",
|
|
204
210
|
className: cn("rounded-md bg-kumo-danger/10 p-3 text-sm text-kumo-danger", className),
|
|
205
|
-
children:
|
|
211
|
+
children: lines.map((line, i) => /* @__PURE__ */ jsx("div", { children: line }, i))
|
|
206
212
|
});
|
|
207
213
|
}
|
|
208
214
|
|
|
@@ -2033,44 +2039,19 @@ async function executeWpPluginImport(url, token, config) {
|
|
|
2033
2039
|
/**
|
|
2034
2040
|
* API token management client functions
|
|
2035
2041
|
*/
|
|
2036
|
-
/**
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
value: "media:read",
|
|
2050
|
-
label: "Media Read",
|
|
2051
|
-
description: "Read media files"
|
|
2052
|
-
},
|
|
2053
|
-
{
|
|
2054
|
-
value: "media:write",
|
|
2055
|
-
label: "Media Write",
|
|
2056
|
-
description: "Upload and delete media"
|
|
2057
|
-
},
|
|
2058
|
-
{
|
|
2059
|
-
value: "schema:read",
|
|
2060
|
-
label: "Schema Read",
|
|
2061
|
-
description: "Read collection schemas"
|
|
2062
|
-
},
|
|
2063
|
-
{
|
|
2064
|
-
value: "schema:write",
|
|
2065
|
-
label: "Schema Write",
|
|
2066
|
-
description: "Modify collection schemas"
|
|
2067
|
-
},
|
|
2068
|
-
{
|
|
2069
|
-
value: "admin",
|
|
2070
|
-
label: "Admin",
|
|
2071
|
-
description: "Full admin access"
|
|
2072
|
-
}
|
|
2073
|
-
];
|
|
2042
|
+
/**
|
|
2043
|
+
* Scope strings for personal API tokens (wire + UI iteration order).
|
|
2044
|
+
* Human-readable copy lives in `ApiTokenSettings` (`SCOPE_UI` + Lingui).
|
|
2045
|
+
*/
|
|
2046
|
+
const API_TOKEN_SCOPES = {
|
|
2047
|
+
ContentRead: "content:read",
|
|
2048
|
+
ContentWrite: "content:write",
|
|
2049
|
+
MediaRead: "media:read",
|
|
2050
|
+
MediaWrite: "media:write",
|
|
2051
|
+
SchemaRead: "schema:read",
|
|
2052
|
+
SchemaWrite: "schema:write",
|
|
2053
|
+
Admin: "admin"
|
|
2054
|
+
};
|
|
2074
2055
|
/**
|
|
2075
2056
|
* Fetch all API tokens for the current user
|
|
2076
2057
|
*/
|
|
@@ -3284,7 +3265,7 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
3284
3265
|
open,
|
|
3285
3266
|
onOpenChange: handleClose,
|
|
3286
3267
|
children: /* @__PURE__ */ jsxs(Dialog, {
|
|
3287
|
-
className: "p-6 max-w-4xl max-h-[80vh] flex flex-col",
|
|
3268
|
+
className: "p-6 max-w-4xl max-h-[80vh] flex flex-col overflow-hidden",
|
|
3288
3269
|
size: "xl",
|
|
3289
3270
|
children: [
|
|
3290
3271
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -3412,7 +3393,7 @@ function MediaPickerModal({ open, onOpenChange, onSelect, mimeTypeFilter = "imag
|
|
|
3412
3393
|
className: "mb-3"
|
|
3413
3394
|
}),
|
|
3414
3395
|
/* @__PURE__ */ jsx("div", {
|
|
3415
|
-
className: "flex-1 overflow-y-auto min-h-
|
|
3396
|
+
className: "flex-1 overflow-y-auto min-h-0",
|
|
3416
3397
|
children: isLoading ? /* @__PURE__ */ jsx("div", {
|
|
3417
3398
|
className: "flex items-center justify-center h-full",
|
|
3418
3399
|
children: /* @__PURE__ */ jsx(Loader, {})
|
|
@@ -4366,7 +4347,10 @@ var index_default = Suggestion;
|
|
|
4366
4347
|
const blockTransforms = [
|
|
4367
4348
|
{
|
|
4368
4349
|
id: "paragraph",
|
|
4369
|
-
label:
|
|
4350
|
+
label: {
|
|
4351
|
+
id: "bkQRMh",
|
|
4352
|
+
message: "Paragraph"
|
|
4353
|
+
},
|
|
4370
4354
|
icon: Paragraph,
|
|
4371
4355
|
transform: (editor) => {
|
|
4372
4356
|
editor.chain().focus().setNode("paragraph").run();
|
|
@@ -4374,7 +4358,10 @@ const blockTransforms = [
|
|
|
4374
4358
|
},
|
|
4375
4359
|
{
|
|
4376
4360
|
id: "heading1",
|
|
4377
|
-
label:
|
|
4361
|
+
label: {
|
|
4362
|
+
id: "lXKZGw",
|
|
4363
|
+
message: "Heading 1"
|
|
4364
|
+
},
|
|
4378
4365
|
icon: TextHOne,
|
|
4379
4366
|
transform: (editor) => {
|
|
4380
4367
|
editor.chain().focus().setNode("heading", { level: 1 }).run();
|
|
@@ -4382,7 +4369,10 @@ const blockTransforms = [
|
|
|
4382
4369
|
},
|
|
4383
4370
|
{
|
|
4384
4371
|
id: "heading2",
|
|
4385
|
-
label:
|
|
4372
|
+
label: {
|
|
4373
|
+
id: "El7NbA",
|
|
4374
|
+
message: "Heading 2"
|
|
4375
|
+
},
|
|
4386
4376
|
icon: TextHTwo,
|
|
4387
4377
|
transform: (editor) => {
|
|
4388
4378
|
editor.chain().focus().setNode("heading", { level: 2 }).run();
|
|
@@ -4390,7 +4380,10 @@ const blockTransforms = [
|
|
|
4390
4380
|
},
|
|
4391
4381
|
{
|
|
4392
4382
|
id: "heading3",
|
|
4393
|
-
label:
|
|
4383
|
+
label: {
|
|
4384
|
+
id: "SFN6dN",
|
|
4385
|
+
message: "Heading 3"
|
|
4386
|
+
},
|
|
4394
4387
|
icon: TextHThree,
|
|
4395
4388
|
transform: (editor) => {
|
|
4396
4389
|
editor.chain().focus().setNode("heading", { level: 3 }).run();
|
|
@@ -4398,7 +4391,10 @@ const blockTransforms = [
|
|
|
4398
4391
|
},
|
|
4399
4392
|
{
|
|
4400
4393
|
id: "blockquote",
|
|
4401
|
-
label:
|
|
4394
|
+
label: {
|
|
4395
|
+
id: "ZhhOwV",
|
|
4396
|
+
message: "Quote"
|
|
4397
|
+
},
|
|
4402
4398
|
icon: Quotes,
|
|
4403
4399
|
transform: (editor) => {
|
|
4404
4400
|
editor.chain().focus().toggleBlockquote().run();
|
|
@@ -4406,7 +4402,10 @@ const blockTransforms = [
|
|
|
4406
4402
|
},
|
|
4407
4403
|
{
|
|
4408
4404
|
id: "codeBlock",
|
|
4409
|
-
label:
|
|
4405
|
+
label: {
|
|
4406
|
+
id: "N2eHWq",
|
|
4407
|
+
message: "Code Block"
|
|
4408
|
+
},
|
|
4410
4409
|
icon: Code,
|
|
4411
4410
|
transform: (editor) => {
|
|
4412
4411
|
editor.chain().focus().toggleCodeBlock().run();
|
|
@@ -4414,7 +4413,10 @@ const blockTransforms = [
|
|
|
4414
4413
|
},
|
|
4415
4414
|
{
|
|
4416
4415
|
id: "bulletList",
|
|
4417
|
-
label:
|
|
4416
|
+
label: {
|
|
4417
|
+
id: "s1c0ja",
|
|
4418
|
+
message: "Bullet List"
|
|
4419
|
+
},
|
|
4418
4420
|
icon: List,
|
|
4419
4421
|
transform: (editor) => {
|
|
4420
4422
|
editor.chain().focus().toggleBulletList().run();
|
|
@@ -4422,7 +4424,10 @@ const blockTransforms = [
|
|
|
4422
4424
|
},
|
|
4423
4425
|
{
|
|
4424
4426
|
id: "orderedList",
|
|
4425
|
-
label:
|
|
4427
|
+
label: {
|
|
4428
|
+
id: "upFPtm",
|
|
4429
|
+
message: "Numbered List"
|
|
4430
|
+
},
|
|
4426
4431
|
icon: ListNumbers,
|
|
4427
4432
|
transform: (editor) => {
|
|
4428
4433
|
editor.chain().focus().toggleOrderedList().run();
|
|
@@ -4433,6 +4438,7 @@ const blockTransforms = [
|
|
|
4433
4438
|
* Block Menu - floating menu for block-level actions
|
|
4434
4439
|
*/
|
|
4435
4440
|
function BlockMenu({ editor, anchorElement, isOpen, onClose }) {
|
|
4441
|
+
const { _: _t } = useLingui();
|
|
4436
4442
|
const [showTransforms, setShowTransforms] = React.useState(false);
|
|
4437
4443
|
const menuRef = React.useRef(null);
|
|
4438
4444
|
const stableOnClose = useStableCallback(onClose);
|
|
@@ -4529,7 +4535,7 @@ function BlockMenu({ editor, anchorElement, isOpen, onClose }) {
|
|
|
4529
4535
|
type: "button",
|
|
4530
4536
|
className: "flex items-center gap-2 w-full px-3 py-2 text-sm hover:bg-kumo-tint text-left",
|
|
4531
4537
|
onClick: () => handleTransform(transform),
|
|
4532
|
-
children: [/* @__PURE__ */ jsx(transform.icon, { className: "h-4 w-4 text-kumo-subtle" }), /* @__PURE__ */ jsx("span", { children: transform.label })]
|
|
4538
|
+
children: [/* @__PURE__ */ jsx(transform.icon, { className: "h-4 w-4 text-kumo-subtle" }), /* @__PURE__ */ jsx("span", { children: _t(transform.label) })]
|
|
4533
4539
|
}, transform.id))
|
|
4534
4540
|
]
|
|
4535
4541
|
}) : /* @__PURE__ */ jsxs("div", {
|
|
@@ -5774,8 +5780,14 @@ function convertPTMarks(marks, markDefs) {
|
|
|
5774
5780
|
const defaultSlashCommands = [
|
|
5775
5781
|
{
|
|
5776
5782
|
id: "heading1",
|
|
5777
|
-
title:
|
|
5778
|
-
|
|
5783
|
+
title: {
|
|
5784
|
+
id: "lXKZGw",
|
|
5785
|
+
message: "Heading 1"
|
|
5786
|
+
},
|
|
5787
|
+
description: {
|
|
5788
|
+
id: "59o/ag",
|
|
5789
|
+
message: "Large section heading"
|
|
5790
|
+
},
|
|
5779
5791
|
icon: TextHOne,
|
|
5780
5792
|
aliases: ["h1", "title"],
|
|
5781
5793
|
command: ({ editor, range }) => {
|
|
@@ -5784,8 +5796,14 @@ const defaultSlashCommands = [
|
|
|
5784
5796
|
},
|
|
5785
5797
|
{
|
|
5786
5798
|
id: "heading2",
|
|
5787
|
-
title:
|
|
5788
|
-
|
|
5799
|
+
title: {
|
|
5800
|
+
id: "El7NbA",
|
|
5801
|
+
message: "Heading 2"
|
|
5802
|
+
},
|
|
5803
|
+
description: {
|
|
5804
|
+
id: "IAcjOi",
|
|
5805
|
+
message: "Medium section heading"
|
|
5806
|
+
},
|
|
5789
5807
|
icon: TextHTwo,
|
|
5790
5808
|
aliases: ["h2", "subtitle"],
|
|
5791
5809
|
command: ({ editor, range }) => {
|
|
@@ -5794,8 +5812,14 @@ const defaultSlashCommands = [
|
|
|
5794
5812
|
},
|
|
5795
5813
|
{
|
|
5796
5814
|
id: "heading3",
|
|
5797
|
-
title:
|
|
5798
|
-
|
|
5815
|
+
title: {
|
|
5816
|
+
id: "SFN6dN",
|
|
5817
|
+
message: "Heading 3"
|
|
5818
|
+
},
|
|
5819
|
+
description: {
|
|
5820
|
+
id: "Ik7fz5",
|
|
5821
|
+
message: "Small section heading"
|
|
5822
|
+
},
|
|
5799
5823
|
icon: TextHThree,
|
|
5800
5824
|
aliases: ["h3"],
|
|
5801
5825
|
command: ({ editor, range }) => {
|
|
@@ -5804,8 +5828,14 @@ const defaultSlashCommands = [
|
|
|
5804
5828
|
},
|
|
5805
5829
|
{
|
|
5806
5830
|
id: "bulletList",
|
|
5807
|
-
title:
|
|
5808
|
-
|
|
5831
|
+
title: {
|
|
5832
|
+
id: "s1c0ja",
|
|
5833
|
+
message: "Bullet List"
|
|
5834
|
+
},
|
|
5835
|
+
description: {
|
|
5836
|
+
id: "md7u2X",
|
|
5837
|
+
message: "Create a bullet list"
|
|
5838
|
+
},
|
|
5809
5839
|
icon: List,
|
|
5810
5840
|
aliases: ["ul", "unordered"],
|
|
5811
5841
|
command: ({ editor, range }) => {
|
|
@@ -5814,8 +5844,14 @@ const defaultSlashCommands = [
|
|
|
5814
5844
|
},
|
|
5815
5845
|
{
|
|
5816
5846
|
id: "numberedList",
|
|
5817
|
-
title:
|
|
5818
|
-
|
|
5847
|
+
title: {
|
|
5848
|
+
id: "upFPtm",
|
|
5849
|
+
message: "Numbered List"
|
|
5850
|
+
},
|
|
5851
|
+
description: {
|
|
5852
|
+
id: "fh33rM",
|
|
5853
|
+
message: "Create a numbered list"
|
|
5854
|
+
},
|
|
5819
5855
|
icon: ListNumbers,
|
|
5820
5856
|
aliases: ["ol", "ordered"],
|
|
5821
5857
|
command: ({ editor, range }) => {
|
|
@@ -5824,8 +5860,14 @@ const defaultSlashCommands = [
|
|
|
5824
5860
|
},
|
|
5825
5861
|
{
|
|
5826
5862
|
id: "quote",
|
|
5827
|
-
title:
|
|
5828
|
-
|
|
5863
|
+
title: {
|
|
5864
|
+
id: "ZhhOwV",
|
|
5865
|
+
message: "Quote"
|
|
5866
|
+
},
|
|
5867
|
+
description: {
|
|
5868
|
+
id: "l+2nGM",
|
|
5869
|
+
message: "Insert a blockquote"
|
|
5870
|
+
},
|
|
5829
5871
|
icon: Quotes,
|
|
5830
5872
|
aliases: ["blockquote", "cite"],
|
|
5831
5873
|
command: ({ editor, range }) => {
|
|
@@ -5834,8 +5876,14 @@ const defaultSlashCommands = [
|
|
|
5834
5876
|
},
|
|
5835
5877
|
{
|
|
5836
5878
|
id: "codeBlock",
|
|
5837
|
-
title:
|
|
5838
|
-
|
|
5879
|
+
title: {
|
|
5880
|
+
id: "N2eHWq",
|
|
5881
|
+
message: "Code Block"
|
|
5882
|
+
},
|
|
5883
|
+
description: {
|
|
5884
|
+
id: "12gVka",
|
|
5885
|
+
message: "Insert a code block"
|
|
5886
|
+
},
|
|
5839
5887
|
icon: CodeBlock,
|
|
5840
5888
|
aliases: [
|
|
5841
5889
|
"code",
|
|
@@ -5848,8 +5896,14 @@ const defaultSlashCommands = [
|
|
|
5848
5896
|
},
|
|
5849
5897
|
{
|
|
5850
5898
|
id: "divider",
|
|
5851
|
-
title:
|
|
5852
|
-
|
|
5899
|
+
title: {
|
|
5900
|
+
id: "R8AthW",
|
|
5901
|
+
message: "Divider"
|
|
5902
|
+
},
|
|
5903
|
+
description: {
|
|
5904
|
+
id: "9Jd2n5",
|
|
5905
|
+
message: "Insert a horizontal rule"
|
|
5906
|
+
},
|
|
5853
5907
|
icon: Minus,
|
|
5854
5908
|
aliases: [
|
|
5855
5909
|
"hr",
|
|
@@ -5958,6 +6012,7 @@ function createSlashCommandsExtension(options) {
|
|
|
5958
6012
|
* Slash command menu component using Floating UI
|
|
5959
6013
|
*/
|
|
5960
6014
|
function SlashCommandMenu({ state, onCommand, onClose: _onClose, setSelectedIndex }) {
|
|
6015
|
+
const { _: _t } = useLingui();
|
|
5961
6016
|
const containerRef = React.useRef(null);
|
|
5962
6017
|
const { refs, floatingStyles } = useFloating({
|
|
5963
6018
|
open: state.isOpen,
|
|
@@ -5992,7 +6047,10 @@ function SlashCommandMenu({ state, onCommand, onClose: _onClose, setSelectedInde
|
|
|
5992
6047
|
className: "z-[100] rounded-lg border bg-kumo-overlay p-1 shadow-lg min-w-[220px] max-h-[300px] overflow-y-auto",
|
|
5993
6048
|
children: state.items.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
5994
6049
|
className: "text-sm text-kumo-subtle px-3 py-2",
|
|
5995
|
-
children:
|
|
6050
|
+
children: _t({
|
|
6051
|
+
id: "Ev2r9A",
|
|
6052
|
+
message: "No results"
|
|
6053
|
+
})
|
|
5996
6054
|
}) : state.items.map((item, index) => /* @__PURE__ */ jsxs("button", {
|
|
5997
6055
|
type: "button",
|
|
5998
6056
|
"data-index": index,
|
|
@@ -6003,10 +6061,10 @@ function SlashCommandMenu({ state, onCommand, onClose: _onClose, setSelectedInde
|
|
|
6003
6061
|
className: "flex flex-col",
|
|
6004
6062
|
children: [/* @__PURE__ */ jsx("span", {
|
|
6005
6063
|
className: "font-medium",
|
|
6006
|
-
children: item.title
|
|
6064
|
+
children: typeof item.title === "string" ? item.title : _t(item.title)
|
|
6007
6065
|
}), /* @__PURE__ */ jsx("span", {
|
|
6008
6066
|
className: "text-xs text-kumo-subtle",
|
|
6009
|
-
children: item.description
|
|
6067
|
+
children: typeof item.description === "string" ? item.description : _t(item.description)
|
|
6010
6068
|
})]
|
|
6011
6069
|
})]
|
|
6012
6070
|
}, item.id))
|
|
@@ -6267,6 +6325,7 @@ function EditorFooter({ editor }) {
|
|
|
6267
6325
|
* Portable Text Editor Component
|
|
6268
6326
|
*/
|
|
6269
6327
|
function PortableTextEditor({ value, onChange, placeholder = "Start writing...", className, editable = true, "aria-labelledby": ariaLabelledby, pluginBlocks = [], focusMode: controlledFocusMode, onFocusModeChange, onEditorReady, minimal = false, onBlockSidebarOpen, onBlockSidebarClose }) {
|
|
6328
|
+
const { _: _t2 } = useLingui();
|
|
6270
6329
|
const onChangeRef = React.useRef(onChange);
|
|
6271
6330
|
React.useEffect(() => {
|
|
6272
6331
|
onChangeRef.current = onChange;
|
|
@@ -6298,8 +6357,14 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
|
|
|
6298
6357
|
const cmds = [...defaultSlashCommands];
|
|
6299
6358
|
cmds.push({
|
|
6300
6359
|
id: "image",
|
|
6301
|
-
title:
|
|
6302
|
-
|
|
6360
|
+
title: {
|
|
6361
|
+
id: "hG89Ed",
|
|
6362
|
+
message: "Image"
|
|
6363
|
+
},
|
|
6364
|
+
description: {
|
|
6365
|
+
id: "3Lcj6W",
|
|
6366
|
+
message: "Insert an image"
|
|
6367
|
+
},
|
|
6303
6368
|
icon: Image$1,
|
|
6304
6369
|
aliases: [
|
|
6305
6370
|
"img",
|
|
@@ -6307,7 +6372,10 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
|
|
|
6307
6372
|
"picture",
|
|
6308
6373
|
"url"
|
|
6309
6374
|
],
|
|
6310
|
-
category:
|
|
6375
|
+
category: {
|
|
6376
|
+
id: "xYilR2",
|
|
6377
|
+
message: "Media"
|
|
6378
|
+
},
|
|
6311
6379
|
command: ({ editor, range }) => {
|
|
6312
6380
|
editor.chain().focus().deleteRange(range).run();
|
|
6313
6381
|
setMediaPickerOpen(true);
|
|
@@ -6315,15 +6383,24 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
|
|
|
6315
6383
|
});
|
|
6316
6384
|
cmds.push({
|
|
6317
6385
|
id: "section",
|
|
6318
|
-
title:
|
|
6319
|
-
|
|
6386
|
+
title: {
|
|
6387
|
+
id: "BhZ5PL",
|
|
6388
|
+
message: "Section"
|
|
6389
|
+
},
|
|
6390
|
+
description: {
|
|
6391
|
+
id: "Pkleyv",
|
|
6392
|
+
message: "Insert a reusable section"
|
|
6393
|
+
},
|
|
6320
6394
|
icon: Stack,
|
|
6321
6395
|
aliases: [
|
|
6322
6396
|
"pattern",
|
|
6323
6397
|
"block",
|
|
6324
6398
|
"template"
|
|
6325
6399
|
],
|
|
6326
|
-
category:
|
|
6400
|
+
category: {
|
|
6401
|
+
id: "4b3oEV",
|
|
6402
|
+
message: "Content"
|
|
6403
|
+
},
|
|
6327
6404
|
command: ({ editor, range }) => {
|
|
6328
6405
|
editor.chain().focus().deleteRange(range).run();
|
|
6329
6406
|
setSectionPickerOpen(true);
|
|
@@ -6332,25 +6409,36 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
|
|
|
6332
6409
|
for (const block of pluginBlocks) cmds.push({
|
|
6333
6410
|
id: `plugin-${block.pluginId}-${block.type}`,
|
|
6334
6411
|
title: block.label,
|
|
6335
|
-
description: block.description
|
|
6412
|
+
description: block.description ?? _t2({
|
|
6413
|
+
id: "g0zqOw",
|
|
6414
|
+
message: "Embed a {0}",
|
|
6415
|
+
values: { 0: block.label }
|
|
6416
|
+
}),
|
|
6336
6417
|
icon: resolveIcon(block.icon),
|
|
6337
6418
|
aliases: [block.type],
|
|
6338
|
-
category:
|
|
6419
|
+
category: {
|
|
6420
|
+
id: "aTofd0",
|
|
6421
|
+
message: "Embeds"
|
|
6422
|
+
},
|
|
6339
6423
|
command: ({ editor, range }) => {
|
|
6340
6424
|
editor.chain().focus().deleteRange(range).run();
|
|
6341
6425
|
setPluginBlockModal(block);
|
|
6342
6426
|
}
|
|
6343
6427
|
});
|
|
6344
6428
|
return cmds;
|
|
6345
|
-
}, [pluginBlocks]);
|
|
6429
|
+
}, [pluginBlocks, _t2]);
|
|
6346
6430
|
const filterCommandsRef = React.useRef((_q) => []);
|
|
6347
6431
|
filterCommandsRef.current = (query) => {
|
|
6348
6432
|
if (!query) return slashCommands;
|
|
6349
6433
|
const searchText = query.toLowerCase();
|
|
6350
6434
|
const titleMatches = [];
|
|
6351
6435
|
const otherMatches = [];
|
|
6352
|
-
for (const item of slashCommands)
|
|
6353
|
-
|
|
6436
|
+
for (const item of slashCommands) {
|
|
6437
|
+
const titleStr = typeof item.title === "string" ? item.title : _t2(item.title);
|
|
6438
|
+
const descStr = typeof item.description === "string" ? item.description : _t2(item.description);
|
|
6439
|
+
if (titleStr.toLowerCase().includes(searchText)) titleMatches.push(item);
|
|
6440
|
+
else if (descStr.toLowerCase().includes(searchText) || item.aliases?.some((alias) => alias.toLowerCase().includes(searchText))) otherMatches.push(item);
|
|
6441
|
+
}
|
|
6354
6442
|
return [...titleMatches, ...otherMatches];
|
|
6355
6443
|
};
|
|
6356
6444
|
const initialContent = React.useMemo(() => portableTextToProsemirror(value || []), []);
|
|
@@ -8112,43 +8200,40 @@ function ContentEditor({ collection, collectionLabel, item, fields, isNew, isSav
|
|
|
8112
8200
|
isSaving: isSaving || false
|
|
8113
8201
|
}),
|
|
8114
8202
|
!isNew && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
8115
|
-
supportsDrafts && hasPendingChanges && onDiscardDraft && /* @__PURE__ */ jsxs(Dialog.Root, {
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
/* @__PURE__ */
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
]
|
|
8150
|
-
})]
|
|
8151
|
-
}),
|
|
8203
|
+
supportsDrafts && hasPendingChanges && onDiscardDraft && /* @__PURE__ */ jsxs(Dialog.Root, { children: [/* @__PURE__ */ jsx(Dialog.Trigger, { render: (p) => /* @__PURE__ */ jsx(Button, {
|
|
8204
|
+
...p,
|
|
8205
|
+
type: "button",
|
|
8206
|
+
variant: "outline",
|
|
8207
|
+
size: "sm",
|
|
8208
|
+
icon: /* @__PURE__ */ jsx(X, {}),
|
|
8209
|
+
children: "Discard changes"
|
|
8210
|
+
}) }), /* @__PURE__ */ jsxs(Dialog, {
|
|
8211
|
+
className: "p-6",
|
|
8212
|
+
size: "sm",
|
|
8213
|
+
children: [
|
|
8214
|
+
/* @__PURE__ */ jsx(Dialog.Title, {
|
|
8215
|
+
className: "text-lg font-semibold",
|
|
8216
|
+
children: "Discard draft changes?"
|
|
8217
|
+
}),
|
|
8218
|
+
/* @__PURE__ */ jsx(Dialog.Description, {
|
|
8219
|
+
className: "text-kumo-subtle",
|
|
8220
|
+
children: "This will revert to the published version. Your draft changes will be lost."
|
|
8221
|
+
}),
|
|
8222
|
+
/* @__PURE__ */ jsxs("div", {
|
|
8223
|
+
className: "mt-6 flex justify-end gap-2",
|
|
8224
|
+
children: [/* @__PURE__ */ jsx(Dialog.Close, { render: (p) => /* @__PURE__ */ jsx(Button, {
|
|
8225
|
+
...p,
|
|
8226
|
+
variant: "secondary",
|
|
8227
|
+
children: "Cancel"
|
|
8228
|
+
}) }), /* @__PURE__ */ jsx(Dialog.Close, { render: (p) => /* @__PURE__ */ jsx(Button, {
|
|
8229
|
+
...p,
|
|
8230
|
+
variant: "destructive",
|
|
8231
|
+
onClick: onDiscardDraft,
|
|
8232
|
+
children: "Discard changes"
|
|
8233
|
+
}) })]
|
|
8234
|
+
})
|
|
8235
|
+
]
|
|
8236
|
+
})] }),
|
|
8152
8237
|
isLive ? /* @__PURE__ */ jsx(Fragment, { children: hasPendingChanges ? /* @__PURE__ */ jsx(Button, {
|
|
8153
8238
|
type: "button",
|
|
8154
8239
|
variant: "primary",
|
|
@@ -8246,6 +8331,7 @@ function ContentEditor({ collection, collectionLabel, item, fields, isNew, isSav
|
|
|
8246
8331
|
children: supportsDrafts ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
8247
8332
|
isLive && /* @__PURE__ */ jsx(Badge, {
|
|
8248
8333
|
variant: "primary",
|
|
8334
|
+
className: "text-white",
|
|
8249
8335
|
children: "Published"
|
|
8250
8336
|
}),
|
|
8251
8337
|
hasPendingChanges && /* @__PURE__ */ jsx(Badge, {
|
|
@@ -8538,27 +8624,31 @@ function FieldRenderer({ name, field, value, onChange, onEditorReady, minimal, p
|
|
|
8538
8624
|
required: field.required
|
|
8539
8625
|
});
|
|
8540
8626
|
case "boolean": return /* @__PURE__ */ jsx(Switch, {
|
|
8627
|
+
id,
|
|
8541
8628
|
label,
|
|
8542
8629
|
checked: typeof value === "boolean" ? value : false,
|
|
8543
8630
|
onCheckedChange: handleChange
|
|
8544
8631
|
});
|
|
8545
8632
|
case "portableText": {
|
|
8546
8633
|
const labelId = `${id}-label`;
|
|
8547
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
8548
|
-
id
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8634
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
8635
|
+
id,
|
|
8636
|
+
children: [!minimal && /* @__PURE__ */ jsx("span", {
|
|
8637
|
+
id: labelId,
|
|
8638
|
+
className: cn("text-sm font-medium leading-none text-kumo-default", labelClass),
|
|
8639
|
+
children: label
|
|
8640
|
+
}), /* @__PURE__ */ jsx(PortableTextEditor, {
|
|
8641
|
+
value: Array.isArray(value) ? value : [],
|
|
8642
|
+
onChange: handleChange,
|
|
8643
|
+
placeholder: `Enter ${label.toLowerCase()}...`,
|
|
8644
|
+
"aria-labelledby": labelId,
|
|
8645
|
+
pluginBlocks,
|
|
8646
|
+
onEditorReady,
|
|
8647
|
+
minimal,
|
|
8648
|
+
onBlockSidebarOpen,
|
|
8649
|
+
onBlockSidebarClose
|
|
8650
|
+
})]
|
|
8651
|
+
});
|
|
8562
8652
|
}
|
|
8563
8653
|
case "richText": return /* @__PURE__ */ jsx(InputArea, {
|
|
8564
8654
|
label,
|
|
@@ -8572,6 +8662,7 @@ function FieldRenderer({ name, field, value, onChange, onEditorReady, minimal, p
|
|
|
8572
8662
|
const selectItems = {};
|
|
8573
8663
|
for (const opt of field.options ?? []) selectItems[opt.value] = opt.label;
|
|
8574
8664
|
return /* @__PURE__ */ jsx(Select, {
|
|
8665
|
+
id,
|
|
8575
8666
|
label,
|
|
8576
8667
|
value: typeof value === "string" ? value : "",
|
|
8577
8668
|
onValueChange: (v) => handleChange(v ?? ""),
|
|
@@ -8610,6 +8701,7 @@ function FieldRenderer({ name, field, value, onChange, onEditorReady, minimal, p
|
|
|
8610
8701
|
required: field.required
|
|
8611
8702
|
});
|
|
8612
8703
|
case "image": return /* @__PURE__ */ jsx(ImageFieldRenderer, {
|
|
8704
|
+
id,
|
|
8613
8705
|
label,
|
|
8614
8706
|
description: name === "featured_image" ? "Used as the main visual for this post on listing pages and at the top of the post" : void 0,
|
|
8615
8707
|
value: value != null && typeof value === "object" ? value : void 0,
|
|
@@ -8639,7 +8731,7 @@ function FieldRenderer({ name, field, value, onChange, onEditorReady, minimal, p
|
|
|
8639
8731
|
});
|
|
8640
8732
|
}
|
|
8641
8733
|
}
|
|
8642
|
-
function ImageFieldRenderer({ label, description, value, onChange, required }) {
|
|
8734
|
+
function ImageFieldRenderer({ id, label, description, value, onChange, required }) {
|
|
8643
8735
|
const [pickerOpen, setPickerOpen] = React.useState(false);
|
|
8644
8736
|
const displayUrl = typeof value === "string" ? value : value?.previewUrl || value?.src || (value && (!value.provider || value.provider === "local") ? `/_emdash/api/media/file/${typeof value.meta?.storageKey === "string" ? value.meta.storageKey : value.id}` : void 0);
|
|
8645
8737
|
const handleSelect = (item) => {
|
|
@@ -8660,58 +8752,61 @@ function ImageFieldRenderer({ label, description, value, onChange, required }) {
|
|
|
8660
8752
|
const handleRemove = () => {
|
|
8661
8753
|
onChange(void 0);
|
|
8662
8754
|
};
|
|
8663
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
8664
|
-
|
|
8665
|
-
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
8686
|
-
|
|
8755
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
8756
|
+
id,
|
|
8757
|
+
children: [
|
|
8758
|
+
/* @__PURE__ */ jsx(Label, { children: label }),
|
|
8759
|
+
displayUrl ? /* @__PURE__ */ jsxs("div", {
|
|
8760
|
+
className: "mt-2 relative group",
|
|
8761
|
+
children: [/* @__PURE__ */ jsx("img", {
|
|
8762
|
+
src: displayUrl,
|
|
8763
|
+
alt: "",
|
|
8764
|
+
className: "max-h-48 rounded-lg border object-cover"
|
|
8765
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
8766
|
+
className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity flex gap-1",
|
|
8767
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
8768
|
+
type: "button",
|
|
8769
|
+
size: "sm",
|
|
8770
|
+
variant: "secondary",
|
|
8771
|
+
onClick: () => setPickerOpen(true),
|
|
8772
|
+
children: "Change"
|
|
8773
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
8774
|
+
type: "button",
|
|
8775
|
+
shape: "square",
|
|
8776
|
+
variant: "destructive",
|
|
8777
|
+
className: "h-8 w-8",
|
|
8778
|
+
onClick: handleRemove,
|
|
8779
|
+
"aria-label": "Remove image",
|
|
8780
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
8781
|
+
})]
|
|
8687
8782
|
})]
|
|
8688
|
-
})
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
|
|
8783
|
+
}) : /* @__PURE__ */ jsx(Button, {
|
|
8784
|
+
type: "button",
|
|
8785
|
+
variant: "outline",
|
|
8786
|
+
className: "mt-2 w-full h-32 border-dashed",
|
|
8787
|
+
onClick: () => setPickerOpen(true),
|
|
8788
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
8789
|
+
className: "flex flex-col items-center gap-2 text-kumo-subtle",
|
|
8790
|
+
children: [/* @__PURE__ */ jsx(Image$1, { className: "h-8 w-8" }), /* @__PURE__ */ jsx("span", { children: "Select image" })]
|
|
8791
|
+
})
|
|
8792
|
+
}),
|
|
8793
|
+
/* @__PURE__ */ jsx(MediaPickerModal, {
|
|
8794
|
+
open: pickerOpen,
|
|
8795
|
+
onOpenChange: setPickerOpen,
|
|
8796
|
+
onSelect: handleSelect,
|
|
8797
|
+
mimeTypeFilter: "image/",
|
|
8798
|
+
title: `Select ${label}`
|
|
8799
|
+
}),
|
|
8800
|
+
description && /* @__PURE__ */ jsx("p", {
|
|
8801
|
+
className: "text-xs text-kumo-subtle mt-1",
|
|
8802
|
+
children: description
|
|
8803
|
+
}),
|
|
8804
|
+
required && !displayUrl && /* @__PURE__ */ jsx("p", {
|
|
8805
|
+
className: "text-sm text-kumo-danger mt-1",
|
|
8806
|
+
children: "This field is required"
|
|
8697
8807
|
})
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
open: pickerOpen,
|
|
8701
|
-
onOpenChange: setPickerOpen,
|
|
8702
|
-
onSelect: handleSelect,
|
|
8703
|
-
mimeTypeFilter: "image/",
|
|
8704
|
-
title: `Select ${label}`
|
|
8705
|
-
}),
|
|
8706
|
-
description && /* @__PURE__ */ jsx("p", {
|
|
8707
|
-
className: "text-xs text-kumo-subtle mt-1",
|
|
8708
|
-
children: description
|
|
8709
|
-
}),
|
|
8710
|
-
required && !displayUrl && /* @__PURE__ */ jsx("p", {
|
|
8711
|
-
className: "text-sm text-kumo-danger mt-1",
|
|
8712
|
-
children: "This field is required"
|
|
8713
|
-
})
|
|
8714
|
-
] });
|
|
8808
|
+
]
|
|
8809
|
+
});
|
|
8715
8810
|
}
|
|
8716
8811
|
function BylineCreditsEditor({ credits, bylines, onChange, onQuickCreate, onQuickEdit }) {
|
|
8717
8812
|
const [selectedBylineId, setSelectedBylineId] = React.useState("");
|
|
@@ -8891,7 +8986,10 @@ function BylineCreditsEditor({ credits, bylines, onChange, onQuickCreate, onQuic
|
|
|
8891
8986
|
children: [/* @__PURE__ */ jsx(Dialog.Close, { render: (p) => /* @__PURE__ */ jsx(Button, {
|
|
8892
8987
|
...p,
|
|
8893
8988
|
variant: "secondary",
|
|
8894
|
-
onClick:
|
|
8989
|
+
onClick: (e) => {
|
|
8990
|
+
resetQuickCreate();
|
|
8991
|
+
p.onClick?.(e);
|
|
8992
|
+
},
|
|
8895
8993
|
children: "Cancel"
|
|
8896
8994
|
}) }), /* @__PURE__ */ jsx(Button, {
|
|
8897
8995
|
type: "button",
|
|
@@ -9035,6 +9133,7 @@ function AuthorSelector({ authorId, users, onChange }) {
|
|
|
9035
9133
|
* Only renders when i18n is configured (manifest.i18n is present).
|
|
9036
9134
|
*/
|
|
9037
9135
|
function LocaleSwitcher({ locales, defaultLocale, value, onChange, showAll = false, className, size = "md" }) {
|
|
9136
|
+
const { _: _t } = useLingui();
|
|
9038
9137
|
return /* @__PURE__ */ jsxs("div", {
|
|
9039
9138
|
className: cn("flex items-center gap-1.5", className),
|
|
9040
9139
|
children: [/* @__PURE__ */ jsx(GlobeSimple, {
|
|
@@ -9043,14 +9142,23 @@ function LocaleSwitcher({ locales, defaultLocale, value, onChange, showAll = fal
|
|
|
9043
9142
|
}), /* @__PURE__ */ jsxs("select", {
|
|
9044
9143
|
value,
|
|
9045
9144
|
onChange: (e) => onChange(e.target.value),
|
|
9046
|
-
"aria-label":
|
|
9145
|
+
"aria-label": _t({
|
|
9146
|
+
id: "8NbHF7",
|
|
9147
|
+
message: "Locale"
|
|
9148
|
+
}),
|
|
9047
9149
|
className: cn("rounded-md border bg-transparent font-medium transition-colors", "focus:ring-kumo-ring focus:outline-none focus:ring-2 focus:ring-offset-1", "hover:bg-kumo-tint/50 cursor-pointer", size === "sm" ? "px-1.5 py-0.5 text-xs" : "px-2 py-1 text-sm"),
|
|
9048
9150
|
children: [showAll && /* @__PURE__ */ jsx("option", {
|
|
9049
9151
|
value: "",
|
|
9050
|
-
children:
|
|
9152
|
+
children: _t({
|
|
9153
|
+
id: "JjOi48",
|
|
9154
|
+
message: "All locales"
|
|
9155
|
+
})
|
|
9051
9156
|
}), locales.map((locale) => /* @__PURE__ */ jsxs("option", {
|
|
9052
9157
|
value: locale,
|
|
9053
|
-
children: [locale.toUpperCase(), locale === defaultLocale ?
|
|
9158
|
+
children: [locale.toUpperCase(), locale === defaultLocale ? _t({
|
|
9159
|
+
id: "FozKV6",
|
|
9160
|
+
message: " (default)"
|
|
9161
|
+
}) : ""]
|
|
9054
9162
|
}, locale))]
|
|
9055
9163
|
})]
|
|
9056
9164
|
});
|
|
@@ -9082,6 +9190,15 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
|
|
|
9082
9190
|
}, [items, searchQuery]);
|
|
9083
9191
|
const totalPages = Math.max(1, Math.ceil(filteredItems.length / PAGE_SIZE));
|
|
9084
9192
|
const paginatedItems = filteredItems.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE);
|
|
9193
|
+
React.useEffect(() => {
|
|
9194
|
+
if (page >= totalPages - 1 && hasMore && onLoadMore && !searchQuery) onLoadMore();
|
|
9195
|
+
}, [
|
|
9196
|
+
page,
|
|
9197
|
+
totalPages,
|
|
9198
|
+
hasMore,
|
|
9199
|
+
onLoadMore,
|
|
9200
|
+
searchQuery
|
|
9201
|
+
]);
|
|
9085
9202
|
return /* @__PURE__ */ jsxs("div", {
|
|
9086
9203
|
className: "space-y-4",
|
|
9087
9204
|
children: [
|
|
@@ -9102,6 +9219,7 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
|
|
|
9102
9219
|
}), /* @__PURE__ */ jsxs(Link$1, {
|
|
9103
9220
|
to: "/content/$collection/new",
|
|
9104
9221
|
params: { collection },
|
|
9222
|
+
search: { locale: activeLocale },
|
|
9105
9223
|
className: buttonVariants(),
|
|
9106
9224
|
children: [/* @__PURE__ */ jsx(Plus, {
|
|
9107
9225
|
className: "mr-2 h-4 w-4",
|
|
@@ -9192,6 +9310,7 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
|
|
|
9192
9310
|
/* @__PURE__ */ jsx(Link$1, {
|
|
9193
9311
|
to: "/content/$collection/new",
|
|
9194
9312
|
params: { collection },
|
|
9313
|
+
search: { locale: activeLocale },
|
|
9195
9314
|
className: "text-kumo-brand underline",
|
|
9196
9315
|
children: "Create your first one"
|
|
9197
9316
|
})
|
|
@@ -9220,6 +9339,7 @@ function ContentList({ collection, collectionLabel, items, trashedItems = [], is
|
|
|
9220
9339
|
className: "text-sm text-kumo-subtle",
|
|
9221
9340
|
children: [
|
|
9222
9341
|
filteredItems.length,
|
|
9342
|
+
hasMore && !searchQuery ? "+" : "",
|
|
9223
9343
|
" ",
|
|
9224
9344
|
filteredItems.length === 1 ? "item" : "items",
|
|
9225
9345
|
searchQuery && ` matching "${searchQuery}"`
|
|
@@ -10092,71 +10212,128 @@ const SLUG_LEADING_TRAILING_PATTERN = /^_|_$/g;
|
|
|
10092
10212
|
const SUPPORT_OPTIONS = [
|
|
10093
10213
|
{
|
|
10094
10214
|
value: "drafts",
|
|
10095
|
-
label:
|
|
10096
|
-
|
|
10215
|
+
label: {
|
|
10216
|
+
id: "M8kJqa",
|
|
10217
|
+
message: "Drafts"
|
|
10218
|
+
},
|
|
10219
|
+
description: {
|
|
10220
|
+
id: "ZpP0HR",
|
|
10221
|
+
message: "Save content as draft before publishing"
|
|
10222
|
+
}
|
|
10097
10223
|
},
|
|
10098
10224
|
{
|
|
10099
10225
|
value: "revisions",
|
|
10100
|
-
label:
|
|
10101
|
-
|
|
10226
|
+
label: {
|
|
10227
|
+
id: "ZdWn/b",
|
|
10228
|
+
message: "Revisions"
|
|
10229
|
+
},
|
|
10230
|
+
description: {
|
|
10231
|
+
id: "9kGBt9",
|
|
10232
|
+
message: "Track content history"
|
|
10233
|
+
}
|
|
10102
10234
|
},
|
|
10103
10235
|
{
|
|
10104
10236
|
value: "preview",
|
|
10105
|
-
label:
|
|
10106
|
-
|
|
10237
|
+
label: {
|
|
10238
|
+
id: "rdUucN",
|
|
10239
|
+
message: "Preview"
|
|
10240
|
+
},
|
|
10241
|
+
description: {
|
|
10242
|
+
id: "KRB02E",
|
|
10243
|
+
message: "Preview content before publishing"
|
|
10244
|
+
}
|
|
10107
10245
|
},
|
|
10108
10246
|
{
|
|
10109
10247
|
value: "search",
|
|
10110
|
-
label:
|
|
10111
|
-
|
|
10248
|
+
label: {
|
|
10249
|
+
id: "A1taO8",
|
|
10250
|
+
message: "Search"
|
|
10251
|
+
},
|
|
10252
|
+
description: {
|
|
10253
|
+
id: "T7NoTE",
|
|
10254
|
+
message: "Enable full-text search on this collection"
|
|
10255
|
+
}
|
|
10112
10256
|
}
|
|
10113
10257
|
];
|
|
10114
|
-
/**
|
|
10115
|
-
* System fields that exist on every collection
|
|
10116
|
-
* These are created automatically and cannot be modified
|
|
10117
|
-
*/
|
|
10118
10258
|
const SYSTEM_FIELDS = [
|
|
10119
10259
|
{
|
|
10120
10260
|
slug: "id",
|
|
10121
|
-
label:
|
|
10261
|
+
label: {
|
|
10262
|
+
id: "S0kLOH",
|
|
10263
|
+
message: "ID"
|
|
10264
|
+
},
|
|
10122
10265
|
type: "text",
|
|
10123
|
-
description:
|
|
10266
|
+
description: {
|
|
10267
|
+
id: "PUk2oG",
|
|
10268
|
+
message: "Unique identifier (ULID)"
|
|
10269
|
+
}
|
|
10124
10270
|
},
|
|
10125
10271
|
{
|
|
10126
10272
|
slug: "slug",
|
|
10127
|
-
label:
|
|
10273
|
+
label: {
|
|
10274
|
+
id: "L85WcV",
|
|
10275
|
+
message: "Slug"
|
|
10276
|
+
},
|
|
10128
10277
|
type: "text",
|
|
10129
|
-
description:
|
|
10278
|
+
description: {
|
|
10279
|
+
id: "f0WSdD",
|
|
10280
|
+
message: "URL-friendly identifier"
|
|
10281
|
+
}
|
|
10130
10282
|
},
|
|
10131
10283
|
{
|
|
10132
10284
|
slug: "status",
|
|
10133
|
-
label:
|
|
10285
|
+
label: {
|
|
10286
|
+
id: "uAQUqI",
|
|
10287
|
+
message: "Status"
|
|
10288
|
+
},
|
|
10134
10289
|
type: "text",
|
|
10135
|
-
description:
|
|
10290
|
+
description: {
|
|
10291
|
+
id: "khtYSH",
|
|
10292
|
+
message: "draft, published, or archived"
|
|
10293
|
+
}
|
|
10136
10294
|
},
|
|
10137
10295
|
{
|
|
10138
10296
|
slug: "created_at",
|
|
10139
|
-
label:
|
|
10297
|
+
label: {
|
|
10298
|
+
id: "88kg0+",
|
|
10299
|
+
message: "Created At"
|
|
10300
|
+
},
|
|
10140
10301
|
type: "datetime",
|
|
10141
|
-
description:
|
|
10302
|
+
description: {
|
|
10303
|
+
id: "SMcuRW",
|
|
10304
|
+
message: "When the entry was created"
|
|
10305
|
+
}
|
|
10142
10306
|
},
|
|
10143
10307
|
{
|
|
10144
10308
|
slug: "updated_at",
|
|
10145
|
-
label:
|
|
10309
|
+
label: {
|
|
10310
|
+
id: "Llcakz",
|
|
10311
|
+
message: "Updated At"
|
|
10312
|
+
},
|
|
10146
10313
|
type: "datetime",
|
|
10147
|
-
description:
|
|
10314
|
+
description: {
|
|
10315
|
+
id: "46AzZK",
|
|
10316
|
+
message: "When the entry was last modified"
|
|
10317
|
+
}
|
|
10148
10318
|
},
|
|
10149
10319
|
{
|
|
10150
10320
|
slug: "published_at",
|
|
10151
|
-
label:
|
|
10321
|
+
label: {
|
|
10322
|
+
id: "6QwXHP",
|
|
10323
|
+
message: "Published At"
|
|
10324
|
+
},
|
|
10152
10325
|
type: "datetime",
|
|
10153
|
-
description:
|
|
10326
|
+
description: {
|
|
10327
|
+
id: "MRpwV3",
|
|
10328
|
+
message: "When the entry was published"
|
|
10329
|
+
}
|
|
10154
10330
|
}
|
|
10155
10331
|
];
|
|
10156
10332
|
/**
|
|
10157
10333
|
* Content Type editor for creating/editing collections
|
|
10158
10334
|
*/
|
|
10159
10335
|
function ContentTypeEditor({ collection, isNew, isSaving, onSave, onAddField, onUpdateField, onDeleteField, onReorderFields }) {
|
|
10336
|
+
const { _: _t } = useLingui();
|
|
10160
10337
|
useNavigate$1();
|
|
10161
10338
|
const [slug, setSlug] = React.useState(collection?.slug ?? "");
|
|
10162
10339
|
const [label, setLabel] = React.useState(collection?.label ?? "");
|
|
@@ -10379,10 +10556,10 @@ function ContentTypeEditor({ collection, isNew, isSaving, onSave, onAddField, on
|
|
|
10379
10556
|
disabled: isFromCode
|
|
10380
10557
|
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("span", {
|
|
10381
10558
|
className: "text-sm font-medium",
|
|
10382
|
-
children: option.label
|
|
10559
|
+
children: _t(option.label)
|
|
10383
10560
|
}), /* @__PURE__ */ jsx("p", {
|
|
10384
10561
|
className: "text-xs text-kumo-subtle",
|
|
10385
|
-
children: option.description
|
|
10562
|
+
children: _t(option.description)
|
|
10386
10563
|
})] })]
|
|
10387
10564
|
}, option.value))]
|
|
10388
10565
|
}),
|
|
@@ -10662,6 +10839,7 @@ function FieldRow({ field, isFromCode, onEdit, onDelete }) {
|
|
|
10662
10839
|
});
|
|
10663
10840
|
}
|
|
10664
10841
|
function SystemFieldRow({ field }) {
|
|
10842
|
+
const { _: _t2 } = useLingui();
|
|
10665
10843
|
return /* @__PURE__ */ jsxs("div", {
|
|
10666
10844
|
className: "flex items-center px-4 py-2 opacity-75",
|
|
10667
10845
|
children: [
|
|
@@ -10674,7 +10852,7 @@ function SystemFieldRow({ field }) {
|
|
|
10674
10852
|
children: [
|
|
10675
10853
|
/* @__PURE__ */ jsx("span", {
|
|
10676
10854
|
className: "font-medium text-sm",
|
|
10677
|
-
children: field.label
|
|
10855
|
+
children: _t2(field.label)
|
|
10678
10856
|
}),
|
|
10679
10857
|
/* @__PURE__ */ jsx("code", {
|
|
10680
10858
|
className: "text-xs bg-kumo-tint px-1.5 py-0.5 rounded text-kumo-subtle",
|
|
@@ -10687,7 +10865,7 @@ function SystemFieldRow({ field }) {
|
|
|
10687
10865
|
]
|
|
10688
10866
|
}), /* @__PURE__ */ jsx("p", {
|
|
10689
10867
|
className: "text-xs text-kumo-subtle mt-0.5",
|
|
10690
|
-
children: field.description
|
|
10868
|
+
children: _t2(field.description)
|
|
10691
10869
|
})]
|
|
10692
10870
|
})
|
|
10693
10871
|
]
|
|
@@ -12076,6 +12254,7 @@ const OAUTH_PROVIDERS = [{
|
|
|
12076
12254
|
icon: /* @__PURE__ */ jsx(GoogleIcon, { className: "h-5 w-5" })
|
|
12077
12255
|
}];
|
|
12078
12256
|
function MagicLinkForm({ onBack }) {
|
|
12257
|
+
const { _: _t } = useLingui();
|
|
12079
12258
|
const [email, setEmail] = React.useState("");
|
|
12080
12259
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
12081
12260
|
const [error, setError] = React.useState(null);
|
|
@@ -12092,11 +12271,17 @@ function MagicLinkForm({ onBack }) {
|
|
|
12092
12271
|
});
|
|
12093
12272
|
if (!response.ok) {
|
|
12094
12273
|
const body = await response.json().catch(() => ({}));
|
|
12095
|
-
throw new Error(body?.error?.message ||
|
|
12274
|
+
throw new Error(body?.error?.message || _t({
|
|
12275
|
+
id: "dsPiA2",
|
|
12276
|
+
message: "Failed to send magic link"
|
|
12277
|
+
}));
|
|
12096
12278
|
}
|
|
12097
12279
|
setSent(true);
|
|
12098
12280
|
} catch (err) {
|
|
12099
|
-
setError(err instanceof Error ? err.message :
|
|
12281
|
+
setError(err instanceof Error ? err.message : _t({
|
|
12282
|
+
id: "dsPiA2",
|
|
12283
|
+
message: "Failed to send magic link"
|
|
12284
|
+
}));
|
|
12100
12285
|
} finally {
|
|
12101
12286
|
setIsLoading(false);
|
|
12102
12287
|
}
|
|
@@ -12121,30 +12306,40 @@ function MagicLinkForm({ onBack }) {
|
|
|
12121
12306
|
}),
|
|
12122
12307
|
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", {
|
|
12123
12308
|
className: "text-xl font-semibold",
|
|
12124
|
-
children:
|
|
12125
|
-
|
|
12309
|
+
children: _t({
|
|
12310
|
+
id: "v4fiSg",
|
|
12311
|
+
message: "Check your email"
|
|
12312
|
+
})
|
|
12313
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
12126
12314
|
className: "text-kumo-subtle mt-2",
|
|
12127
|
-
children:
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
", we've sent a sign-in link."
|
|
12134
|
-
]
|
|
12315
|
+
children: /* @__PURE__ */ jsx(Trans, {
|
|
12316
|
+
id: "HvU4EW",
|
|
12317
|
+
message: "If an account exists for <0>{email}</0>, we've sent a sign-in link.",
|
|
12318
|
+
values: { email },
|
|
12319
|
+
components: { 0: /* @__PURE__ */ jsx("span", { className: "font-medium text-kumo-default" }) }
|
|
12320
|
+
})
|
|
12135
12321
|
})] }),
|
|
12136
12322
|
/* @__PURE__ */ jsxs("div", {
|
|
12137
12323
|
className: "text-sm text-kumo-subtle",
|
|
12138
|
-
children: [/* @__PURE__ */ jsx("p", { children:
|
|
12324
|
+
children: [/* @__PURE__ */ jsx("p", { children: _t({
|
|
12325
|
+
id: "tfQcxX",
|
|
12326
|
+
message: "Click the link in the email to sign in."
|
|
12327
|
+
}) }), /* @__PURE__ */ jsx("p", {
|
|
12139
12328
|
className: "mt-2",
|
|
12140
|
-
children:
|
|
12329
|
+
children: _t({
|
|
12330
|
+
id: "Cw9Xfg",
|
|
12331
|
+
message: "The link will expire in 15 minutes."
|
|
12332
|
+
})
|
|
12141
12333
|
})]
|
|
12142
12334
|
}),
|
|
12143
12335
|
/* @__PURE__ */ jsx(Button, {
|
|
12144
12336
|
variant: "outline",
|
|
12145
12337
|
onClick: onBack,
|
|
12146
12338
|
className: "mt-4 w-full justify-center",
|
|
12147
|
-
children:
|
|
12339
|
+
children: _t({
|
|
12340
|
+
id: "VCoEm+",
|
|
12341
|
+
message: "Back to login"
|
|
12342
|
+
})
|
|
12148
12343
|
})
|
|
12149
12344
|
]
|
|
12150
12345
|
});
|
|
@@ -12153,7 +12348,10 @@ function MagicLinkForm({ onBack }) {
|
|
|
12153
12348
|
className: "space-y-4",
|
|
12154
12349
|
children: [
|
|
12155
12350
|
/* @__PURE__ */ jsx(Input, {
|
|
12156
|
-
label:
|
|
12351
|
+
label: _t({
|
|
12352
|
+
id: "ATGYL1",
|
|
12353
|
+
message: "Email address"
|
|
12354
|
+
}),
|
|
12157
12355
|
type: "email",
|
|
12158
12356
|
value: email,
|
|
12159
12357
|
onChange: (e) => setEmail(e.target.value),
|
|
@@ -12174,14 +12372,23 @@ function MagicLinkForm({ onBack }) {
|
|
|
12174
12372
|
variant: "primary",
|
|
12175
12373
|
loading: isLoading,
|
|
12176
12374
|
disabled: !email,
|
|
12177
|
-
children: isLoading ?
|
|
12375
|
+
children: isLoading ? _t({
|
|
12376
|
+
id: "IoAuJG",
|
|
12377
|
+
message: "Sending..."
|
|
12378
|
+
}) : _t({
|
|
12379
|
+
id: "+Ni3Gv",
|
|
12380
|
+
message: "Send magic link"
|
|
12381
|
+
})
|
|
12178
12382
|
}),
|
|
12179
12383
|
/* @__PURE__ */ jsx(Button, {
|
|
12180
12384
|
type: "button",
|
|
12181
12385
|
variant: "ghost",
|
|
12182
12386
|
className: "w-full justify-center",
|
|
12183
12387
|
onClick: onBack,
|
|
12184
|
-
children:
|
|
12388
|
+
children: _t({
|
|
12389
|
+
id: "VCoEm+",
|
|
12390
|
+
message: "Back to login"
|
|
12391
|
+
})
|
|
12185
12392
|
})
|
|
12186
12393
|
]
|
|
12187
12394
|
});
|
|
@@ -12191,6 +12398,8 @@ function handleOAuthClick(providerId) {
|
|
|
12191
12398
|
}
|
|
12192
12399
|
function LoginPage({ redirectUrl = "/_emdash/admin" }) {
|
|
12193
12400
|
const safeRedirectUrl = sanitizeRedirectUrl(redirectUrl);
|
|
12401
|
+
const { _: _t2 } = useLingui();
|
|
12402
|
+
const { locale, setLocale } = useLocale();
|
|
12194
12403
|
const [method, setMethod] = React.useState("passkey");
|
|
12195
12404
|
const [urlError, setUrlError] = React.useState(null);
|
|
12196
12405
|
const { data: manifest, isLoading: manifestLoading } = useQuery({
|
|
@@ -12205,7 +12414,11 @@ function LoginPage({ redirectUrl = "/_emdash/admin" }) {
|
|
|
12205
12414
|
const error = params.get("error");
|
|
12206
12415
|
const message = params.get("message");
|
|
12207
12416
|
if (error) {
|
|
12208
|
-
setUrlError(message ||
|
|
12417
|
+
setUrlError(message || _t2({
|
|
12418
|
+
id: "Xeb2Gt",
|
|
12419
|
+
message: "Authentication error: {error}",
|
|
12420
|
+
values: { error }
|
|
12421
|
+
}));
|
|
12209
12422
|
window.history.replaceState({}, "", window.location.pathname);
|
|
12210
12423
|
}
|
|
12211
12424
|
}, []);
|
|
@@ -12228,7 +12441,13 @@ function LoginPage({ redirectUrl = "/_emdash/admin" }) {
|
|
|
12228
12441
|
className: "text-center mb-8",
|
|
12229
12442
|
children: [/* @__PURE__ */ jsx(LogoLockup, { className: "h-10 mx-auto mb-2" }), /* @__PURE__ */ jsxs("h1", {
|
|
12230
12443
|
className: "text-2xl font-semibold text-kumo-default",
|
|
12231
|
-
children: [method === "passkey" &&
|
|
12444
|
+
children: [method === "passkey" && _t2({
|
|
12445
|
+
id: "lE0wHD",
|
|
12446
|
+
message: "Sign in to your site"
|
|
12447
|
+
}), method === "magic-link" && _t2({
|
|
12448
|
+
id: "me9L29",
|
|
12449
|
+
message: "Sign in with email"
|
|
12450
|
+
})]
|
|
12232
12451
|
})]
|
|
12233
12452
|
}),
|
|
12234
12453
|
urlError && /* @__PURE__ */ jsx("div", {
|
|
@@ -12244,7 +12463,10 @@ function LoginPage({ redirectUrl = "/_emdash/admin" }) {
|
|
|
12244
12463
|
optionsEndpoint: "/_emdash/api/auth/passkey/options",
|
|
12245
12464
|
verifyEndpoint: "/_emdash/api/auth/passkey/verify",
|
|
12246
12465
|
onSuccess: handleSuccess,
|
|
12247
|
-
buttonText:
|
|
12466
|
+
buttonText: _t2({
|
|
12467
|
+
id: "QjsOMP",
|
|
12468
|
+
message: "Sign in with Passkey"
|
|
12469
|
+
})
|
|
12248
12470
|
}),
|
|
12249
12471
|
/* @__PURE__ */ jsxs("div", {
|
|
12250
12472
|
className: "relative",
|
|
@@ -12255,7 +12477,10 @@ function LoginPage({ redirectUrl = "/_emdash/admin" }) {
|
|
|
12255
12477
|
className: "relative flex justify-center text-xs uppercase",
|
|
12256
12478
|
children: /* @__PURE__ */ jsx("span", {
|
|
12257
12479
|
className: "bg-kumo-base px-2 text-kumo-subtle",
|
|
12258
|
-
children:
|
|
12480
|
+
children: _t2({
|
|
12481
|
+
id: "zW+FpA",
|
|
12482
|
+
message: "Or continue with"
|
|
12483
|
+
})
|
|
12259
12484
|
})
|
|
12260
12485
|
})]
|
|
12261
12486
|
}),
|
|
@@ -12277,26 +12502,42 @@ function LoginPage({ redirectUrl = "/_emdash/admin" }) {
|
|
|
12277
12502
|
className: "w-full justify-center",
|
|
12278
12503
|
type: "button",
|
|
12279
12504
|
onClick: () => setMethod("magic-link"),
|
|
12280
|
-
children:
|
|
12505
|
+
children: _t2({
|
|
12506
|
+
id: "RxerEl",
|
|
12507
|
+
message: "Sign in with email link"
|
|
12508
|
+
})
|
|
12281
12509
|
})
|
|
12282
12510
|
]
|
|
12283
12511
|
}), method === "magic-link" && /* @__PURE__ */ jsx(MagicLinkForm, { onBack: () => setMethod("passkey") })]
|
|
12284
12512
|
}),
|
|
12285
12513
|
/* @__PURE__ */ jsx("p", {
|
|
12286
12514
|
className: "text-center mt-6 text-sm text-kumo-subtle",
|
|
12287
|
-
children: method === "passkey" ?
|
|
12515
|
+
children: method === "passkey" ? _t2({
|
|
12516
|
+
id: "+ET/av",
|
|
12517
|
+
message: "Use your registered passkey to sign in securely."
|
|
12518
|
+
}) : _t2({
|
|
12519
|
+
id: "pv+wH3",
|
|
12520
|
+
message: "We'll send you a link to sign in without a password."
|
|
12521
|
+
})
|
|
12288
12522
|
}),
|
|
12289
|
-
manifest?.signupEnabled && /* @__PURE__ */
|
|
12523
|
+
manifest?.signupEnabled && /* @__PURE__ */ jsx("p", {
|
|
12290
12524
|
className: "text-center mt-4 text-sm text-kumo-subtle",
|
|
12291
|
-
children:
|
|
12292
|
-
|
|
12293
|
-
" ",
|
|
12294
|
-
/* @__PURE__ */ jsx(Link$1, {
|
|
12525
|
+
children: /* @__PURE__ */ jsx(Trans, {
|
|
12526
|
+
id: "352VU2",
|
|
12527
|
+
message: "Don't have an account? <0>Sign up</0>",
|
|
12528
|
+
components: { 0: /* @__PURE__ */ jsx(Link$1, {
|
|
12295
12529
|
to: "/signup",
|
|
12296
|
-
className: "text-kumo-brand hover:underline font-medium"
|
|
12297
|
-
|
|
12298
|
-
|
|
12299
|
-
|
|
12530
|
+
className: "text-kumo-brand hover:underline font-medium"
|
|
12531
|
+
}) }
|
|
12532
|
+
})
|
|
12533
|
+
}),
|
|
12534
|
+
SUPPORTED_LOCALES.length > 1 && /* @__PURE__ */ jsx("div", {
|
|
12535
|
+
className: "mt-6 flex justify-center gap-2 text-xs text-kumo-subtle",
|
|
12536
|
+
children: SUPPORTED_LOCALES.map((l, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [i > 0 && /* @__PURE__ */ jsx("span", { children: "·" }), /* @__PURE__ */ jsx("button", {
|
|
12537
|
+
onClick: () => setLocale(l.code),
|
|
12538
|
+
className: l.code === locale ? "font-medium text-kumo-default" : "hover:text-kumo-default transition-colors",
|
|
12539
|
+
children: l.label
|
|
12540
|
+
})] }, l.code))
|
|
12300
12541
|
})
|
|
12301
12542
|
]
|
|
12302
12543
|
})
|
|
@@ -14471,7 +14712,7 @@ function ContentPickerModal({ open, onOpenChange, onSelect }) {
|
|
|
14471
14712
|
open,
|
|
14472
14713
|
onOpenChange,
|
|
14473
14714
|
children: /* @__PURE__ */ jsxs(Dialog, {
|
|
14474
|
-
className: "p-6 w-2xl h-[80vh] flex flex-col",
|
|
14715
|
+
className: "p-6 max-w-2xl h-[80vh] flex flex-col",
|
|
14475
14716
|
size: "lg",
|
|
14476
14717
|
children: [
|
|
14477
14718
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -14821,9 +15062,11 @@ function MenuEditor() {
|
|
|
14821
15062
|
/* @__PURE__ */ jsx(Input, {
|
|
14822
15063
|
label: "URL",
|
|
14823
15064
|
name: "url",
|
|
14824
|
-
type: "
|
|
15065
|
+
type: "text",
|
|
14825
15066
|
required: true,
|
|
14826
|
-
|
|
15067
|
+
pattern: "(https?://.+|/.*)",
|
|
15068
|
+
title: "Enter a URL (https://…) or a relative path (/…)",
|
|
15069
|
+
placeholder: "https://example.com or /about"
|
|
14827
15070
|
}),
|
|
14828
15071
|
/* @__PURE__ */ jsxs(Select, {
|
|
14829
15072
|
label: "Target",
|
|
@@ -14987,8 +15230,10 @@ function MenuEditor() {
|
|
|
14987
15230
|
editingItem.type === "custom" && /* @__PURE__ */ jsx(Input, {
|
|
14988
15231
|
label: "URL",
|
|
14989
15232
|
name: "url",
|
|
14990
|
-
type: "
|
|
15233
|
+
type: "text",
|
|
14991
15234
|
required: true,
|
|
15235
|
+
pattern: "(https?://.+|/.*)",
|
|
15236
|
+
title: "Enter a URL (https://…) or a relative path (/…)",
|
|
14992
15237
|
defaultValue: editingItem.custom_url || ""
|
|
14993
15238
|
}),
|
|
14994
15239
|
/* @__PURE__ */ jsxs(Select, {
|
|
@@ -15517,6 +15762,7 @@ function Redirects() {
|
|
|
15517
15762
|
setTab("redirects");
|
|
15518
15763
|
}
|
|
15519
15764
|
const redirects = redirectsQuery.data?.items ?? [];
|
|
15765
|
+
const loopRedirectIds = new Set(redirectsQuery.data?.loopRedirectIds ?? []);
|
|
15520
15766
|
return /* @__PURE__ */ jsxs("div", {
|
|
15521
15767
|
className: "space-y-6",
|
|
15522
15768
|
children: [
|
|
@@ -15550,173 +15796,208 @@ function Redirects() {
|
|
|
15550
15796
|
children: "404 Errors"
|
|
15551
15797
|
})]
|
|
15552
15798
|
}),
|
|
15553
|
-
tab === "redirects" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
15554
|
-
|
|
15555
|
-
|
|
15556
|
-
/* @__PURE__ */ jsxs("div", {
|
|
15557
|
-
className: "relative flex-1 max-w-md",
|
|
15558
|
-
children: [/* @__PURE__ */ jsx(MagnifyingGlass, {
|
|
15559
|
-
className: "absolute left-3 top-1/2 -translate-y-1/2 text-kumo-subtle",
|
|
15560
|
-
size: 16
|
|
15561
|
-
}), /* @__PURE__ */ jsx(Input, {
|
|
15562
|
-
placeholder: "Search source or destination...",
|
|
15563
|
-
className: "pl-10",
|
|
15564
|
-
value: search,
|
|
15565
|
-
onChange: (e) => setSearch(e.target.value)
|
|
15566
|
-
})]
|
|
15567
|
-
}),
|
|
15568
|
-
/* @__PURE__ */ jsxs("select", {
|
|
15569
|
-
value: filterEnabled,
|
|
15570
|
-
onChange: (e) => setFilterEnabled(e.target.value),
|
|
15571
|
-
className: "h-10 rounded-md border border-kumo-line bg-kumo-base px-3 text-sm",
|
|
15572
|
-
children: [
|
|
15573
|
-
/* @__PURE__ */ jsx("option", {
|
|
15574
|
-
value: "all",
|
|
15575
|
-
children: "All statuses"
|
|
15576
|
-
}),
|
|
15577
|
-
/* @__PURE__ */ jsx("option", {
|
|
15578
|
-
value: "true",
|
|
15579
|
-
children: "Enabled"
|
|
15580
|
-
}),
|
|
15581
|
-
/* @__PURE__ */ jsx("option", {
|
|
15582
|
-
value: "false",
|
|
15583
|
-
children: "Disabled"
|
|
15584
|
-
})
|
|
15585
|
-
]
|
|
15586
|
-
}),
|
|
15587
|
-
/* @__PURE__ */ jsxs("select", {
|
|
15588
|
-
value: filterAuto,
|
|
15589
|
-
onChange: (e) => setFilterAuto(e.target.value),
|
|
15590
|
-
className: "h-10 rounded-md border border-kumo-line bg-kumo-base px-3 text-sm",
|
|
15591
|
-
children: [
|
|
15592
|
-
/* @__PURE__ */ jsx("option", {
|
|
15593
|
-
value: "all",
|
|
15594
|
-
children: "All types"
|
|
15595
|
-
}),
|
|
15596
|
-
/* @__PURE__ */ jsx("option", {
|
|
15597
|
-
value: "false",
|
|
15598
|
-
children: "Manual"
|
|
15599
|
-
}),
|
|
15600
|
-
/* @__PURE__ */ jsx("option", {
|
|
15601
|
-
value: "true",
|
|
15602
|
-
children: "Auto (slug change)"
|
|
15603
|
-
})
|
|
15604
|
-
]
|
|
15605
|
-
})
|
|
15606
|
-
]
|
|
15607
|
-
}), redirectsQuery.isLoading ? /* @__PURE__ */ jsx("div", {
|
|
15608
|
-
className: "py-12 text-center text-kumo-subtle",
|
|
15609
|
-
children: "Loading redirects..."
|
|
15610
|
-
}) : redirects.length === 0 ? /* @__PURE__ */ jsxs("div", {
|
|
15611
|
-
className: "py-12 text-center text-kumo-subtle",
|
|
15612
|
-
children: [
|
|
15613
|
-
/* @__PURE__ */ jsx(ArrowsLeftRight, {
|
|
15614
|
-
size: 48,
|
|
15615
|
-
className: "mx-auto mb-4 opacity-30"
|
|
15616
|
-
}),
|
|
15617
|
-
/* @__PURE__ */ jsx("p", {
|
|
15618
|
-
className: "text-lg font-medium",
|
|
15619
|
-
children: "No redirects yet"
|
|
15620
|
-
}),
|
|
15621
|
-
/* @__PURE__ */ jsx("p", {
|
|
15622
|
-
className: "text-sm mt-1",
|
|
15623
|
-
children: "Create redirect rules to manage URL changes."
|
|
15624
|
-
})
|
|
15625
|
-
]
|
|
15626
|
-
}) : /* @__PURE__ */ jsxs("div", {
|
|
15627
|
-
className: "border rounded-lg",
|
|
15628
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
15629
|
-
className: "flex items-center gap-4 py-2 px-4 border-b bg-kumo-tint/50 text-sm font-medium text-kumo-subtle",
|
|
15630
|
-
children: [
|
|
15631
|
-
/* @__PURE__ */ jsx("div", {
|
|
15632
|
-
className: "flex-1",
|
|
15633
|
-
children: "Source"
|
|
15634
|
-
}),
|
|
15635
|
-
/* @__PURE__ */ jsx("div", { className: "w-8 text-center" }),
|
|
15636
|
-
/* @__PURE__ */ jsx("div", {
|
|
15637
|
-
className: "flex-1",
|
|
15638
|
-
children: "Destination"
|
|
15639
|
-
}),
|
|
15640
|
-
/* @__PURE__ */ jsx("div", {
|
|
15641
|
-
className: "w-14 text-center",
|
|
15642
|
-
children: "Code"
|
|
15643
|
-
}),
|
|
15644
|
-
/* @__PURE__ */ jsx("div", {
|
|
15645
|
-
className: "w-16 text-right",
|
|
15646
|
-
children: "Hits"
|
|
15647
|
-
}),
|
|
15648
|
-
/* @__PURE__ */ jsx("div", {
|
|
15649
|
-
className: "w-20 text-center",
|
|
15650
|
-
children: "Status"
|
|
15651
|
-
}),
|
|
15652
|
-
/* @__PURE__ */ jsx("div", { className: "w-20" })
|
|
15653
|
-
]
|
|
15654
|
-
}), redirects.map((r) => /* @__PURE__ */ jsxs("div", {
|
|
15655
|
-
className: cn("flex items-center gap-4 py-2 px-4 border-b last:border-0 text-sm", !r.enabled && "opacity-50"),
|
|
15799
|
+
tab === "redirects" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
15800
|
+
/* @__PURE__ */ jsxs("div", {
|
|
15801
|
+
className: "flex items-center gap-4",
|
|
15656
15802
|
children: [
|
|
15657
|
-
/* @__PURE__ */
|
|
15658
|
-
className: "flex-1
|
|
15659
|
-
|
|
15660
|
-
|
|
15661
|
-
|
|
15662
|
-
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
title: r.destination,
|
|
15669
|
-
children: r.destination
|
|
15670
|
-
}),
|
|
15671
|
-
/* @__PURE__ */ jsx("div", {
|
|
15672
|
-
className: "w-14 text-center",
|
|
15673
|
-
children: /* @__PURE__ */ jsx(Badge, {
|
|
15674
|
-
variant: "secondary",
|
|
15675
|
-
children: r.type
|
|
15676
|
-
})
|
|
15677
|
-
}),
|
|
15678
|
-
/* @__PURE__ */ jsx("div", {
|
|
15679
|
-
className: "w-16 text-right tabular-nums text-kumo-subtle",
|
|
15680
|
-
children: r.hits
|
|
15803
|
+
/* @__PURE__ */ jsxs("div", {
|
|
15804
|
+
className: "relative flex-1 max-w-md",
|
|
15805
|
+
children: [/* @__PURE__ */ jsx(MagnifyingGlass, {
|
|
15806
|
+
className: "absolute left-3 top-1/2 -translate-y-1/2 text-kumo-subtle",
|
|
15807
|
+
size: 16
|
|
15808
|
+
}), /* @__PURE__ */ jsx(Input, {
|
|
15809
|
+
placeholder: "Search source or destination...",
|
|
15810
|
+
className: "pl-10",
|
|
15811
|
+
value: search,
|
|
15812
|
+
onChange: (e) => setSearch(e.target.value)
|
|
15813
|
+
})]
|
|
15681
15814
|
}),
|
|
15682
|
-
/* @__PURE__ */
|
|
15683
|
-
|
|
15684
|
-
|
|
15685
|
-
|
|
15686
|
-
|
|
15687
|
-
|
|
15688
|
-
|
|
15815
|
+
/* @__PURE__ */ jsxs("select", {
|
|
15816
|
+
value: filterEnabled,
|
|
15817
|
+
onChange: (e) => setFilterEnabled(e.target.value),
|
|
15818
|
+
className: "h-10 rounded-md border border-kumo-line bg-kumo-base px-3 text-sm",
|
|
15819
|
+
children: [
|
|
15820
|
+
/* @__PURE__ */ jsx("option", {
|
|
15821
|
+
value: "all",
|
|
15822
|
+
children: "All statuses"
|
|
15689
15823
|
}),
|
|
15690
|
-
|
|
15691
|
-
|
|
15824
|
+
/* @__PURE__ */ jsx("option", {
|
|
15825
|
+
value: "true",
|
|
15826
|
+
children: "Enabled"
|
|
15827
|
+
}),
|
|
15828
|
+
/* @__PURE__ */ jsx("option", {
|
|
15829
|
+
value: "false",
|
|
15830
|
+
children: "Disabled"
|
|
15831
|
+
})
|
|
15832
|
+
]
|
|
15692
15833
|
}),
|
|
15693
|
-
/* @__PURE__ */ jsxs("
|
|
15694
|
-
|
|
15834
|
+
/* @__PURE__ */ jsxs("select", {
|
|
15835
|
+
value: filterAuto,
|
|
15836
|
+
onChange: (e) => setFilterAuto(e.target.value),
|
|
15837
|
+
className: "h-10 rounded-md border border-kumo-line bg-kumo-base px-3 text-sm",
|
|
15695
15838
|
children: [
|
|
15696
|
-
|
|
15697
|
-
|
|
15698
|
-
|
|
15699
|
-
children: "auto"
|
|
15839
|
+
/* @__PURE__ */ jsx("option", {
|
|
15840
|
+
value: "all",
|
|
15841
|
+
children: "All types"
|
|
15700
15842
|
}),
|
|
15701
|
-
/* @__PURE__ */ jsx("
|
|
15702
|
-
|
|
15703
|
-
|
|
15704
|
-
title: "Edit redirect",
|
|
15705
|
-
"aria-label": `Edit redirect ${r.source}`,
|
|
15706
|
-
children: /* @__PURE__ */ jsx(PencilSimple, { size: 14 })
|
|
15843
|
+
/* @__PURE__ */ jsx("option", {
|
|
15844
|
+
value: "false",
|
|
15845
|
+
children: "Manual"
|
|
15707
15846
|
}),
|
|
15708
|
-
/* @__PURE__ */ jsx("
|
|
15709
|
-
|
|
15710
|
-
|
|
15711
|
-
title: "Delete redirect",
|
|
15712
|
-
"aria-label": `Delete redirect ${r.source}`,
|
|
15713
|
-
children: /* @__PURE__ */ jsx(Trash, { size: 14 })
|
|
15847
|
+
/* @__PURE__ */ jsx("option", {
|
|
15848
|
+
value: "true",
|
|
15849
|
+
children: "Auto (slug change)"
|
|
15714
15850
|
})
|
|
15715
15851
|
]
|
|
15716
15852
|
})
|
|
15717
15853
|
]
|
|
15718
|
-
},
|
|
15719
|
-
|
|
15854
|
+
}),
|
|
15855
|
+
loopRedirectIds.size > 0 && /* @__PURE__ */ jsxs("div", {
|
|
15856
|
+
role: "alert",
|
|
15857
|
+
className: "flex items-start gap-3 rounded-lg border border-kumo-warning/50 bg-kumo-warning-tint p-4",
|
|
15858
|
+
children: [/* @__PURE__ */ jsx(WarningCircle, {
|
|
15859
|
+
size: 20,
|
|
15860
|
+
className: "mt-0.5 shrink-0 text-kumo-warning",
|
|
15861
|
+
weight: "fill",
|
|
15862
|
+
"aria-hidden": "true"
|
|
15863
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
|
|
15864
|
+
className: "text-sm font-medium text-kumo-warning",
|
|
15865
|
+
children: "Redirect loop detected"
|
|
15866
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
15867
|
+
className: "mt-1 text-sm text-kumo-subtle",
|
|
15868
|
+
children: [
|
|
15869
|
+
loopRedirectIds.size,
|
|
15870
|
+
" ",
|
|
15871
|
+
loopRedirectIds.size === 1 ? "redirect is" : "redirects are",
|
|
15872
|
+
" part of a loop. Visitors hitting these paths will see an error."
|
|
15873
|
+
]
|
|
15874
|
+
})] })]
|
|
15875
|
+
}),
|
|
15876
|
+
redirectsQuery.isLoading ? /* @__PURE__ */ jsx("div", {
|
|
15877
|
+
className: "py-12 text-center text-kumo-subtle",
|
|
15878
|
+
children: "Loading redirects..."
|
|
15879
|
+
}) : redirects.length === 0 ? /* @__PURE__ */ jsxs("div", {
|
|
15880
|
+
className: "py-12 text-center text-kumo-subtle",
|
|
15881
|
+
children: [
|
|
15882
|
+
/* @__PURE__ */ jsx(ArrowsLeftRight, {
|
|
15883
|
+
size: 48,
|
|
15884
|
+
className: "mx-auto mb-4 opacity-30"
|
|
15885
|
+
}),
|
|
15886
|
+
/* @__PURE__ */ jsx("p", {
|
|
15887
|
+
className: "text-lg font-medium",
|
|
15888
|
+
children: "No redirects yet"
|
|
15889
|
+
}),
|
|
15890
|
+
/* @__PURE__ */ jsx("p", {
|
|
15891
|
+
className: "text-sm mt-1",
|
|
15892
|
+
children: "Create redirect rules to manage URL changes."
|
|
15893
|
+
})
|
|
15894
|
+
]
|
|
15895
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
15896
|
+
className: "border rounded-lg",
|
|
15897
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
15898
|
+
className: "flex items-center gap-4 py-2 px-4 border-b bg-kumo-tint/50 text-sm font-medium text-kumo-subtle",
|
|
15899
|
+
children: [
|
|
15900
|
+
/* @__PURE__ */ jsx("div", {
|
|
15901
|
+
className: "flex-1",
|
|
15902
|
+
children: "Source"
|
|
15903
|
+
}),
|
|
15904
|
+
/* @__PURE__ */ jsx("div", { className: "w-8 text-center" }),
|
|
15905
|
+
/* @__PURE__ */ jsx("div", {
|
|
15906
|
+
className: "flex-1",
|
|
15907
|
+
children: "Destination"
|
|
15908
|
+
}),
|
|
15909
|
+
/* @__PURE__ */ jsx("div", {
|
|
15910
|
+
className: "w-14 text-center",
|
|
15911
|
+
children: "Code"
|
|
15912
|
+
}),
|
|
15913
|
+
/* @__PURE__ */ jsx("div", {
|
|
15914
|
+
className: "w-16 text-right",
|
|
15915
|
+
children: "Hits"
|
|
15916
|
+
}),
|
|
15917
|
+
/* @__PURE__ */ jsx("div", {
|
|
15918
|
+
className: "w-20 text-center",
|
|
15919
|
+
children: "Status"
|
|
15920
|
+
}),
|
|
15921
|
+
/* @__PURE__ */ jsx("div", { className: "w-20" })
|
|
15922
|
+
]
|
|
15923
|
+
}), redirects.map((r) => /* @__PURE__ */ jsxs("div", {
|
|
15924
|
+
className: cn("flex items-center gap-4 py-2 px-4 border-b last:border-0 text-sm", !r.enabled && "opacity-50"),
|
|
15925
|
+
children: [
|
|
15926
|
+
/* @__PURE__ */ jsx("div", {
|
|
15927
|
+
className: "flex-1 font-mono text-xs truncate",
|
|
15928
|
+
title: r.source,
|
|
15929
|
+
children: r.source
|
|
15930
|
+
}),
|
|
15931
|
+
/* @__PURE__ */ jsx("div", {
|
|
15932
|
+
className: "w-8 text-center text-kumo-subtle",
|
|
15933
|
+
children: /* @__PURE__ */ jsx(ArrowRight, { size: 14 })
|
|
15934
|
+
}),
|
|
15935
|
+
/* @__PURE__ */ jsx("div", {
|
|
15936
|
+
className: "flex-1 font-mono text-xs truncate",
|
|
15937
|
+
title: r.destination,
|
|
15938
|
+
children: r.destination
|
|
15939
|
+
}),
|
|
15940
|
+
/* @__PURE__ */ jsx("div", {
|
|
15941
|
+
className: "w-14 text-center",
|
|
15942
|
+
children: /* @__PURE__ */ jsx(Badge, {
|
|
15943
|
+
variant: "secondary",
|
|
15944
|
+
children: r.type
|
|
15945
|
+
})
|
|
15946
|
+
}),
|
|
15947
|
+
/* @__PURE__ */ jsx("div", {
|
|
15948
|
+
className: "w-16 text-right tabular-nums text-kumo-subtle",
|
|
15949
|
+
children: r.hits
|
|
15950
|
+
}),
|
|
15951
|
+
/* @__PURE__ */ jsx("div", {
|
|
15952
|
+
className: "w-20 text-center",
|
|
15953
|
+
children: /* @__PURE__ */ jsx(Switch, {
|
|
15954
|
+
checked: r.enabled,
|
|
15955
|
+
onCheckedChange: (checked) => toggleMutation.mutate({
|
|
15956
|
+
id: r.id,
|
|
15957
|
+
enabled: checked
|
|
15958
|
+
}),
|
|
15959
|
+
"aria-label": r.enabled ? "Disable redirect" : "Enable redirect"
|
|
15960
|
+
})
|
|
15961
|
+
}),
|
|
15962
|
+
/* @__PURE__ */ jsxs("div", {
|
|
15963
|
+
className: "w-20 flex items-center justify-end gap-1",
|
|
15964
|
+
children: [
|
|
15965
|
+
loopRedirectIds.has(r.id) && /* @__PURE__ */ jsx("span", {
|
|
15966
|
+
title: "Part of a redirect loop",
|
|
15967
|
+
className: "mr-1 inline-flex",
|
|
15968
|
+
children: /* @__PURE__ */ jsx(WarningCircle, {
|
|
15969
|
+
size: 14,
|
|
15970
|
+
weight: "fill",
|
|
15971
|
+
className: "text-kumo-warning",
|
|
15972
|
+
role: "img",
|
|
15973
|
+
"aria-label": "Part of a redirect loop"
|
|
15974
|
+
})
|
|
15975
|
+
}),
|
|
15976
|
+
r.auto && /* @__PURE__ */ jsx(Badge, {
|
|
15977
|
+
variant: "outline",
|
|
15978
|
+
className: "mr-1 text-xs",
|
|
15979
|
+
children: "auto"
|
|
15980
|
+
}),
|
|
15981
|
+
/* @__PURE__ */ jsx("button", {
|
|
15982
|
+
onClick: () => setEditRedirect(r),
|
|
15983
|
+
className: "p-1 text-kumo-subtle hover:text-kumo-default",
|
|
15984
|
+
title: "Edit redirect",
|
|
15985
|
+
"aria-label": `Edit redirect ${r.source}`,
|
|
15986
|
+
children: /* @__PURE__ */ jsx(PencilSimple, { size: 14 })
|
|
15987
|
+
}),
|
|
15988
|
+
/* @__PURE__ */ jsx("button", {
|
|
15989
|
+
onClick: () => setDeleteId(r.id),
|
|
15990
|
+
className: "p-1 text-kumo-subtle hover:text-kumo-danger",
|
|
15991
|
+
title: "Delete redirect",
|
|
15992
|
+
"aria-label": `Delete redirect ${r.source}`,
|
|
15993
|
+
children: /* @__PURE__ */ jsx(Trash, { size: 14 })
|
|
15994
|
+
})
|
|
15995
|
+
]
|
|
15996
|
+
})
|
|
15997
|
+
]
|
|
15998
|
+
}, r.id))]
|
|
15999
|
+
})
|
|
16000
|
+
] }),
|
|
15720
16001
|
tab === "404s" && /* @__PURE__ */ jsx(NotFoundPanel, {
|
|
15721
16002
|
items: notFoundQuery.data ?? [],
|
|
15722
16003
|
onCreateRedirect: handleCreateFrom404
|
|
@@ -16463,13 +16744,18 @@ function Settings() {
|
|
|
16463
16744
|
queryKey: ["manifest"],
|
|
16464
16745
|
queryFn: fetchManifest
|
|
16465
16746
|
});
|
|
16747
|
+
const { _: _t } = useLingui();
|
|
16748
|
+
const { locale, setLocale } = useLocale();
|
|
16466
16749
|
const showSecuritySettings = manifest?.authMode === "passkey";
|
|
16467
16750
|
return /* @__PURE__ */ jsxs("div", {
|
|
16468
16751
|
className: "space-y-6",
|
|
16469
16752
|
children: [
|
|
16470
16753
|
/* @__PURE__ */ jsx("h1", {
|
|
16471
16754
|
className: "text-2xl font-bold",
|
|
16472
|
-
children:
|
|
16755
|
+
children: _t({
|
|
16756
|
+
id: "Tz0i8g",
|
|
16757
|
+
message: "Settings"
|
|
16758
|
+
})
|
|
16473
16759
|
}),
|
|
16474
16760
|
/* @__PURE__ */ jsxs("div", {
|
|
16475
16761
|
className: "space-y-2",
|
|
@@ -16477,20 +16763,38 @@ function Settings() {
|
|
|
16477
16763
|
/* @__PURE__ */ jsx(SettingsLink, {
|
|
16478
16764
|
to: "/settings/general",
|
|
16479
16765
|
icon: /* @__PURE__ */ jsx(Gear, { className: "h-5 w-5" }),
|
|
16480
|
-
title:
|
|
16481
|
-
|
|
16766
|
+
title: _t({
|
|
16767
|
+
id: "Weq9zb",
|
|
16768
|
+
message: "General"
|
|
16769
|
+
}),
|
|
16770
|
+
description: _t({
|
|
16771
|
+
id: "RR0ADZ",
|
|
16772
|
+
message: "Site identity, logo, favicon, and reading preferences"
|
|
16773
|
+
})
|
|
16482
16774
|
}),
|
|
16483
16775
|
/* @__PURE__ */ jsx(SettingsLink, {
|
|
16484
16776
|
to: "/settings/social",
|
|
16485
16777
|
icon: /* @__PURE__ */ jsx(ShareNetwork, { className: "h-5 w-5" }),
|
|
16486
|
-
title:
|
|
16487
|
-
|
|
16778
|
+
title: _t({
|
|
16779
|
+
id: "d0rUsW",
|
|
16780
|
+
message: "Social Links"
|
|
16781
|
+
}),
|
|
16782
|
+
description: _t({
|
|
16783
|
+
id: "qS3mgX",
|
|
16784
|
+
message: "Social media profile links"
|
|
16785
|
+
})
|
|
16488
16786
|
}),
|
|
16489
16787
|
/* @__PURE__ */ jsx(SettingsLink, {
|
|
16490
16788
|
to: "/settings/seo",
|
|
16491
16789
|
icon: /* @__PURE__ */ jsx(MagnifyingGlass, { className: "h-5 w-5" }),
|
|
16492
|
-
title:
|
|
16493
|
-
|
|
16790
|
+
title: _t({
|
|
16791
|
+
id: "4Ml90q",
|
|
16792
|
+
message: "SEO"
|
|
16793
|
+
}),
|
|
16794
|
+
description: _t({
|
|
16795
|
+
id: "zY0S+v",
|
|
16796
|
+
message: "Search engine optimization and verification"
|
|
16797
|
+
})
|
|
16494
16798
|
})
|
|
16495
16799
|
]
|
|
16496
16800
|
}),
|
|
@@ -16499,13 +16803,25 @@ function Settings() {
|
|
|
16499
16803
|
children: [/* @__PURE__ */ jsx(SettingsLink, {
|
|
16500
16804
|
to: "/settings/security",
|
|
16501
16805
|
icon: /* @__PURE__ */ jsx(Shield, { className: "h-5 w-5" }),
|
|
16502
|
-
title:
|
|
16503
|
-
|
|
16806
|
+
title: _t({
|
|
16807
|
+
id: "a3LDKx",
|
|
16808
|
+
message: "Security"
|
|
16809
|
+
}),
|
|
16810
|
+
description: _t({
|
|
16811
|
+
id: "OfnTKV",
|
|
16812
|
+
message: "Manage your passkeys and authentication"
|
|
16813
|
+
})
|
|
16504
16814
|
}), /* @__PURE__ */ jsx(SettingsLink, {
|
|
16505
16815
|
to: "/settings/allowed-domains",
|
|
16506
16816
|
icon: /* @__PURE__ */ jsx(Globe, { className: "h-5 w-5" }),
|
|
16507
|
-
title:
|
|
16508
|
-
|
|
16817
|
+
title: _t({
|
|
16818
|
+
id: "Tllxyd",
|
|
16819
|
+
message: "Self-Signup Domains"
|
|
16820
|
+
}),
|
|
16821
|
+
description: _t({
|
|
16822
|
+
id: "DsZc8w",
|
|
16823
|
+
message: "Allow users from specific domains to sign up"
|
|
16824
|
+
})
|
|
16509
16825
|
})]
|
|
16510
16826
|
}),
|
|
16511
16827
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -16513,49 +16829,217 @@ function Settings() {
|
|
|
16513
16829
|
children: [/* @__PURE__ */ jsx(SettingsLink, {
|
|
16514
16830
|
to: "/settings/api-tokens",
|
|
16515
16831
|
icon: /* @__PURE__ */ jsx(Key, { className: "h-5 w-5" }),
|
|
16516
|
-
title:
|
|
16517
|
-
|
|
16832
|
+
title: _t({
|
|
16833
|
+
id: "ZiooJI",
|
|
16834
|
+
message: "API Tokens"
|
|
16835
|
+
}),
|
|
16836
|
+
description: _t({
|
|
16837
|
+
id: "dhH+RW",
|
|
16838
|
+
message: "Create personal access tokens for programmatic API access"
|
|
16839
|
+
})
|
|
16518
16840
|
}), /* @__PURE__ */ jsx(SettingsLink, {
|
|
16519
16841
|
to: "/settings/email",
|
|
16520
16842
|
icon: /* @__PURE__ */ jsx(Envelope, { className: "h-5 w-5" }),
|
|
16521
|
-
title:
|
|
16522
|
-
|
|
16843
|
+
title: _t({
|
|
16844
|
+
id: "O3oNi5",
|
|
16845
|
+
message: "Email"
|
|
16846
|
+
}),
|
|
16847
|
+
description: _t({
|
|
16848
|
+
id: "/JPN+P",
|
|
16849
|
+
message: "View email provider status and send test emails"
|
|
16850
|
+
})
|
|
16523
16851
|
})]
|
|
16852
|
+
}),
|
|
16853
|
+
SUPPORTED_LOCALES.length > 1 && /* @__PURE__ */ jsx("div", {
|
|
16854
|
+
className: "space-y-2",
|
|
16855
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
16856
|
+
className: "flex items-center justify-between p-4 rounded-lg border bg-kumo-base",
|
|
16857
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
16858
|
+
className: "flex items-center gap-3",
|
|
16859
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
16860
|
+
className: "text-kumo-subtle",
|
|
16861
|
+
children: /* @__PURE__ */ jsx(GlobeSimple, { className: "h-5 w-5" })
|
|
16862
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
16863
|
+
className: "font-medium",
|
|
16864
|
+
children: _t({
|
|
16865
|
+
id: "vXIe7J",
|
|
16866
|
+
message: "Language"
|
|
16867
|
+
})
|
|
16868
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
16869
|
+
className: "text-sm text-kumo-subtle",
|
|
16870
|
+
children: _t({
|
|
16871
|
+
id: "Y8S9QC",
|
|
16872
|
+
message: "Choose your preferred admin language"
|
|
16873
|
+
})
|
|
16874
|
+
})] })]
|
|
16875
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
16876
|
+
className: "flex gap-1",
|
|
16877
|
+
children: SUPPORTED_LOCALES.map((l) => /* @__PURE__ */ jsx("button", {
|
|
16878
|
+
onClick: () => setLocale(l.code),
|
|
16879
|
+
className: cn("rounded-md px-3 py-1.5 text-sm transition-colors", l.code === locale ? "bg-kumo-brand/10 text-kumo-brand font-medium" : "hover:bg-kumo-tint"),
|
|
16880
|
+
children: l.label
|
|
16881
|
+
}, l.code))
|
|
16882
|
+
})]
|
|
16883
|
+
})
|
|
16524
16884
|
})
|
|
16525
16885
|
]
|
|
16526
16886
|
});
|
|
16527
16887
|
}
|
|
16528
16888
|
|
|
16529
16889
|
//#endregion
|
|
16530
|
-
//#region src/components/
|
|
16890
|
+
//#region src/components/users/roleDefinitions.ts
|
|
16531
16891
|
/**
|
|
16532
|
-
*
|
|
16533
|
-
*
|
|
16534
|
-
* Only available when using passkey auth. When external auth (e.g., Cloudflare Access)
|
|
16535
|
-
* is configured, this page shows an informational message instead.
|
|
16892
|
+
* Canonical role levels for admin UI (badge colors, selects, labels).
|
|
16893
|
+
* Allowed Domains UI only offers default roles up to Editor (40), not Admin (50).
|
|
16536
16894
|
*/
|
|
16537
|
-
const
|
|
16895
|
+
const ROLE_ENTRIES = [
|
|
16538
16896
|
{
|
|
16539
16897
|
value: 10,
|
|
16540
|
-
|
|
16898
|
+
color: "gray",
|
|
16899
|
+
label: {
|
|
16900
|
+
id: "M2vfqB",
|
|
16901
|
+
message: "Subscriber"
|
|
16902
|
+
},
|
|
16903
|
+
description: {
|
|
16904
|
+
id: "m7BmGK",
|
|
16905
|
+
message: "Can view content"
|
|
16906
|
+
}
|
|
16541
16907
|
},
|
|
16542
16908
|
{
|
|
16543
16909
|
value: 20,
|
|
16544
|
-
|
|
16910
|
+
color: "blue",
|
|
16911
|
+
label: {
|
|
16912
|
+
id: "3L51iw",
|
|
16913
|
+
message: "Contributor"
|
|
16914
|
+
},
|
|
16915
|
+
description: {
|
|
16916
|
+
id: "WzyYFi",
|
|
16917
|
+
message: "Can create content"
|
|
16918
|
+
}
|
|
16545
16919
|
},
|
|
16546
16920
|
{
|
|
16547
16921
|
value: 30,
|
|
16548
|
-
|
|
16922
|
+
color: "green",
|
|
16923
|
+
label: {
|
|
16924
|
+
id: "VbeIOx",
|
|
16925
|
+
message: "Author"
|
|
16926
|
+
},
|
|
16927
|
+
description: {
|
|
16928
|
+
id: "1onhKx",
|
|
16929
|
+
message: "Can publish own content"
|
|
16930
|
+
}
|
|
16549
16931
|
},
|
|
16550
16932
|
{
|
|
16551
16933
|
value: 40,
|
|
16552
|
-
|
|
16934
|
+
color: "purple",
|
|
16935
|
+
label: {
|
|
16936
|
+
id: "uBAxNB",
|
|
16937
|
+
message: "Editor"
|
|
16938
|
+
},
|
|
16939
|
+
description: {
|
|
16940
|
+
id: "ppZiw8",
|
|
16941
|
+
message: "Can manage all content"
|
|
16942
|
+
}
|
|
16943
|
+
},
|
|
16944
|
+
{
|
|
16945
|
+
value: 50,
|
|
16946
|
+
color: "red",
|
|
16947
|
+
label: {
|
|
16948
|
+
id: "U3pytU",
|
|
16949
|
+
message: "Admin"
|
|
16950
|
+
},
|
|
16951
|
+
description: {
|
|
16952
|
+
id: "scmRyR",
|
|
16953
|
+
message: "Full access"
|
|
16954
|
+
}
|
|
16553
16955
|
}
|
|
16554
16956
|
];
|
|
16555
|
-
|
|
16556
|
-
|
|
16957
|
+
const ROLE_CONFIG = Object.fromEntries(ROLE_ENTRIES.map((e) => [e.value, {
|
|
16958
|
+
label: e.label,
|
|
16959
|
+
description: e.description,
|
|
16960
|
+
color: e.color
|
|
16961
|
+
}]));
|
|
16962
|
+
function unknownRoleConfig(role) {
|
|
16963
|
+
return {
|
|
16964
|
+
label: {
|
|
16965
|
+
id: "h4POyA",
|
|
16966
|
+
message: "Role {role}",
|
|
16967
|
+
values: { role }
|
|
16968
|
+
},
|
|
16969
|
+
description: {
|
|
16970
|
+
id: "C52+JH",
|
|
16971
|
+
message: "Unknown role"
|
|
16972
|
+
},
|
|
16973
|
+
color: "gray"
|
|
16974
|
+
};
|
|
16557
16975
|
}
|
|
16976
|
+
/** Badge / display config for a numeric role level */
|
|
16977
|
+
function getRoleConfig(role) {
|
|
16978
|
+
return ROLE_CONFIG[role] ?? unknownRoleConfig(role);
|
|
16979
|
+
}
|
|
16980
|
+
|
|
16981
|
+
//#endregion
|
|
16982
|
+
//#region src/components/users/useRolesConfig.ts
|
|
16983
|
+
const MSG_ROLE_UNKNOWN = {
|
|
16984
|
+
id: "Ef7StM",
|
|
16985
|
+
message: "Unknown"
|
|
16986
|
+
};
|
|
16987
|
+
/**
|
|
16988
|
+
* Shared resolved role strings + descriptor rows for selects (after `i18n` is active).
|
|
16989
|
+
*/
|
|
16990
|
+
function useRolesConfig() {
|
|
16991
|
+
const { _: _t } = useLingui();
|
|
16992
|
+
const roles = React.useMemo(() => ROLE_ENTRIES.map(({ value, label, description }) => ({
|
|
16993
|
+
value,
|
|
16994
|
+
label: _t(label),
|
|
16995
|
+
description: _t(description)
|
|
16996
|
+
})), [_t]);
|
|
16997
|
+
const roleLabels = React.useMemo(() => Object.fromEntries(ROLE_ENTRIES.map((r) => [String(r.value), _t(r.label)])), [_t]);
|
|
16998
|
+
return {
|
|
16999
|
+
roleLabels,
|
|
17000
|
+
getRoleLabel: React.useCallback((level) => roleLabels[String(level)] ?? _t(MSG_ROLE_UNKNOWN), [roleLabels, _t]),
|
|
17001
|
+
roles
|
|
17002
|
+
};
|
|
17003
|
+
}
|
|
17004
|
+
|
|
17005
|
+
//#endregion
|
|
17006
|
+
//#region src/components/settings/useAllowedDomainsRolesConfig.ts
|
|
17007
|
+
/** Self-signup default role must not be Admin (API / product rule). */
|
|
17008
|
+
const MAX_SELF_SIGNUP_DEFAULT_ROLE = 40;
|
|
17009
|
+
/**
|
|
17010
|
+
* Role labels and selects for Allowed Domains (Subscriber–Editor only for defaults).
|
|
17011
|
+
* Built on {@link useRolesConfig}; keeps the filter + `Select` `items` shape in one place.
|
|
17012
|
+
*/
|
|
17013
|
+
function useAllowedDomainsRolesConfig() {
|
|
17014
|
+
const { roleLabels, getRoleLabel, roles } = useRolesConfig();
|
|
17015
|
+
const signupRoles = React.useMemo(() => roles.filter((r) => r.value <= MAX_SELF_SIGNUP_DEFAULT_ROLE), [roles]);
|
|
17016
|
+
return {
|
|
17017
|
+
getRoleLabel,
|
|
17018
|
+
signupRoles,
|
|
17019
|
+
signupRoleItems: React.useMemo(() => {
|
|
17020
|
+
const entries = signupRoles.map((r) => {
|
|
17021
|
+
const label = roleLabels[String(r.value)];
|
|
17022
|
+
return [String(r.value), label ?? getRoleLabel(r.value)];
|
|
17023
|
+
});
|
|
17024
|
+
return Object.fromEntries(entries);
|
|
17025
|
+
}, [
|
|
17026
|
+
signupRoles,
|
|
17027
|
+
roleLabels,
|
|
17028
|
+
getRoleLabel
|
|
17029
|
+
])
|
|
17030
|
+
};
|
|
17031
|
+
}
|
|
17032
|
+
|
|
17033
|
+
//#endregion
|
|
17034
|
+
//#region src/components/settings/AllowedDomainsSettings.tsx
|
|
17035
|
+
/**
|
|
17036
|
+
* Allowed Domains Settings - Self-signup domain management
|
|
17037
|
+
*
|
|
17038
|
+
* Only available when using passkey auth. When external auth (e.g., Cloudflare Access)
|
|
17039
|
+
* is configured, this page shows an informational message instead.
|
|
17040
|
+
*/
|
|
16558
17041
|
function AllowedDomainsSettings() {
|
|
17042
|
+
const { getRoleLabel, signupRoles, signupRoleItems } = useAllowedDomainsRolesConfig();
|
|
16559
17043
|
const queryClient = useQueryClient();
|
|
16560
17044
|
const [isAddingDomain, setIsAddingDomain] = React.useState(false);
|
|
16561
17045
|
const [editingDomain, setEditingDomain] = React.useState(null);
|
|
@@ -16747,7 +17231,7 @@ function AllowedDomainsSettings() {
|
|
|
16747
17231
|
children: domain.domain
|
|
16748
17232
|
}), /* @__PURE__ */ jsxs("div", {
|
|
16749
17233
|
className: "text-sm text-kumo-subtle",
|
|
16750
|
-
children: ["Default role: ",
|
|
17234
|
+
children: ["Default role: ", getRoleLabel(domain.defaultRole)]
|
|
16751
17235
|
})] })]
|
|
16752
17236
|
}), /* @__PURE__ */ jsxs("div", {
|
|
16753
17237
|
className: "flex items-center gap-2",
|
|
@@ -16808,8 +17292,8 @@ function AllowedDomainsSettings() {
|
|
|
16808
17292
|
label: "Default Role",
|
|
16809
17293
|
value: String(newRole),
|
|
16810
17294
|
onValueChange: (v) => v !== null && setNewRole(Number(v)),
|
|
16811
|
-
items:
|
|
16812
|
-
children:
|
|
17295
|
+
items: signupRoleItems,
|
|
17296
|
+
children: signupRoles.map((role) => /* @__PURE__ */ jsx(Select.Option, {
|
|
16813
17297
|
value: String(role.value),
|
|
16814
17298
|
children: role.label
|
|
16815
17299
|
}, role.value))
|
|
@@ -16869,8 +17353,8 @@ function AllowedDomainsSettings() {
|
|
|
16869
17353
|
label: "Default Role",
|
|
16870
17354
|
value: String(editingDomain?.defaultRole ?? 30),
|
|
16871
17355
|
onValueChange: (v) => v !== null && editingDomain && handleUpdateRole(editingDomain.domain, Number(v)),
|
|
16872
|
-
items:
|
|
16873
|
-
children:
|
|
17356
|
+
items: signupRoleItems,
|
|
17357
|
+
children: signupRoles.map((role) => /* @__PURE__ */ jsx(Select.Option, {
|
|
16874
17358
|
value: String(role.value),
|
|
16875
17359
|
children: role.label
|
|
16876
17360
|
}, role.value))
|
|
@@ -16929,25 +17413,121 @@ function AllowedDomainsSettings() {
|
|
|
16929
17413
|
const EXPIRY_OPTIONS = [
|
|
16930
17414
|
{
|
|
16931
17415
|
value: "none",
|
|
16932
|
-
label:
|
|
17416
|
+
label: {
|
|
17417
|
+
id: "JYZYJA",
|
|
17418
|
+
message: "No expiry"
|
|
17419
|
+
}
|
|
16933
17420
|
},
|
|
16934
17421
|
{
|
|
16935
17422
|
value: "7d",
|
|
16936
|
-
label:
|
|
17423
|
+
label: {
|
|
17424
|
+
id: "rJe6vw",
|
|
17425
|
+
message: "7 days"
|
|
17426
|
+
}
|
|
16937
17427
|
},
|
|
16938
17428
|
{
|
|
16939
17429
|
value: "30d",
|
|
16940
|
-
label:
|
|
17430
|
+
label: {
|
|
17431
|
+
id: "P9cEa2",
|
|
17432
|
+
message: "30 days"
|
|
17433
|
+
}
|
|
16941
17434
|
},
|
|
16942
17435
|
{
|
|
16943
17436
|
value: "90d",
|
|
16944
|
-
label:
|
|
17437
|
+
label: {
|
|
17438
|
+
id: "h28hXf",
|
|
17439
|
+
message: "90 days"
|
|
17440
|
+
}
|
|
16945
17441
|
},
|
|
16946
17442
|
{
|
|
16947
17443
|
value: "365d",
|
|
16948
|
-
label:
|
|
17444
|
+
label: {
|
|
17445
|
+
id: "+N7uug",
|
|
17446
|
+
message: "1 year"
|
|
17447
|
+
}
|
|
16949
17448
|
}
|
|
16950
17449
|
];
|
|
17450
|
+
const API_TOKEN_SCOPE_VALUES = [
|
|
17451
|
+
{
|
|
17452
|
+
scope: API_TOKEN_SCOPES.ContentRead,
|
|
17453
|
+
label: {
|
|
17454
|
+
id: "DqsyRK",
|
|
17455
|
+
message: "Content Read"
|
|
17456
|
+
},
|
|
17457
|
+
description: {
|
|
17458
|
+
id: "Pho0BC",
|
|
17459
|
+
message: "Read content entries"
|
|
17460
|
+
}
|
|
17461
|
+
},
|
|
17462
|
+
{
|
|
17463
|
+
scope: API_TOKEN_SCOPES.ContentWrite,
|
|
17464
|
+
label: {
|
|
17465
|
+
id: "js1bld",
|
|
17466
|
+
message: "Content Write"
|
|
17467
|
+
},
|
|
17468
|
+
description: {
|
|
17469
|
+
id: "e48Hn6",
|
|
17470
|
+
message: "Create, update, delete content"
|
|
17471
|
+
}
|
|
17472
|
+
},
|
|
17473
|
+
{
|
|
17474
|
+
scope: API_TOKEN_SCOPES.MediaRead,
|
|
17475
|
+
label: {
|
|
17476
|
+
id: "TNFBJj",
|
|
17477
|
+
message: "Media Read"
|
|
17478
|
+
},
|
|
17479
|
+
description: {
|
|
17480
|
+
id: "IxcUJS",
|
|
17481
|
+
message: "Read media files"
|
|
17482
|
+
}
|
|
17483
|
+
},
|
|
17484
|
+
{
|
|
17485
|
+
scope: API_TOKEN_SCOPES.MediaWrite,
|
|
17486
|
+
label: {
|
|
17487
|
+
id: "nAGBQY",
|
|
17488
|
+
message: "Media Write"
|
|
17489
|
+
},
|
|
17490
|
+
description: {
|
|
17491
|
+
id: "SrZ1jh",
|
|
17492
|
+
message: "Upload and delete media"
|
|
17493
|
+
}
|
|
17494
|
+
},
|
|
17495
|
+
{
|
|
17496
|
+
scope: API_TOKEN_SCOPES.SchemaRead,
|
|
17497
|
+
label: {
|
|
17498
|
+
id: "19WSvR",
|
|
17499
|
+
message: "Schema Read"
|
|
17500
|
+
},
|
|
17501
|
+
description: {
|
|
17502
|
+
id: "nEEs8e",
|
|
17503
|
+
message: "Read collection schemas"
|
|
17504
|
+
}
|
|
17505
|
+
},
|
|
17506
|
+
{
|
|
17507
|
+
scope: API_TOKEN_SCOPES.SchemaWrite,
|
|
17508
|
+
label: {
|
|
17509
|
+
id: "n6+BBp",
|
|
17510
|
+
message: "Schema Write"
|
|
17511
|
+
},
|
|
17512
|
+
description: {
|
|
17513
|
+
id: "UgmJPq",
|
|
17514
|
+
message: "Modify collection schemas"
|
|
17515
|
+
}
|
|
17516
|
+
},
|
|
17517
|
+
{
|
|
17518
|
+
scope: API_TOKEN_SCOPES.Admin,
|
|
17519
|
+
label: {
|
|
17520
|
+
id: "U3pytU",
|
|
17521
|
+
message: "Admin"
|
|
17522
|
+
},
|
|
17523
|
+
description: {
|
|
17524
|
+
id: "5SaI4f",
|
|
17525
|
+
message: "Full admin access"
|
|
17526
|
+
}
|
|
17527
|
+
}
|
|
17528
|
+
];
|
|
17529
|
+
/** Wire scopes shown on the create-token form (contract-tested vs `API_TOKEN_SCOPES` and `@emdash-cms/auth`). */
|
|
17530
|
+
const API_TOKEN_SCOPE_FORM_SCOPES = API_TOKEN_SCOPE_VALUES.map((row) => row.scope);
|
|
16951
17531
|
function computeExpiryDate(option) {
|
|
16952
17532
|
if (option === "none") return void 0;
|
|
16953
17533
|
const days = parseInt(option, 10);
|
|
@@ -16957,6 +17537,7 @@ function computeExpiryDate(option) {
|
|
|
16957
17537
|
return date.toISOString();
|
|
16958
17538
|
}
|
|
16959
17539
|
function ApiTokenSettings() {
|
|
17540
|
+
const { _: _t } = useLingui();
|
|
16960
17541
|
const queryClient = useQueryClient();
|
|
16961
17542
|
const [showCreateForm, setShowCreateForm] = React.useState(false);
|
|
16962
17543
|
const [newToken, setNewToken] = React.useState(null);
|
|
@@ -16998,6 +17579,7 @@ function ApiTokenSettings() {
|
|
|
16998
17579
|
copyTimeoutRef.current = setTimeout(setCopied, 2e3, false);
|
|
16999
17580
|
} catch {}
|
|
17000
17581
|
};
|
|
17582
|
+
const expirySelectItems = React.useMemo(() => Object.fromEntries(EXPIRY_OPTIONS.map((o) => [o.value, _t(o.label)])), [_t]);
|
|
17001
17583
|
return /* @__PURE__ */ jsxs("div", {
|
|
17002
17584
|
className: "space-y-6",
|
|
17003
17585
|
children: [
|
|
@@ -17008,15 +17590,24 @@ function ApiTokenSettings() {
|
|
|
17008
17590
|
children: /* @__PURE__ */ jsx(Button, {
|
|
17009
17591
|
variant: "ghost",
|
|
17010
17592
|
shape: "square",
|
|
17011
|
-
"aria-label":
|
|
17593
|
+
"aria-label": _t({
|
|
17594
|
+
id: "9aZHfH",
|
|
17595
|
+
message: "Back to settings"
|
|
17596
|
+
}),
|
|
17012
17597
|
children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" })
|
|
17013
17598
|
})
|
|
17014
17599
|
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h1", {
|
|
17015
17600
|
className: "text-2xl font-bold",
|
|
17016
|
-
children:
|
|
17601
|
+
children: _t({
|
|
17602
|
+
id: "ZiooJI",
|
|
17603
|
+
message: "API Tokens"
|
|
17604
|
+
})
|
|
17017
17605
|
}), /* @__PURE__ */ jsx("p", {
|
|
17018
17606
|
className: "text-sm text-kumo-subtle",
|
|
17019
|
-
children:
|
|
17607
|
+
children: _t({
|
|
17608
|
+
id: "dhH+RW",
|
|
17609
|
+
message: "Create personal access tokens for programmatic API access"
|
|
17610
|
+
})
|
|
17020
17611
|
})] })]
|
|
17021
17612
|
}),
|
|
17022
17613
|
newToken && /* @__PURE__ */ jsx("div", {
|
|
@@ -17028,13 +17619,20 @@ function ApiTokenSettings() {
|
|
|
17028
17619
|
/* @__PURE__ */ jsxs("div", {
|
|
17029
17620
|
className: "flex-1 min-w-0",
|
|
17030
17621
|
children: [
|
|
17031
|
-
/* @__PURE__ */
|
|
17622
|
+
/* @__PURE__ */ jsx("p", {
|
|
17032
17623
|
className: "font-medium text-green-800 dark:text-green-200",
|
|
17033
|
-
children:
|
|
17624
|
+
children: _t({
|
|
17625
|
+
id: "eoLxnB",
|
|
17626
|
+
message: "Token created: {0}",
|
|
17627
|
+
values: { 0: newToken.info.name }
|
|
17628
|
+
})
|
|
17034
17629
|
}),
|
|
17035
17630
|
/* @__PURE__ */ jsx("p", {
|
|
17036
17631
|
className: "text-sm text-green-700 dark:text-green-300 mt-1",
|
|
17037
|
-
children:
|
|
17632
|
+
children: _t({
|
|
17633
|
+
id: "DyPcUA",
|
|
17634
|
+
message: "Copy this token now — it won't be shown again."
|
|
17635
|
+
})
|
|
17038
17636
|
}),
|
|
17039
17637
|
/* @__PURE__ */ jsxs("div", {
|
|
17040
17638
|
className: "mt-3 flex items-center gap-2",
|
|
@@ -17047,21 +17645,33 @@ function ApiTokenSettings() {
|
|
|
17047
17645
|
variant: "ghost",
|
|
17048
17646
|
shape: "square",
|
|
17049
17647
|
onClick: () => setTokenVisible(!tokenVisible),
|
|
17050
|
-
"aria-label": tokenVisible ?
|
|
17648
|
+
"aria-label": tokenVisible ? _t({
|
|
17649
|
+
id: "NEZFJN",
|
|
17650
|
+
message: "Hide token"
|
|
17651
|
+
}) : _t({
|
|
17652
|
+
id: "10eUfR",
|
|
17653
|
+
message: "Show token"
|
|
17654
|
+
}),
|
|
17051
17655
|
children: tokenVisible ? /* @__PURE__ */ jsx(EyeSlash, {}) : /* @__PURE__ */ jsx(Eye, {})
|
|
17052
17656
|
}),
|
|
17053
17657
|
/* @__PURE__ */ jsx(Button, {
|
|
17054
17658
|
variant: "ghost",
|
|
17055
17659
|
shape: "square",
|
|
17056
17660
|
onClick: handleCopyToken,
|
|
17057
|
-
"aria-label":
|
|
17661
|
+
"aria-label": _t({
|
|
17662
|
+
id: "BddwrJ",
|
|
17663
|
+
message: "Copy token"
|
|
17664
|
+
}),
|
|
17058
17665
|
children: /* @__PURE__ */ jsx(Copy, {})
|
|
17059
17666
|
})
|
|
17060
17667
|
]
|
|
17061
17668
|
}),
|
|
17062
17669
|
copied && /* @__PURE__ */ jsx("p", {
|
|
17063
17670
|
className: "text-xs text-green-600 dark:text-green-400 mt-1",
|
|
17064
|
-
children:
|
|
17671
|
+
children: _t({
|
|
17672
|
+
id: "FxVG/l",
|
|
17673
|
+
message: "Copied to clipboard"
|
|
17674
|
+
})
|
|
17065
17675
|
})
|
|
17066
17676
|
]
|
|
17067
17677
|
}),
|
|
@@ -17069,13 +17679,20 @@ function ApiTokenSettings() {
|
|
|
17069
17679
|
variant: "ghost",
|
|
17070
17680
|
size: "sm",
|
|
17071
17681
|
onClick: () => setNewToken(null),
|
|
17072
|
-
"aria-label":
|
|
17073
|
-
|
|
17682
|
+
"aria-label": _t({
|
|
17683
|
+
id: "1QfxQT",
|
|
17684
|
+
message: "Dismiss"
|
|
17685
|
+
}),
|
|
17686
|
+
children: _t({
|
|
17687
|
+
id: "1QfxQT",
|
|
17688
|
+
message: "Dismiss"
|
|
17689
|
+
})
|
|
17074
17690
|
})
|
|
17075
17691
|
]
|
|
17076
17692
|
})
|
|
17077
17693
|
}),
|
|
17078
17694
|
showCreateForm ? /* @__PURE__ */ jsx(CreateTokenForm, {
|
|
17695
|
+
expirySelectItems,
|
|
17079
17696
|
isCreating: createMutation.isPending,
|
|
17080
17697
|
error: createMutation.error?.message ?? null,
|
|
17081
17698
|
onSubmit: (input) => createMutation.mutate({
|
|
@@ -17087,7 +17704,10 @@ function ApiTokenSettings() {
|
|
|
17087
17704
|
}) : /* @__PURE__ */ jsx(Button, {
|
|
17088
17705
|
icon: /* @__PURE__ */ jsx(Plus, {}),
|
|
17089
17706
|
onClick: () => setShowCreateForm(true),
|
|
17090
|
-
children:
|
|
17707
|
+
children: _t({
|
|
17708
|
+
id: "JkdaXO",
|
|
17709
|
+
message: "Create Token"
|
|
17710
|
+
})
|
|
17091
17711
|
}),
|
|
17092
17712
|
/* @__PURE__ */ jsx("div", {
|
|
17093
17713
|
className: "rounded-lg border bg-kumo-base",
|
|
@@ -17096,7 +17716,10 @@ function ApiTokenSettings() {
|
|
|
17096
17716
|
children: /* @__PURE__ */ jsx(Loader, {})
|
|
17097
17717
|
}) : !tokens || tokens.length === 0 ? /* @__PURE__ */ jsx("div", {
|
|
17098
17718
|
className: "py-8 text-center text-sm text-kumo-subtle",
|
|
17099
|
-
children:
|
|
17719
|
+
children: _t({
|
|
17720
|
+
id: "aio6Hc",
|
|
17721
|
+
message: "No API tokens yet. Create one to get started."
|
|
17722
|
+
})
|
|
17100
17723
|
}) : /* @__PURE__ */ jsx("div", {
|
|
17101
17724
|
className: "divide-y",
|
|
17102
17725
|
children: tokens.map((token) => /* @__PURE__ */ jsxs("div", {
|
|
@@ -17117,14 +17740,30 @@ function ApiTokenSettings() {
|
|
|
17117
17740
|
/* @__PURE__ */ jsxs("div", {
|
|
17118
17741
|
className: "flex gap-3 mt-1 text-xs text-kumo-subtle",
|
|
17119
17742
|
children: [
|
|
17120
|
-
/* @__PURE__ */
|
|
17121
|
-
|
|
17122
|
-
|
|
17743
|
+
/* @__PURE__ */ jsx("span", { children: _t({
|
|
17744
|
+
id: "NSzA6n",
|
|
17745
|
+
message: "Scopes: {0}",
|
|
17746
|
+
values: { 0: token.scopes.join(", ") }
|
|
17747
|
+
}) }),
|
|
17748
|
+
token.expiresAt && /* @__PURE__ */ jsx("span", { children: _t({
|
|
17749
|
+
id: "oOfJ56",
|
|
17750
|
+
message: "Expires {0}",
|
|
17751
|
+
values: { 0: new Date(token.expiresAt).toLocaleDateString() }
|
|
17752
|
+
}) }),
|
|
17753
|
+
token.lastUsedAt && /* @__PURE__ */ jsx("span", { children: _t({
|
|
17754
|
+
id: "ylo1I0",
|
|
17755
|
+
message: "Last used {0}",
|
|
17756
|
+
values: { 0: new Date(token.lastUsedAt).toLocaleDateString() }
|
|
17757
|
+
}) })
|
|
17123
17758
|
]
|
|
17124
17759
|
}),
|
|
17125
|
-
/* @__PURE__ */
|
|
17760
|
+
/* @__PURE__ */ jsx("div", {
|
|
17126
17761
|
className: "text-xs text-kumo-subtle mt-0.5",
|
|
17127
|
-
children:
|
|
17762
|
+
children: _t({
|
|
17763
|
+
id: "MXSt4t",
|
|
17764
|
+
message: "Created {0}",
|
|
17765
|
+
values: { 0: new Date(token.createdAt).toLocaleDateString() }
|
|
17766
|
+
})
|
|
17128
17767
|
})
|
|
17129
17768
|
]
|
|
17130
17769
|
}), revokeConfirmId === token.id ? /* @__PURE__ */ jsxs("div", {
|
|
@@ -17136,14 +17775,23 @@ function ApiTokenSettings() {
|
|
|
17136
17775
|
}),
|
|
17137
17776
|
/* @__PURE__ */ jsx("span", {
|
|
17138
17777
|
className: "text-sm text-kumo-danger",
|
|
17139
|
-
children:
|
|
17778
|
+
children: _t({
|
|
17779
|
+
id: "U4/l0o",
|
|
17780
|
+
message: "Revoke?"
|
|
17781
|
+
})
|
|
17140
17782
|
}),
|
|
17141
17783
|
/* @__PURE__ */ jsx(Button, {
|
|
17142
17784
|
variant: "destructive",
|
|
17143
17785
|
size: "sm",
|
|
17144
17786
|
disabled: revokeMutation.isPending,
|
|
17145
17787
|
onClick: () => revokeMutation.mutate(token.id),
|
|
17146
|
-
children: revokeMutation.isPending ?
|
|
17788
|
+
children: revokeMutation.isPending ? _t({
|
|
17789
|
+
id: "zzTOEt",
|
|
17790
|
+
message: "Revoking..."
|
|
17791
|
+
}) : _t({
|
|
17792
|
+
id: "7VpPHA",
|
|
17793
|
+
message: "Confirm"
|
|
17794
|
+
})
|
|
17147
17795
|
}),
|
|
17148
17796
|
/* @__PURE__ */ jsx(Button, {
|
|
17149
17797
|
variant: "outline",
|
|
@@ -17152,14 +17800,20 @@ function ApiTokenSettings() {
|
|
|
17152
17800
|
setRevokeConfirmId(null);
|
|
17153
17801
|
revokeMutation.reset();
|
|
17154
17802
|
},
|
|
17155
|
-
children:
|
|
17803
|
+
children: _t({
|
|
17804
|
+
id: "dEgA5A",
|
|
17805
|
+
message: "Cancel"
|
|
17806
|
+
})
|
|
17156
17807
|
})
|
|
17157
17808
|
]
|
|
17158
17809
|
}) : /* @__PURE__ */ jsx(Button, {
|
|
17159
17810
|
variant: "ghost",
|
|
17160
17811
|
shape: "square",
|
|
17161
17812
|
onClick: () => setRevokeConfirmId(token.id),
|
|
17162
|
-
"aria-label":
|
|
17813
|
+
"aria-label": _t({
|
|
17814
|
+
id: "7/ePoE",
|
|
17815
|
+
message: "Revoke token"
|
|
17816
|
+
}),
|
|
17163
17817
|
children: /* @__PURE__ */ jsx(Trash, { className: "h-4 w-4 text-kumo-subtle hover:text-kumo-danger" })
|
|
17164
17818
|
})]
|
|
17165
17819
|
}, token.id))
|
|
@@ -17168,7 +17822,8 @@ function ApiTokenSettings() {
|
|
|
17168
17822
|
]
|
|
17169
17823
|
});
|
|
17170
17824
|
}
|
|
17171
|
-
function CreateTokenForm({ isCreating, error, onSubmit, onCancel }) {
|
|
17825
|
+
function CreateTokenForm({ expirySelectItems, isCreating, error, onSubmit, onCancel }) {
|
|
17826
|
+
const { _: _t2 } = useLingui();
|
|
17172
17827
|
const [name, setName] = React.useState("");
|
|
17173
17828
|
const [selectedScopes, setSelectedScopes] = React.useState(/* @__PURE__ */ new Set());
|
|
17174
17829
|
const [expiry, setExpiry] = React.useState("30d");
|
|
@@ -17194,7 +17849,10 @@ function CreateTokenForm({ isCreating, error, onSubmit, onCancel }) {
|
|
|
17194
17849
|
children: [
|
|
17195
17850
|
/* @__PURE__ */ jsx("h2", {
|
|
17196
17851
|
className: "text-lg font-semibold mb-4",
|
|
17197
|
-
children:
|
|
17852
|
+
children: _t2({
|
|
17853
|
+
id: "IBeakM",
|
|
17854
|
+
message: "Create New Token"
|
|
17855
|
+
})
|
|
17198
17856
|
}),
|
|
17199
17857
|
error && /* @__PURE__ */ jsxs("div", {
|
|
17200
17858
|
className: "mb-4 rounded-lg border border-kumo-danger/50 bg-kumo-danger/10 p-3 flex items-center gap-2 text-sm text-kumo-danger",
|
|
@@ -17205,40 +17863,54 @@ function CreateTokenForm({ isCreating, error, onSubmit, onCancel }) {
|
|
|
17205
17863
|
className: "space-y-4",
|
|
17206
17864
|
children: [
|
|
17207
17865
|
/* @__PURE__ */ jsx(Input, {
|
|
17208
|
-
label:
|
|
17866
|
+
label: _t2({
|
|
17867
|
+
id: "jJrqb1",
|
|
17868
|
+
message: "Token Name"
|
|
17869
|
+
}),
|
|
17209
17870
|
value: name,
|
|
17210
17871
|
onChange: (e) => setName(e.target.value),
|
|
17211
|
-
placeholder:
|
|
17872
|
+
placeholder: _t2({
|
|
17873
|
+
id: "O1SmJ+",
|
|
17874
|
+
message: "e.g., CI/CD Pipeline"
|
|
17875
|
+
}),
|
|
17212
17876
|
required: true,
|
|
17213
17877
|
autoFocus: true
|
|
17214
17878
|
}),
|
|
17215
17879
|
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
17216
17880
|
className: "text-sm font-medium mb-2",
|
|
17217
|
-
children:
|
|
17881
|
+
children: _t2({
|
|
17882
|
+
id: "N/rFzD",
|
|
17883
|
+
message: "Scopes"
|
|
17884
|
+
})
|
|
17218
17885
|
}), /* @__PURE__ */ jsx("div", {
|
|
17219
17886
|
className: "space-y-2",
|
|
17220
|
-
children:
|
|
17221
|
-
|
|
17222
|
-
|
|
17223
|
-
|
|
17224
|
-
|
|
17225
|
-
|
|
17226
|
-
|
|
17227
|
-
|
|
17228
|
-
|
|
17229
|
-
|
|
17230
|
-
|
|
17231
|
-
|
|
17232
|
-
|
|
17887
|
+
children: API_TOKEN_SCOPE_VALUES.map(({ scope, label, description }) => {
|
|
17888
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
17889
|
+
className: "flex items-start gap-2 cursor-pointer",
|
|
17890
|
+
children: [/* @__PURE__ */ jsx(Checkbox, {
|
|
17891
|
+
checked: selectedScopes.has(scope),
|
|
17892
|
+
onCheckedChange: () => toggleScope(scope)
|
|
17893
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
17894
|
+
className: "text-sm font-medium",
|
|
17895
|
+
children: _t2(label)
|
|
17896
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
17897
|
+
className: "text-xs text-kumo-subtle",
|
|
17898
|
+
children: _t2(description)
|
|
17899
|
+
})] })]
|
|
17900
|
+
}, scope);
|
|
17901
|
+
})
|
|
17233
17902
|
})] }),
|
|
17234
17903
|
/* @__PURE__ */ jsx(Select, {
|
|
17235
|
-
label:
|
|
17904
|
+
label: _t2({
|
|
17905
|
+
id: "agO/T/",
|
|
17906
|
+
message: "Expiry"
|
|
17907
|
+
}),
|
|
17236
17908
|
value: expiry,
|
|
17237
17909
|
onValueChange: (v) => v !== null && setExpiry(v),
|
|
17238
|
-
items:
|
|
17910
|
+
items: expirySelectItems,
|
|
17239
17911
|
children: EXPIRY_OPTIONS.map((option) => /* @__PURE__ */ jsx(Select.Option, {
|
|
17240
17912
|
value: option.value,
|
|
17241
|
-
children: option.label
|
|
17913
|
+
children: _t2(option.label)
|
|
17242
17914
|
}, option.value))
|
|
17243
17915
|
}),
|
|
17244
17916
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -17246,12 +17918,21 @@ function CreateTokenForm({ isCreating, error, onSubmit, onCancel }) {
|
|
|
17246
17918
|
children: [/* @__PURE__ */ jsx(Button, {
|
|
17247
17919
|
type: "submit",
|
|
17248
17920
|
disabled: !isValid || isCreating,
|
|
17249
|
-
children: isCreating ?
|
|
17921
|
+
children: isCreating ? _t2({
|
|
17922
|
+
id: "HM56Bx",
|
|
17923
|
+
message: "Creating..."
|
|
17924
|
+
}) : _t2({
|
|
17925
|
+
id: "JkdaXO",
|
|
17926
|
+
message: "Create Token"
|
|
17927
|
+
})
|
|
17250
17928
|
}), /* @__PURE__ */ jsx(Button, {
|
|
17251
17929
|
type: "button",
|
|
17252
17930
|
variant: "outline",
|
|
17253
17931
|
onClick: onCancel,
|
|
17254
|
-
children:
|
|
17932
|
+
children: _t2({
|
|
17933
|
+
id: "dEgA5A",
|
|
17934
|
+
message: "Cancel"
|
|
17935
|
+
})
|
|
17255
17936
|
})]
|
|
17256
17937
|
})
|
|
17257
17938
|
]
|
|
@@ -17276,7 +17957,7 @@ function EmailSettings() {
|
|
|
17276
17957
|
const timer = setTimeout(setStatus, 5e3, null);
|
|
17277
17958
|
return () => clearTimeout(timer);
|
|
17278
17959
|
}, [status]);
|
|
17279
|
-
const { data: settings, isLoading } = useQuery({
|
|
17960
|
+
const { data: settings, isLoading, error: fetchError } = useQuery({
|
|
17280
17961
|
queryKey: ["email-settings"],
|
|
17281
17962
|
queryFn: fetchEmailSettings
|
|
17282
17963
|
});
|
|
@@ -17305,6 +17986,27 @@ function EmailSettings() {
|
|
|
17305
17986
|
className: "flex items-center justify-center py-12",
|
|
17306
17987
|
children: /* @__PURE__ */ jsx(Loader, { size: "lg" })
|
|
17307
17988
|
});
|
|
17989
|
+
if (fetchError) return /* @__PURE__ */ jsxs("div", {
|
|
17990
|
+
className: "space-y-6",
|
|
17991
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
17992
|
+
className: "flex items-center gap-3",
|
|
17993
|
+
children: [/* @__PURE__ */ jsx(Link$1, {
|
|
17994
|
+
to: "/settings",
|
|
17995
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
17996
|
+
variant: "ghost",
|
|
17997
|
+
shape: "square",
|
|
17998
|
+
"aria-label": "Back to settings",
|
|
17999
|
+
children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" })
|
|
18000
|
+
})
|
|
18001
|
+
}), /* @__PURE__ */ jsx("h1", {
|
|
18002
|
+
className: "text-2xl font-bold",
|
|
18003
|
+
children: "Email Settings"
|
|
18004
|
+
})]
|
|
18005
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
18006
|
+
className: "flex items-center gap-2 rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-800 dark:border-red-800 dark:bg-red-950/30 dark:text-red-200",
|
|
18007
|
+
children: [/* @__PURE__ */ jsx(WarningCircle, { className: "h-4 w-4 flex-shrink-0" }), getMutationError(fetchError) || "Failed to load email settings"]
|
|
18008
|
+
})]
|
|
18009
|
+
});
|
|
17308
18010
|
return /* @__PURE__ */ jsxs("div", {
|
|
17309
18011
|
className: "space-y-6",
|
|
17310
18012
|
children: [
|
|
@@ -19123,7 +19825,10 @@ async function searchContent(query) {
|
|
|
19123
19825
|
function buildNavItems(manifest, userRole) {
|
|
19124
19826
|
const items = [{
|
|
19125
19827
|
id: "dashboard",
|
|
19126
|
-
title:
|
|
19828
|
+
title: {
|
|
19829
|
+
id: "7p5kLi",
|
|
19830
|
+
message: "Dashboard"
|
|
19831
|
+
},
|
|
19127
19832
|
to: "/",
|
|
19128
19833
|
icon: SquaresFour,
|
|
19129
19834
|
keywords: ["home", "overview"]
|
|
@@ -19138,7 +19843,10 @@ function buildNavItems(manifest, userRole) {
|
|
|
19138
19843
|
});
|
|
19139
19844
|
items.push({
|
|
19140
19845
|
id: "media",
|
|
19141
|
-
title:
|
|
19846
|
+
title: {
|
|
19847
|
+
id: "ia4TsE",
|
|
19848
|
+
message: "Media Library"
|
|
19849
|
+
},
|
|
19142
19850
|
to: "/media",
|
|
19143
19851
|
icon: Image$1,
|
|
19144
19852
|
keywords: [
|
|
@@ -19148,35 +19856,50 @@ function buildNavItems(manifest, userRole) {
|
|
|
19148
19856
|
]
|
|
19149
19857
|
}, {
|
|
19150
19858
|
id: "menus",
|
|
19151
|
-
title:
|
|
19859
|
+
title: {
|
|
19860
|
+
id: "NXjnVQ",
|
|
19861
|
+
message: "Menus"
|
|
19862
|
+
},
|
|
19152
19863
|
to: "/menus",
|
|
19153
19864
|
icon: List,
|
|
19154
19865
|
minRole: ROLE_EDITOR$2,
|
|
19155
19866
|
keywords: ["navigation"]
|
|
19156
19867
|
}, {
|
|
19157
19868
|
id: "widgets",
|
|
19158
|
-
title:
|
|
19869
|
+
title: {
|
|
19870
|
+
id: "tL6W2K",
|
|
19871
|
+
message: "Widgets"
|
|
19872
|
+
},
|
|
19159
19873
|
to: "/widgets",
|
|
19160
19874
|
icon: GridFour,
|
|
19161
19875
|
minRole: ROLE_EDITOR$2,
|
|
19162
19876
|
keywords: ["sidebar", "footer"]
|
|
19163
19877
|
}, {
|
|
19164
19878
|
id: "sections",
|
|
19165
|
-
title:
|
|
19879
|
+
title: {
|
|
19880
|
+
id: "R4OWFD",
|
|
19881
|
+
message: "Sections"
|
|
19882
|
+
},
|
|
19166
19883
|
to: "/sections",
|
|
19167
19884
|
icon: Stack,
|
|
19168
19885
|
minRole: ROLE_EDITOR$2,
|
|
19169
19886
|
keywords: ["page builder", "blocks"]
|
|
19170
19887
|
}, {
|
|
19171
19888
|
id: "content-types",
|
|
19172
|
-
title:
|
|
19889
|
+
title: {
|
|
19890
|
+
id: "F7Jcuy",
|
|
19891
|
+
message: "Content Types"
|
|
19892
|
+
},
|
|
19173
19893
|
to: "/content-types",
|
|
19174
19894
|
icon: Database,
|
|
19175
19895
|
minRole: ROLE_ADMIN$2,
|
|
19176
19896
|
keywords: ["schema", "collections"]
|
|
19177
19897
|
}, {
|
|
19178
19898
|
id: "categories",
|
|
19179
|
-
title:
|
|
19899
|
+
title: {
|
|
19900
|
+
id: "NUrY9o",
|
|
19901
|
+
message: "Categories"
|
|
19902
|
+
},
|
|
19180
19903
|
to: "/taxonomies/$taxonomy",
|
|
19181
19904
|
params: { taxonomy: "category" },
|
|
19182
19905
|
icon: FileText,
|
|
@@ -19184,7 +19907,10 @@ function buildNavItems(manifest, userRole) {
|
|
|
19184
19907
|
keywords: ["taxonomy"]
|
|
19185
19908
|
}, {
|
|
19186
19909
|
id: "tags",
|
|
19187
|
-
title:
|
|
19910
|
+
title: {
|
|
19911
|
+
id: "OYHzN1",
|
|
19912
|
+
message: "Tags"
|
|
19913
|
+
},
|
|
19188
19914
|
to: "/taxonomies/$taxonomy",
|
|
19189
19915
|
params: { taxonomy: "tag" },
|
|
19190
19916
|
icon: FileText,
|
|
@@ -19192,35 +19918,50 @@ function buildNavItems(manifest, userRole) {
|
|
|
19192
19918
|
keywords: ["taxonomy"]
|
|
19193
19919
|
}, {
|
|
19194
19920
|
id: "users",
|
|
19195
|
-
title:
|
|
19921
|
+
title: {
|
|
19922
|
+
id: "Sxm8rQ",
|
|
19923
|
+
message: "Users"
|
|
19924
|
+
},
|
|
19196
19925
|
to: "/users",
|
|
19197
19926
|
icon: Users,
|
|
19198
19927
|
minRole: ROLE_ADMIN$2,
|
|
19199
19928
|
keywords: ["accounts", "team"]
|
|
19200
19929
|
}, {
|
|
19201
19930
|
id: "plugins",
|
|
19202
|
-
title:
|
|
19931
|
+
title: {
|
|
19932
|
+
id: "ohUJJM",
|
|
19933
|
+
message: "Plugins"
|
|
19934
|
+
},
|
|
19203
19935
|
to: "/plugins-manager",
|
|
19204
19936
|
icon: PuzzlePiece,
|
|
19205
19937
|
minRole: ROLE_ADMIN$2,
|
|
19206
19938
|
keywords: ["extensions", "add-ons"]
|
|
19207
19939
|
}, {
|
|
19208
19940
|
id: "import",
|
|
19209
|
-
title:
|
|
19941
|
+
title: {
|
|
19942
|
+
id: "l3s5ri",
|
|
19943
|
+
message: "Import"
|
|
19944
|
+
},
|
|
19210
19945
|
to: "/import/wordpress",
|
|
19211
19946
|
icon: Upload,
|
|
19212
19947
|
minRole: ROLE_ADMIN$2,
|
|
19213
19948
|
keywords: ["wordpress", "migrate"]
|
|
19214
19949
|
}, {
|
|
19215
19950
|
id: "settings",
|
|
19216
|
-
title:
|
|
19951
|
+
title: {
|
|
19952
|
+
id: "Tz0i8g",
|
|
19953
|
+
message: "Settings"
|
|
19954
|
+
},
|
|
19217
19955
|
to: "/settings",
|
|
19218
19956
|
icon: Gear,
|
|
19219
19957
|
minRole: ROLE_ADMIN$2,
|
|
19220
19958
|
keywords: ["configuration", "preferences"]
|
|
19221
19959
|
}, {
|
|
19222
19960
|
id: "security",
|
|
19223
|
-
title:
|
|
19961
|
+
title: {
|
|
19962
|
+
id: "zro6wS",
|
|
19963
|
+
message: "Security Settings"
|
|
19964
|
+
},
|
|
19224
19965
|
to: "/settings/security",
|
|
19225
19966
|
icon: Gear,
|
|
19226
19967
|
minRole: ROLE_ADMIN$2,
|
|
@@ -19241,16 +19982,17 @@ function buildNavItems(manifest, userRole) {
|
|
|
19241
19982
|
}
|
|
19242
19983
|
return items.filter((item) => !item.minRole || userRole >= item.minRole);
|
|
19243
19984
|
}
|
|
19244
|
-
function filterNavItems(items, query) {
|
|
19985
|
+
function filterNavItems(items, query, translate) {
|
|
19245
19986
|
if (!query) return items;
|
|
19246
19987
|
const lowerQuery = query.toLowerCase();
|
|
19247
19988
|
return items.filter((item) => {
|
|
19248
|
-
const titleMatch = item.title.toLowerCase().includes(lowerQuery);
|
|
19989
|
+
const titleMatch = (typeof item.title === "string" ? item.title : translate(item.title)).toLowerCase().includes(lowerQuery);
|
|
19249
19990
|
const keywordMatch = item.keywords?.some((k) => k.toLowerCase().includes(lowerQuery));
|
|
19250
19991
|
return titleMatch || keywordMatch;
|
|
19251
19992
|
});
|
|
19252
19993
|
}
|
|
19253
19994
|
function AdminCommandPalette({ manifest }) {
|
|
19995
|
+
const { _: _t } = useLingui();
|
|
19254
19996
|
const [open, setOpen] = React.useState(false);
|
|
19255
19997
|
const [query, setQuery] = React.useState("");
|
|
19256
19998
|
const navigate = useNavigate$1();
|
|
@@ -19265,14 +20007,22 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19265
20007
|
});
|
|
19266
20008
|
const isPendingSearch = query.length >= 2 && query !== debouncedQuery || isSearching;
|
|
19267
20009
|
const allNavItems = React.useMemo(() => buildNavItems(manifest, userRole), [manifest, userRole]);
|
|
19268
|
-
const filteredNavItems = React.useMemo(() => filterNavItems(allNavItems, query), [
|
|
20010
|
+
const filteredNavItems = React.useMemo(() => filterNavItems(allNavItems, query, _t), [
|
|
20011
|
+
allNavItems,
|
|
20012
|
+
query,
|
|
20013
|
+
_t
|
|
20014
|
+
]);
|
|
19269
20015
|
const resultGroups = React.useMemo(() => {
|
|
19270
20016
|
const groups = [];
|
|
19271
20017
|
if (filteredNavItems.length > 0) groups.push({
|
|
19272
|
-
|
|
20018
|
+
id: "navigation",
|
|
20019
|
+
label: {
|
|
20020
|
+
id: "UxKoFf",
|
|
20021
|
+
message: "Navigation"
|
|
20022
|
+
},
|
|
19273
20023
|
items: filteredNavItems.map((item) => ({
|
|
19274
20024
|
id: item.id,
|
|
19275
|
-
title: item.title,
|
|
20025
|
+
title: typeof item.title === "string" ? item.title : _t(item.title),
|
|
19276
20026
|
to: item.to,
|
|
19277
20027
|
params: item.params,
|
|
19278
20028
|
icon: /* @__PURE__ */ jsx(item.icon, { className: "h-4 w-4" })
|
|
@@ -19280,7 +20030,7 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19280
20030
|
});
|
|
19281
20031
|
if (searchResults?.items && searchResults.items.length > 0) {
|
|
19282
20032
|
const contentItems = searchResults.items.map((result) => {
|
|
19283
|
-
const
|
|
20033
|
+
const collectionLabel = manifest.collections[result.collection]?.label ?? result.collection;
|
|
19284
20034
|
return {
|
|
19285
20035
|
id: `content-${result.id}`,
|
|
19286
20036
|
title: result.title || result.slug,
|
|
@@ -19290,12 +20040,16 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19290
20040
|
id: result.id
|
|
19291
20041
|
},
|
|
19292
20042
|
icon: /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4" }),
|
|
19293
|
-
description:
|
|
20043
|
+
description: collectionLabel,
|
|
19294
20044
|
collection: result.collection
|
|
19295
20045
|
};
|
|
19296
20046
|
});
|
|
19297
20047
|
groups.push({
|
|
19298
|
-
|
|
20048
|
+
id: "content",
|
|
20049
|
+
label: {
|
|
20050
|
+
id: "4b3oEV",
|
|
20051
|
+
message: "Content"
|
|
20052
|
+
},
|
|
19299
20053
|
items: contentItems
|
|
19300
20054
|
});
|
|
19301
20055
|
}
|
|
@@ -19303,7 +20057,8 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19303
20057
|
}, [
|
|
19304
20058
|
filteredNavItems,
|
|
19305
20059
|
searchResults,
|
|
19306
|
-
manifest.collections
|
|
20060
|
+
manifest.collections,
|
|
20061
|
+
_t
|
|
19307
20062
|
]);
|
|
19308
20063
|
useHotkeys("mod+k", (e) => {
|
|
19309
20064
|
e.preventDefault();
|
|
@@ -19331,12 +20086,15 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19331
20086
|
items: resultGroups,
|
|
19332
20087
|
value: query,
|
|
19333
20088
|
onValueChange: setQuery,
|
|
19334
|
-
itemToStringValue: (group) => group.label,
|
|
20089
|
+
itemToStringValue: (group) => _t(group.label),
|
|
19335
20090
|
onSelect: handleSelect,
|
|
19336
20091
|
getSelectableItems: (groups) => groups.flatMap((g) => g.items),
|
|
19337
20092
|
children: [
|
|
19338
20093
|
/* @__PURE__ */ jsx(CommandPalette.Input, {
|
|
19339
|
-
placeholder:
|
|
20094
|
+
placeholder: _t({
|
|
20095
|
+
id: "z/bggT",
|
|
20096
|
+
message: "Search pages and content..."
|
|
20097
|
+
}),
|
|
19340
20098
|
leading: /* @__PURE__ */ jsx(MagnifyingGlass, {
|
|
19341
20099
|
className: "h-4 w-4 text-kumo-subtle",
|
|
19342
20100
|
weight: "bold"
|
|
@@ -19344,14 +20102,17 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19344
20102
|
}),
|
|
19345
20103
|
/* @__PURE__ */ jsx(CommandPalette.List, { children: isPendingSearch ? /* @__PURE__ */ jsx(CommandPalette.Loading, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(CommandPalette.Results, { children: (group) => /* @__PURE__ */ jsxs(CommandPalette.Group, {
|
|
19346
20104
|
items: group.items,
|
|
19347
|
-
children: [/* @__PURE__ */ jsx(CommandPalette.GroupLabel, { children: group.label }), /* @__PURE__ */ jsx(CommandPalette.Items, { children: (item) => /* @__PURE__ */ jsx(CommandPalette.ResultItem, {
|
|
20105
|
+
children: [/* @__PURE__ */ jsx(CommandPalette.GroupLabel, { children: _t(group.label) }), /* @__PURE__ */ jsx(CommandPalette.Items, { children: (item) => /* @__PURE__ */ jsx(CommandPalette.ResultItem, {
|
|
19348
20106
|
value: item,
|
|
19349
20107
|
title: item.title,
|
|
19350
20108
|
description: item.description,
|
|
19351
20109
|
icon: item.icon,
|
|
19352
20110
|
onClick: (e) => handleItemClick(item, e)
|
|
19353
20111
|
}, item.id) })]
|
|
19354
|
-
}, group.
|
|
20112
|
+
}, group.id) }), /* @__PURE__ */ jsx(CommandPalette.Empty, { children: _t({
|
|
20113
|
+
id: "AxPAXW",
|
|
20114
|
+
message: "No results found"
|
|
20115
|
+
}) })] }) }),
|
|
19355
20116
|
/* @__PURE__ */ jsx(CommandPalette.Footer, { children: /* @__PURE__ */ jsxs("div", {
|
|
19356
20117
|
className: "flex items-center gap-4 text-kumo-subtle",
|
|
19357
20118
|
children: [
|
|
@@ -19360,21 +20121,30 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19360
20121
|
children: [/* @__PURE__ */ jsx("kbd", {
|
|
19361
20122
|
className: "rounded bg-kumo-control px-1.5 py-0.5 text-xs",
|
|
19362
20123
|
children: "Enter"
|
|
19363
|
-
}), /* @__PURE__ */ jsx("span", { children:
|
|
20124
|
+
}), /* @__PURE__ */ jsx("span", { children: _t({
|
|
20125
|
+
id: "jpBN9M",
|
|
20126
|
+
message: "to select"
|
|
20127
|
+
}) })]
|
|
19364
20128
|
}),
|
|
19365
20129
|
/* @__PURE__ */ jsxs("span", {
|
|
19366
20130
|
className: "flex items-center gap-1",
|
|
19367
20131
|
children: [/* @__PURE__ */ jsxs("kbd", {
|
|
19368
20132
|
className: "rounded bg-kumo-control px-1.5 py-0.5 text-xs",
|
|
19369
20133
|
children: [IS_MAC ? "Cmd" : "Ctrl", "+Enter"]
|
|
19370
|
-
}), /* @__PURE__ */ jsx("span", { children:
|
|
20134
|
+
}), /* @__PURE__ */ jsx("span", { children: _t({
|
|
20135
|
+
id: "k2rZ7L",
|
|
20136
|
+
message: "new tab"
|
|
20137
|
+
}) })]
|
|
19371
20138
|
}),
|
|
19372
20139
|
/* @__PURE__ */ jsxs("span", {
|
|
19373
20140
|
className: "flex items-center gap-1",
|
|
19374
20141
|
children: [/* @__PURE__ */ jsx("kbd", {
|
|
19375
20142
|
className: "rounded bg-kumo-control px-1.5 py-0.5 text-xs",
|
|
19376
20143
|
children: "Esc"
|
|
19377
|
-
}), /* @__PURE__ */ jsx("span", { children:
|
|
20144
|
+
}), /* @__PURE__ */ jsx("span", { children: _t({
|
|
20145
|
+
id: "UbVgIu",
|
|
20146
|
+
message: "to close"
|
|
20147
|
+
}) })]
|
|
19378
20148
|
})
|
|
19379
20149
|
]
|
|
19380
20150
|
}) })
|
|
@@ -19489,20 +20259,13 @@ function SidebarNav({ manifest }) {
|
|
|
19489
20259
|
icon: Stack,
|
|
19490
20260
|
minRole: ROLE_EDITOR$1
|
|
19491
20261
|
},
|
|
19492
|
-
{
|
|
19493
|
-
to: "/taxonomies/$taxonomy",
|
|
19494
|
-
label: "Categories",
|
|
19495
|
-
icon: FileText,
|
|
19496
|
-
params: { taxonomy: "category" },
|
|
19497
|
-
minRole: ROLE_EDITOR$1
|
|
19498
|
-
},
|
|
19499
|
-
{
|
|
20262
|
+
...manifest.taxonomies.map((tax) => ({
|
|
19500
20263
|
to: "/taxonomies/$taxonomy",
|
|
19501
|
-
label:
|
|
20264
|
+
label: tax.label,
|
|
19502
20265
|
icon: FileText,
|
|
19503
|
-
params: { taxonomy:
|
|
20266
|
+
params: { taxonomy: tax.name },
|
|
19504
20267
|
minRole: ROLE_EDITOR$1
|
|
19505
|
-
},
|
|
20268
|
+
})),
|
|
19506
20269
|
{
|
|
19507
20270
|
to: "/bylines",
|
|
19508
20271
|
label: "Bylines",
|
|
@@ -19710,7 +20473,11 @@ function SidebarNav({ manifest }) {
|
|
|
19710
20473
|
] }),
|
|
19711
20474
|
/* @__PURE__ */ jsx(KumoSidebar.Footer, { children: /* @__PURE__ */ jsxs("p", {
|
|
19712
20475
|
className: "emdash-nav-label px-3 py-2 text-[11px] text-white/30",
|
|
19713
|
-
children: [
|
|
20476
|
+
children: [
|
|
20477
|
+
"EmDash CMS v",
|
|
20478
|
+
manifest.version || "0.0.0",
|
|
20479
|
+
manifest.commit && ` (${manifest.commit})`
|
|
20480
|
+
]
|
|
19714
20481
|
}) })
|
|
19715
20482
|
]
|
|
19716
20483
|
})] });
|
|
@@ -19851,13 +20618,71 @@ function Header() {
|
|
|
19851
20618
|
*
|
|
19852
20619
|
* Shown to new users on their first login to welcome them to EmDash.
|
|
19853
20620
|
*/
|
|
19854
|
-
|
|
19855
|
-
|
|
19856
|
-
|
|
19857
|
-
|
|
19858
|
-
|
|
19859
|
-
|
|
19860
|
-
|
|
20621
|
+
const MSG_ROLE_ADMINISTRATOR = {
|
|
20622
|
+
id: "Faptqt",
|
|
20623
|
+
message: "Administrator"
|
|
20624
|
+
};
|
|
20625
|
+
const MSG_ROLE_EDITOR = {
|
|
20626
|
+
id: "uBAxNB",
|
|
20627
|
+
message: "Editor"
|
|
20628
|
+
};
|
|
20629
|
+
const MSG_ROLE_AUTHOR = {
|
|
20630
|
+
id: "VbeIOx",
|
|
20631
|
+
message: "Author"
|
|
20632
|
+
};
|
|
20633
|
+
const MSG_ROLE_CONTRIBUTOR = {
|
|
20634
|
+
id: "3L51iw",
|
|
20635
|
+
message: "Contributor"
|
|
20636
|
+
};
|
|
20637
|
+
const MSG_ROLE_SUBSCRIBER = {
|
|
20638
|
+
id: "M2vfqB",
|
|
20639
|
+
message: "Subscriber"
|
|
20640
|
+
};
|
|
20641
|
+
function roleDescriptor(role) {
|
|
20642
|
+
if (role >= 50) return MSG_ROLE_ADMINISTRATOR;
|
|
20643
|
+
if (role >= 40) return MSG_ROLE_EDITOR;
|
|
20644
|
+
if (role >= 30) return MSG_ROLE_AUTHOR;
|
|
20645
|
+
if (role >= 20) return MSG_ROLE_CONTRIBUTOR;
|
|
20646
|
+
return MSG_ROLE_SUBSCRIBER;
|
|
20647
|
+
}
|
|
20648
|
+
const MSG_ACCOUNT_CREATED = {
|
|
20649
|
+
id: "ATCJJC",
|
|
20650
|
+
message: "Your account has been created successfully."
|
|
20651
|
+
};
|
|
20652
|
+
const MSG_YOUR_ROLE = {
|
|
20653
|
+
id: "T25KCz",
|
|
20654
|
+
message: "Your Role"
|
|
20655
|
+
};
|
|
20656
|
+
const MSG_SCOPE_ADMIN = {
|
|
20657
|
+
id: "T8yDG9",
|
|
20658
|
+
message: "You have full access to manage this site, including users, settings, and all content."
|
|
20659
|
+
};
|
|
20660
|
+
const MSG_SCOPE_EDITOR = {
|
|
20661
|
+
id: "Ic/8JR",
|
|
20662
|
+
message: "You can manage content, media, menus, and taxonomies."
|
|
20663
|
+
};
|
|
20664
|
+
const MSG_SCOPE_AUTHOR = {
|
|
20665
|
+
id: "kKNInt",
|
|
20666
|
+
message: "You can create and edit your own content."
|
|
20667
|
+
};
|
|
20668
|
+
const MSG_SCOPE_CONTRIBUTOR = {
|
|
20669
|
+
id: "nzN9WF",
|
|
20670
|
+
message: "You can view and contribute to the site."
|
|
20671
|
+
};
|
|
20672
|
+
function scopeDescriptor(isAdmin, userRole) {
|
|
20673
|
+
if (isAdmin) return MSG_SCOPE_ADMIN;
|
|
20674
|
+
if (userRole >= 40) return MSG_SCOPE_EDITOR;
|
|
20675
|
+
if (userRole >= 30) return MSG_SCOPE_AUTHOR;
|
|
20676
|
+
return MSG_SCOPE_CONTRIBUTOR;
|
|
20677
|
+
}
|
|
20678
|
+
const MSG_ADMIN_INVITE = {
|
|
20679
|
+
id: "QwxfcZ",
|
|
20680
|
+
message: "As an administrator, you can invite other users from the Users section."
|
|
20681
|
+
};
|
|
20682
|
+
const MSG_CLOSE = {
|
|
20683
|
+
id: "yz7wBu",
|
|
20684
|
+
message: "Close"
|
|
20685
|
+
};
|
|
19861
20686
|
async function dismissWelcome() {
|
|
19862
20687
|
const response = await apiFetch("/_emdash/api/auth/me", {
|
|
19863
20688
|
method: "POST",
|
|
@@ -19867,6 +20692,7 @@ async function dismissWelcome() {
|
|
|
19867
20692
|
if (!response.ok) await throwResponseError(response, "Failed to dismiss welcome");
|
|
19868
20693
|
}
|
|
19869
20694
|
function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
20695
|
+
const { _: _t } = useLingui();
|
|
19870
20696
|
const queryClient = useQueryClient();
|
|
19871
20697
|
const dismissMutation = useMutation({
|
|
19872
20698
|
mutationFn: dismissWelcome,
|
|
@@ -19887,28 +20713,36 @@ function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
|
19887
20713
|
const handleGetStarted = () => {
|
|
19888
20714
|
dismissMutation.mutate();
|
|
19889
20715
|
};
|
|
19890
|
-
const roleLabel =
|
|
20716
|
+
const roleLabel = _t(roleDescriptor(userRole));
|
|
19891
20717
|
const isAdmin = userRole >= 50;
|
|
20718
|
+
const firstName = userName?.split(" ")?.[0]?.trim() ?? "";
|
|
20719
|
+
const titleDescriptor = firstName.length > 0 ? {
|
|
20720
|
+
id: "7vQyJA",
|
|
20721
|
+
message: "Welcome to EmDash, {firstName}!",
|
|
20722
|
+
values: { firstName }
|
|
20723
|
+
} : {
|
|
20724
|
+
id: "N5RCak",
|
|
20725
|
+
message: "Welcome to EmDash!"
|
|
20726
|
+
};
|
|
19892
20727
|
return /* @__PURE__ */ jsx(Dialog.Root, {
|
|
19893
20728
|
open,
|
|
19894
20729
|
onOpenChange: (isOpen) => !isOpen && handleGetStarted(),
|
|
19895
20730
|
children: /* @__PURE__ */ jsxs(Dialog, {
|
|
19896
20731
|
className: "p-6 sm:max-w-md",
|
|
19897
|
-
size: "lg",
|
|
19898
20732
|
children: [
|
|
19899
20733
|
/* @__PURE__ */ jsxs("div", {
|
|
19900
20734
|
className: "flex items-start justify-between gap-4",
|
|
19901
20735
|
children: [/* @__PURE__ */ jsx("div", { className: "flex-1" }), /* @__PURE__ */ jsx(Dialog.Close, {
|
|
19902
|
-
"aria-label":
|
|
20736
|
+
"aria-label": _t(MSG_CLOSE),
|
|
19903
20737
|
render: (props) => /* @__PURE__ */ jsxs(Button, {
|
|
19904
20738
|
...props,
|
|
19905
20739
|
variant: "ghost",
|
|
19906
20740
|
shape: "square",
|
|
19907
|
-
"aria-label":
|
|
20741
|
+
"aria-label": _t(MSG_CLOSE),
|
|
19908
20742
|
className: "absolute right-4 top-4",
|
|
19909
20743
|
children: [/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }), /* @__PURE__ */ jsx("span", {
|
|
19910
20744
|
className: "sr-only",
|
|
19911
|
-
children:
|
|
20745
|
+
children: _t(MSG_CLOSE)
|
|
19912
20746
|
})]
|
|
19913
20747
|
})
|
|
19914
20748
|
})]
|
|
@@ -19920,17 +20754,13 @@ function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
|
19920
20754
|
className: "mx-auto mb-4",
|
|
19921
20755
|
children: /* @__PURE__ */ jsx(LogoIcon, { className: "h-16 w-16" })
|
|
19922
20756
|
}),
|
|
19923
|
-
/* @__PURE__ */
|
|
20757
|
+
/* @__PURE__ */ jsx(Dialog.Title, {
|
|
19924
20758
|
className: "text-2xl font-semibold leading-none tracking-tight",
|
|
19925
|
-
children:
|
|
19926
|
-
"Welcome to EmDash",
|
|
19927
|
-
userName ? `, ${userName.split(" ")[0]}` : "",
|
|
19928
|
-
"!"
|
|
19929
|
-
]
|
|
20759
|
+
children: _t(titleDescriptor)
|
|
19930
20760
|
}),
|
|
19931
20761
|
/* @__PURE__ */ jsx(Dialog.Description, {
|
|
19932
20762
|
className: "text-base text-kumo-subtle",
|
|
19933
|
-
children:
|
|
20763
|
+
children: _t(MSG_ACCOUNT_CREATED)
|
|
19934
20764
|
})
|
|
19935
20765
|
]
|
|
19936
20766
|
}),
|
|
@@ -19941,7 +20771,7 @@ function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
|
19941
20771
|
children: [
|
|
19942
20772
|
/* @__PURE__ */ jsx("div", {
|
|
19943
20773
|
className: "text-sm font-medium",
|
|
19944
|
-
children:
|
|
20774
|
+
children: _t(MSG_YOUR_ROLE)
|
|
19945
20775
|
}),
|
|
19946
20776
|
/* @__PURE__ */ jsx("div", {
|
|
19947
20777
|
className: "text-lg font-semibold text-kumo-brand",
|
|
@@ -19949,20 +20779,12 @@ function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
|
19949
20779
|
}),
|
|
19950
20780
|
/* @__PURE__ */ jsx("p", {
|
|
19951
20781
|
className: "text-sm text-kumo-subtle mt-1",
|
|
19952
|
-
children: isAdmin
|
|
20782
|
+
children: _t(scopeDescriptor(isAdmin, userRole))
|
|
19953
20783
|
})
|
|
19954
20784
|
]
|
|
19955
|
-
}), isAdmin && /* @__PURE__ */
|
|
20785
|
+
}), isAdmin && /* @__PURE__ */ jsx("p", {
|
|
19956
20786
|
className: "text-sm text-kumo-subtle",
|
|
19957
|
-
children:
|
|
19958
|
-
"As an administrator, you can invite other users from the",
|
|
19959
|
-
" ",
|
|
19960
|
-
/* @__PURE__ */ jsx("span", {
|
|
19961
|
-
className: "font-medium",
|
|
19962
|
-
children: "Users"
|
|
19963
|
-
}),
|
|
19964
|
-
" section."
|
|
19965
|
-
]
|
|
20787
|
+
children: _t(MSG_ADMIN_INVITE)
|
|
19966
20788
|
})]
|
|
19967
20789
|
}),
|
|
19968
20790
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -19971,7 +20793,13 @@ function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
|
19971
20793
|
onClick: handleGetStarted,
|
|
19972
20794
|
disabled: dismissMutation.isPending,
|
|
19973
20795
|
size: "lg",
|
|
19974
|
-
children: dismissMutation.isPending ?
|
|
20796
|
+
children: dismissMutation.isPending ? _t({
|
|
20797
|
+
id: "Z3FXyt",
|
|
20798
|
+
message: "Loading..."
|
|
20799
|
+
}) : _t({
|
|
20800
|
+
id: "c3b0B0",
|
|
20801
|
+
message: "Get Started"
|
|
20802
|
+
})
|
|
19975
20803
|
})
|
|
19976
20804
|
})
|
|
19977
20805
|
]
|
|
@@ -21450,22 +22278,29 @@ function isPaletteItem(data) {
|
|
|
21450
22278
|
/** Built-in widget types available in the palette */
|
|
21451
22279
|
const BUILTIN_WIDGETS = [{
|
|
21452
22280
|
id: "palette-content",
|
|
21453
|
-
label:
|
|
21454
|
-
|
|
21455
|
-
|
|
21456
|
-
|
|
21457
|
-
|
|
21458
|
-
|
|
22281
|
+
label: {
|
|
22282
|
+
id: "ESoS5n",
|
|
22283
|
+
message: "Content Block"
|
|
22284
|
+
},
|
|
22285
|
+
description: {
|
|
22286
|
+
id: "oYoiTA",
|
|
22287
|
+
message: "Rich text content"
|
|
22288
|
+
},
|
|
22289
|
+
input: { type: "content" }
|
|
21459
22290
|
}, {
|
|
21460
22291
|
id: "palette-menu",
|
|
21461
|
-
label:
|
|
21462
|
-
|
|
21463
|
-
|
|
21464
|
-
|
|
21465
|
-
|
|
21466
|
-
|
|
22292
|
+
label: {
|
|
22293
|
+
id: "zucql+",
|
|
22294
|
+
message: "Menu"
|
|
22295
|
+
},
|
|
22296
|
+
description: {
|
|
22297
|
+
id: "an2U5p",
|
|
22298
|
+
message: "Display a navigation menu"
|
|
22299
|
+
},
|
|
22300
|
+
input: { type: "menu" }
|
|
21467
22301
|
}];
|
|
21468
22302
|
function Widgets() {
|
|
22303
|
+
const { _: _t } = useLingui();
|
|
21469
22304
|
const queryClient = useQueryClient();
|
|
21470
22305
|
const toastManager = Toast.useToastManager();
|
|
21471
22306
|
const [isCreateAreaOpen, setIsCreateAreaOpen] = React.useState(false);
|
|
@@ -21707,9 +22542,12 @@ function Widgets() {
|
|
|
21707
22542
|
className: "space-y-2",
|
|
21708
22543
|
children: [BUILTIN_WIDGETS.map((item) => /* @__PURE__ */ jsx(DraggablePaletteItem, {
|
|
21709
22544
|
id: item.id,
|
|
21710
|
-
label: item.label,
|
|
21711
|
-
description: item.description,
|
|
21712
|
-
widgetInput:
|
|
22545
|
+
label: _t(item.label),
|
|
22546
|
+
description: _t(item.description),
|
|
22547
|
+
widgetInput: {
|
|
22548
|
+
...item.input,
|
|
22549
|
+
title: _t(item.label)
|
|
22550
|
+
}
|
|
21713
22551
|
}, item.id)), components.map((comp) => /* @__PURE__ */ jsx(DraggablePaletteItem, {
|
|
21714
22552
|
id: `palette-comp-${comp.id}`,
|
|
21715
22553
|
label: comp.label,
|
|
@@ -24473,50 +25311,11 @@ function BylinesPage() {
|
|
|
24473
25311
|
|
|
24474
25312
|
//#endregion
|
|
24475
25313
|
//#region src/components/users/RoleBadge.tsx
|
|
24476
|
-
/** Role level to name mapping */
|
|
24477
|
-
const ROLE_CONFIG = {
|
|
24478
|
-
10: {
|
|
24479
|
-
label: "Subscriber",
|
|
24480
|
-
color: "gray",
|
|
24481
|
-
description: "Can view content"
|
|
24482
|
-
},
|
|
24483
|
-
20: {
|
|
24484
|
-
label: "Contributor",
|
|
24485
|
-
color: "blue",
|
|
24486
|
-
description: "Can create content"
|
|
24487
|
-
},
|
|
24488
|
-
30: {
|
|
24489
|
-
label: "Author",
|
|
24490
|
-
color: "green",
|
|
24491
|
-
description: "Can publish own content"
|
|
24492
|
-
},
|
|
24493
|
-
40: {
|
|
24494
|
-
label: "Editor",
|
|
24495
|
-
color: "purple",
|
|
24496
|
-
description: "Can manage all content"
|
|
24497
|
-
},
|
|
24498
|
-
50: {
|
|
24499
|
-
label: "Admin",
|
|
24500
|
-
color: "red",
|
|
24501
|
-
description: "Full access"
|
|
24502
|
-
}
|
|
24503
|
-
};
|
|
24504
|
-
/** Get role config, with fallback for unknown roles */
|
|
24505
|
-
function getRoleConfig(role) {
|
|
24506
|
-
return ROLE_CONFIG[role] ?? {
|
|
24507
|
-
label: `Role ${role}`,
|
|
24508
|
-
color: "gray",
|
|
24509
|
-
description: "Unknown role"
|
|
24510
|
-
};
|
|
24511
|
-
}
|
|
24512
|
-
/** Get role label from role level */
|
|
24513
|
-
function getRoleLabel(role) {
|
|
24514
|
-
return getRoleConfig(role).label;
|
|
24515
|
-
}
|
|
24516
25314
|
/**
|
|
24517
25315
|
* Role badge component with semantic colors
|
|
24518
25316
|
*/
|
|
24519
25317
|
function RoleBadge({ role, size = "sm", showDescription = false, className }) {
|
|
25318
|
+
const { _: _t } = useLingui();
|
|
24520
25319
|
const config = getRoleConfig(role);
|
|
24521
25320
|
return /* @__PURE__ */ jsxs("span", {
|
|
24522
25321
|
className: cn("inline-flex items-center rounded-full font-medium", {
|
|
@@ -24529,41 +25328,13 @@ function RoleBadge({ role, size = "sm", showDescription = false, className }) {
|
|
|
24529
25328
|
purple: "bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200",
|
|
24530
25329
|
red: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200"
|
|
24531
25330
|
}[config.color], className),
|
|
24532
|
-
title: showDescription ? void 0 : config.description,
|
|
24533
|
-
children: [config.label, showDescription && /* @__PURE__ */ jsxs("span", {
|
|
25331
|
+
title: showDescription ? void 0 : _t(config.description),
|
|
25332
|
+
children: [_t(config.label), showDescription && /* @__PURE__ */ jsxs("span", {
|
|
24534
25333
|
className: "ml-1 opacity-75",
|
|
24535
|
-
children: ["- ", config.description]
|
|
25334
|
+
children: ["- ", _t(config.description)]
|
|
24536
25335
|
})]
|
|
24537
25336
|
});
|
|
24538
25337
|
}
|
|
24539
|
-
/** List of all roles for dropdowns */
|
|
24540
|
-
const ROLES = [
|
|
24541
|
-
{
|
|
24542
|
-
value: 10,
|
|
24543
|
-
label: "Subscriber",
|
|
24544
|
-
description: "Can view content"
|
|
24545
|
-
},
|
|
24546
|
-
{
|
|
24547
|
-
value: 20,
|
|
24548
|
-
label: "Contributor",
|
|
24549
|
-
description: "Can create content"
|
|
24550
|
-
},
|
|
24551
|
-
{
|
|
24552
|
-
value: 30,
|
|
24553
|
-
label: "Author",
|
|
24554
|
-
description: "Can publish own content"
|
|
24555
|
-
},
|
|
24556
|
-
{
|
|
24557
|
-
value: 40,
|
|
24558
|
-
label: "Editor",
|
|
24559
|
-
description: "Can manage all content"
|
|
24560
|
-
},
|
|
24561
|
-
{
|
|
24562
|
-
value: 50,
|
|
24563
|
-
label: "Admin",
|
|
24564
|
-
description: "Full access"
|
|
24565
|
-
}
|
|
24566
|
-
];
|
|
24567
25338
|
|
|
24568
25339
|
//#endregion
|
|
24569
25340
|
//#region src/components/users/UserList.tsx
|
|
@@ -24571,6 +25342,22 @@ const ROLES = [
|
|
|
24571
25342
|
* User list component with search, filter, and table display
|
|
24572
25343
|
*/
|
|
24573
25344
|
function UserList({ users, isLoading, hasMore, searchQuery, roleFilter, onSearchChange, onRoleFilterChange, onSelectUser, onInviteUser, onLoadMore }) {
|
|
25345
|
+
const { _: _t } = useLingui();
|
|
25346
|
+
const { roles, roleLabels } = useRolesConfig();
|
|
25347
|
+
const roleFilterSelectItems = React.useMemo(() => ({
|
|
25348
|
+
all: _t({
|
|
25349
|
+
id: "Hm90t3",
|
|
25350
|
+
message: "All roles"
|
|
25351
|
+
}),
|
|
25352
|
+
...roleLabels
|
|
25353
|
+
}), [_t, roleLabels]);
|
|
25354
|
+
const roleFilterSelectOptions = React.useMemo(() => [{
|
|
25355
|
+
value: "all",
|
|
25356
|
+
label: _t({
|
|
25357
|
+
id: "Hm90t3",
|
|
25358
|
+
message: "All roles"
|
|
25359
|
+
})
|
|
25360
|
+
}, ...roles], [_t, roles]);
|
|
24574
25361
|
return /* @__PURE__ */ jsxs("div", {
|
|
24575
25362
|
className: "space-y-4",
|
|
24576
25363
|
children: [
|
|
@@ -24600,21 +25387,15 @@ function UserList({ users, isLoading, hasMore, searchQuery, roleFilter, onSearch
|
|
|
24600
25387
|
onChange: (e) => onSearchChange(e.target.value),
|
|
24601
25388
|
"aria-label": "Search users"
|
|
24602
25389
|
})]
|
|
24603
|
-
}), /* @__PURE__ */
|
|
25390
|
+
}), /* @__PURE__ */ jsx(Select, {
|
|
24604
25391
|
value: roleFilter?.toString() ?? "all",
|
|
24605
25392
|
onValueChange: (value) => onRoleFilterChange(value === "all" || value === null ? void 0 : parseInt(value, 10)),
|
|
24606
|
-
items:
|
|
24607
|
-
all: "All roles",
|
|
24608
|
-
...Object.fromEntries(ROLES.map((r) => [r.value.toString(), r.label]))
|
|
24609
|
-
},
|
|
25393
|
+
items: roleFilterSelectItems,
|
|
24610
25394
|
"aria-label": "Filter by role",
|
|
24611
|
-
children:
|
|
24612
|
-
value:
|
|
24613
|
-
children:
|
|
24614
|
-
}
|
|
24615
|
-
value: role.value.toString(),
|
|
24616
|
-
children: role.label
|
|
24617
|
-
}, role.value))]
|
|
25395
|
+
children: roleFilterSelectOptions.map((option) => /* @__PURE__ */ jsx(Select.Option, {
|
|
25396
|
+
value: option.value,
|
|
25397
|
+
children: option.label
|
|
25398
|
+
}, option.value))
|
|
24618
25399
|
})]
|
|
24619
25400
|
}),
|
|
24620
25401
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -24791,6 +25572,7 @@ function UserListSkeleton() {
|
|
|
24791
25572
|
* User detail slide-over panel with inline editing
|
|
24792
25573
|
*/
|
|
24793
25574
|
function UserDetail({ user, isLoading, isOpen, isSaving, isSendingRecovery, recoverySent, recoveryError, currentUserId, onClose, onSave, onDisable, onEnable, onSendRecovery }) {
|
|
25575
|
+
const { roles, roleLabels, getRoleLabel } = useRolesConfig();
|
|
24794
25576
|
const [name, setName] = React.useState(user?.name ?? "");
|
|
24795
25577
|
const [email, setEmail] = React.useState(user?.email ?? "");
|
|
24796
25578
|
const [role, setRole] = React.useState(user?.role ?? 30);
|
|
@@ -24902,8 +25684,8 @@ function UserDetail({ user, isLoading, isOpen, isSaving, isSendingRecovery, reco
|
|
|
24902
25684
|
label: "Role",
|
|
24903
25685
|
value: role.toString(),
|
|
24904
25686
|
onValueChange: (v) => v !== null && setRole(parseInt(v, 10)),
|
|
24905
|
-
items:
|
|
24906
|
-
children:
|
|
25687
|
+
items: roleLabels,
|
|
25688
|
+
children: roles.map((r) => /* @__PURE__ */ jsx(Select.Option, {
|
|
24907
25689
|
value: r.value.toString(),
|
|
24908
25690
|
children: /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", { children: r.label }), /* @__PURE__ */ jsx("div", {
|
|
24909
25691
|
className: "text-xs text-kumo-subtle",
|
|
@@ -25114,6 +25896,7 @@ function UserDetailSkeleton() {
|
|
|
25114
25896
|
* Invite user modal — sends invite email or shows copy-link fallback
|
|
25115
25897
|
*/
|
|
25116
25898
|
function InviteUserModal({ open, isSending, error, inviteUrl, onOpenChange, onInvite }) {
|
|
25899
|
+
const { roles, roleLabels } = useRolesConfig();
|
|
25117
25900
|
const [email, setEmail] = React.useState("");
|
|
25118
25901
|
const [role, setRole] = React.useState(30);
|
|
25119
25902
|
const [copied, setCopied] = React.useState(false);
|
|
@@ -25241,8 +26024,8 @@ function InviteUserModal({ open, isSending, error, inviteUrl, onOpenChange, onIn
|
|
|
25241
26024
|
label: "Role",
|
|
25242
26025
|
value: role.toString(),
|
|
25243
26026
|
onValueChange: (v) => v !== null && setRole(parseInt(v, 10)),
|
|
25244
|
-
items:
|
|
25245
|
-
children:
|
|
26027
|
+
items: roleLabels,
|
|
26028
|
+
children: roles.map((r) => /* @__PURE__ */ jsx(Select.Option, {
|
|
25246
26029
|
value: r.value.toString(),
|
|
25247
26030
|
children: /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", { children: r.label }), /* @__PURE__ */ jsx("div", {
|
|
25248
26031
|
className: "text-xs text-kumo-subtle",
|
|
@@ -25297,6 +26080,7 @@ function useDebounce(value, delay) {
|
|
|
25297
26080
|
return debouncedValue;
|
|
25298
26081
|
}
|
|
25299
26082
|
function UsersPage() {
|
|
26083
|
+
const { getRoleLabel } = useRolesConfig();
|
|
25300
26084
|
const queryClient = useQueryClient();
|
|
25301
26085
|
const [searchQuery, setSearchQuery] = React.useState("");
|
|
25302
26086
|
const [roleFilter, setRoleFilter] = React.useState();
|
|
@@ -25551,6 +26335,10 @@ const adminLayoutRoute = createRoute({
|
|
|
25551
26335
|
id: "_admin",
|
|
25552
26336
|
component: RootComponent
|
|
25553
26337
|
});
|
|
26338
|
+
if (typeof window !== "undefined" && typeof window.requestIdleCallback === "undefined") {
|
|
26339
|
+
window.requestIdleCallback = (cb) => setTimeout(cb, 50);
|
|
26340
|
+
window.cancelIdleCallback = (id) => clearTimeout(id);
|
|
26341
|
+
}
|
|
25554
26342
|
function RootComponent() {
|
|
25555
26343
|
const { data: manifest, isLoading, error } = useQuery({
|
|
25556
26344
|
queryKey: ["manifest"],
|
|
@@ -25683,6 +26471,9 @@ function ContentListPage() {
|
|
|
25683
26471
|
});
|
|
25684
26472
|
}
|
|
25685
26473
|
});
|
|
26474
|
+
const items = React.useMemo(() => {
|
|
26475
|
+
return data?.pages.flatMap((page) => page.items) || [];
|
|
26476
|
+
}, [data]);
|
|
25686
26477
|
if (!manifest) return /* @__PURE__ */ jsx(LoadingScreen, {});
|
|
25687
26478
|
const collectionConfig = manifest.collections[collection];
|
|
25688
26479
|
if (!collectionConfig) return /* @__PURE__ */ jsx(NotFoundPage, { message: `Collection "${collection}" not found` });
|
|
@@ -25694,9 +26485,6 @@ function ContentListPage() {
|
|
|
25694
26485
|
search: { locale: locale || void 0 }
|
|
25695
26486
|
});
|
|
25696
26487
|
};
|
|
25697
|
-
const items = React.useMemo(() => {
|
|
25698
|
-
return data?.pages.flatMap((page) => page.items) || [];
|
|
25699
|
-
}, [data]);
|
|
25700
26488
|
return /* @__PURE__ */ jsx(ContentList, {
|
|
25701
26489
|
collection,
|
|
25702
26490
|
collectionLabel: collectionConfig.label,
|
|
@@ -25705,7 +26493,7 @@ function ContentListPage() {
|
|
|
25705
26493
|
isLoading: isLoading || isFetchingNextPage,
|
|
25706
26494
|
isTrashedLoading,
|
|
25707
26495
|
hasMore: !!hasNextPage,
|
|
25708
|
-
onLoadMore: () => void fetchNextPage(),
|
|
26496
|
+
onLoadMore: React.useCallback(() => void fetchNextPage(), [fetchNextPage]),
|
|
25709
26497
|
trashedCount: trashedData?.items?.length || 0,
|
|
25710
26498
|
onDelete: (id) => deleteMutation.mutate(id),
|
|
25711
26499
|
onRestore: (id) => restoreMutation.mutate(id),
|
|
@@ -25729,10 +26517,12 @@ function getPluginBlocks(manifest) {
|
|
|
25729
26517
|
const contentNewRoute = createRoute({
|
|
25730
26518
|
getParentRoute: () => adminLayoutRoute,
|
|
25731
26519
|
path: "/content/$collection/new",
|
|
25732
|
-
component: ContentNewPage
|
|
26520
|
+
component: ContentNewPage,
|
|
26521
|
+
validateSearch: (search) => ({ locale: typeof search.locale === "string" ? search.locale : void 0 })
|
|
25733
26522
|
});
|
|
25734
26523
|
function ContentNewPage() {
|
|
25735
26524
|
const { collection } = useParams({ from: "/_admin/content/$collection/new" });
|
|
26525
|
+
const { locale } = useSearch({ from: "/_admin/content/$collection/new" });
|
|
25736
26526
|
const navigate = useNavigate();
|
|
25737
26527
|
const queryClient = useQueryClient();
|
|
25738
26528
|
const [selectedBylines, setSelectedBylines] = React.useState([]);
|
|
@@ -25741,7 +26531,10 @@ function ContentNewPage() {
|
|
|
25741
26531
|
queryFn: fetchManifest
|
|
25742
26532
|
});
|
|
25743
26533
|
const createMutation = useMutation({
|
|
25744
|
-
mutationFn: (data) => createContent(collection,
|
|
26534
|
+
mutationFn: (data) => createContent(collection, {
|
|
26535
|
+
...data,
|
|
26536
|
+
locale
|
|
26537
|
+
}),
|
|
25745
26538
|
onSuccess: (result) => {
|
|
25746
26539
|
queryClient.invalidateQueries({ queryKey: ["content", collection] });
|
|
25747
26540
|
navigate({
|
|
@@ -25808,11 +26601,13 @@ function ContentNewPage() {
|
|
|
25808
26601
|
const contentEditRoute = createRoute({
|
|
25809
26602
|
getParentRoute: () => adminLayoutRoute,
|
|
25810
26603
|
path: "/content/$collection/$id",
|
|
25811
|
-
component: ContentEditPage
|
|
26604
|
+
component: ContentEditPage,
|
|
26605
|
+
validateSearch: (search) => ({ ...typeof search.field === "string" && { field: search.field } })
|
|
25812
26606
|
});
|
|
25813
26607
|
const ROLE_EDITOR = 40;
|
|
25814
26608
|
function ContentEditPage() {
|
|
25815
26609
|
const { collection, id } = useParams({ from: "/_admin/content/$collection/$id" });
|
|
26610
|
+
const searchParams = useSearch({ from: "/_admin/content/$collection/$id" });
|
|
25816
26611
|
const queryClient = useQueryClient();
|
|
25817
26612
|
const navigate = useNavigate();
|
|
25818
26613
|
const toastManager = Toast.useToastManager();
|
|
@@ -25829,6 +26624,29 @@ function ContentEditPage() {
|
|
|
25829
26624
|
],
|
|
25830
26625
|
queryFn: () => fetchContent(collection, id)
|
|
25831
26626
|
});
|
|
26627
|
+
React.useEffect(() => {
|
|
26628
|
+
if (typeof searchParams.field !== "string" || isLoading) return;
|
|
26629
|
+
const timeoutId = requestIdleCallback(() => {
|
|
26630
|
+
const el = document.getElementById(`field-${searchParams.field}`);
|
|
26631
|
+
if (el) {
|
|
26632
|
+
el.scrollIntoView({
|
|
26633
|
+
behavior: "smooth",
|
|
26634
|
+
block: "center"
|
|
26635
|
+
});
|
|
26636
|
+
el.focus();
|
|
26637
|
+
const { field: _, ...preservedSearch } = searchParams;
|
|
26638
|
+
navigate({
|
|
26639
|
+
search: preservedSearch,
|
|
26640
|
+
replace: true
|
|
26641
|
+
});
|
|
26642
|
+
}
|
|
26643
|
+
});
|
|
26644
|
+
return () => cancelIdleCallback(timeoutId);
|
|
26645
|
+
}, [
|
|
26646
|
+
searchParams,
|
|
26647
|
+
isLoading,
|
|
26648
|
+
navigate
|
|
26649
|
+
]);
|
|
25832
26650
|
const { data: translationsData } = useQuery({
|
|
25833
26651
|
queryKey: [
|
|
25834
26652
|
"translations",
|
|
@@ -26826,19 +27644,30 @@ const router = createAdminRouter(queryClient);
|
|
|
26826
27644
|
* Main Admin Application
|
|
26827
27645
|
*/
|
|
26828
27646
|
const EMPTY_PLUGINS = {};
|
|
26829
|
-
function AdminApp({ pluginAdmins = EMPTY_PLUGINS }) {
|
|
27647
|
+
function AdminApp({ pluginAdmins = EMPTY_PLUGINS, locale = "en", messages = {} }) {
|
|
26830
27648
|
React.useEffect(() => {
|
|
26831
27649
|
document.getElementById("emdash-boot-loader")?.remove();
|
|
26832
27650
|
}, []);
|
|
26833
|
-
|
|
26834
|
-
|
|
26835
|
-
|
|
26836
|
-
|
|
26837
|
-
|
|
26838
|
-
})
|
|
26839
|
-
|
|
27651
|
+
const i18nInitialized = React.useRef(false);
|
|
27652
|
+
if (!i18nInitialized.current) {
|
|
27653
|
+
i18n.loadAndActivate({
|
|
27654
|
+
locale,
|
|
27655
|
+
messages
|
|
27656
|
+
});
|
|
27657
|
+
i18nInitialized.current = true;
|
|
27658
|
+
}
|
|
27659
|
+
return /* @__PURE__ */ jsx(ThemeProvider, { children: /* @__PURE__ */ jsx(I18nProvider, {
|
|
27660
|
+
i18n,
|
|
27661
|
+
children: /* @__PURE__ */ jsx(Toasty, { children: /* @__PURE__ */ jsx(PluginAdminProvider, {
|
|
27662
|
+
pluginAdmins,
|
|
27663
|
+
children: /* @__PURE__ */ jsx(QueryClientProvider, {
|
|
27664
|
+
client: queryClient,
|
|
27665
|
+
children: /* @__PURE__ */ jsx(RouterProvider, { router })
|
|
27666
|
+
})
|
|
27667
|
+
}) })
|
|
27668
|
+
}) });
|
|
26840
27669
|
}
|
|
26841
27670
|
|
|
26842
27671
|
//#endregion
|
|
26843
|
-
export { API_BASE, API_TOKEN_SCOPES, AdminApp, AdminApp as App, CAPABILITY_LABELS, ContentEditor, ContentList, Dashboard, Header, Link, LoginPage, MediaLibrary, MediaPickerModal, PasskeyLogin, PasskeyRegistration, PluginAdminProvider, PortableTextEditor, SaveButton, Settings, SetupWizard, Shell, KumoSidebar as Sidebar, SidebarNav, analyzeWpPluginSite, analyzeWxr, apiFetch, bulkCommentAction, checkPluginUpdates, cn, compareRevisions, completeSignup, createAdminRouter, createAllowedDomain, createApiToken, createByline, createCollection, createContent, createField, createMenu, createMenuItem, createRedirect, createSection, createTaxonomy, createTerm, createWidget, createWidgetArea, deleteAllowedDomain, deleteByline, deleteCollection, deleteComment, deleteContent, deleteField, deleteFromProvider, deleteMedia, deleteMenu, deleteMenuItem, deletePasskey, deleteRedirect, deleteSection, deleteTerm, deleteWidget, deleteWidgetArea, describeCapability, disablePlugin, disableUser, discardDraft, duplicateContent, enablePlugin, enableUser, executeWpPluginImport, executeWxrImport, fetch404Summary, fetchAllowedDomains, fetchApiTokens, fetchByline, fetchBylines, fetchCollection, fetchCollections, fetchComment, fetchCommentCounts, fetchComments, fetchContent, fetchContentList, fetchDashboardStats, fetchEmailSettings, fetchFields, fetchManifest, fetchMarketplacePlugin, fetchMediaList, fetchMediaProviders, fetchMenu, fetchMenus, fetchOrphanedTables, fetchPasskeys, fetchPlugin, fetchPlugins, fetchProviderMedia, fetchRedirects, fetchRevision, fetchRevisions, fetchSection, fetchSections, fetchSettings, fetchTaxonomyDef, fetchTaxonomyDefs, fetchTerms, fetchTheme, fetchTranslations, fetchTrashedContent, fetchUser, fetchUsers, fetchWidgetArea, fetchWidgetAreas, fetchWidgetComponents, generatePreviewUrl, getDraftStatus, getPreviewUrl, hasAllowedDomains, importWxrMedia, installMarketplacePlugin, inviteUser, parseApiResponse, permanentDeleteContent, prepareWxrImport, probeImportUrl, publishContent, registerOrphanedTable, renamePasskey, reorderFields, reorderMenuItems, reorderWidgets, requestSignup, restoreContent, restoreRevision, revokeApiToken, rewriteContentUrls, scheduleContent, searchMarketplace, searchThemes, sendRecoveryLink, sendTestEmail, setSearchEnabled, throwResponseError, uninstallMarketplacePlugin, unpublishContent, unscheduleContent, updateAllowedDomain, updateByline, updateCollection, updateCommentStatus, updateContent, updateField, updateMarketplacePlugin, updateMedia, updateMenu, updateMenuItem, updateRedirect, updateSection, updateSettings, updateTerm, updateUser, updateWidget, uploadMedia, uploadToProvider, useCurrentUser, useNavigate, useParams, usePluginAdmins, usePluginField, usePluginHasPages, usePluginHasWidgets, usePluginPage, usePluginWidget, verifySignupToken };
|
|
27672
|
+
export { API_BASE, API_TOKEN_SCOPES, AdminApp, AdminApp as App, CAPABILITY_LABELS, ContentEditor, ContentList, DEFAULT_LOCALE, Dashboard, Header, Link, LoginPage, MediaLibrary, MediaPickerModal, PasskeyLogin, PasskeyRegistration, PluginAdminProvider, PortableTextEditor, SUPPORTED_LOCALES, SUPPORTED_LOCALE_CODES, SaveButton, Settings, SetupWizard, Shell, KumoSidebar as Sidebar, SidebarNav, analyzeWpPluginSite, analyzeWxr, apiFetch, bulkCommentAction, checkPluginUpdates, cn, compareRevisions, completeSignup, createAdminRouter, createAllowedDomain, createApiToken, createByline, createCollection, createContent, createField, createMenu, createMenuItem, createRedirect, createSection, createTaxonomy, createTerm, createWidget, createWidgetArea, deleteAllowedDomain, deleteByline, deleteCollection, deleteComment, deleteContent, deleteField, deleteFromProvider, deleteMedia, deleteMenu, deleteMenuItem, deletePasskey, deleteRedirect, deleteSection, deleteTerm, deleteWidget, deleteWidgetArea, describeCapability, disablePlugin, disableUser, discardDraft, duplicateContent, enablePlugin, enableUser, executeWpPluginImport, executeWxrImport, fetch404Summary, fetchAllowedDomains, fetchApiTokens, fetchByline, fetchBylines, fetchCollection, fetchCollections, fetchComment, fetchCommentCounts, fetchComments, fetchContent, fetchContentList, fetchDashboardStats, fetchEmailSettings, fetchFields, fetchManifest, fetchMarketplacePlugin, fetchMediaList, fetchMediaProviders, fetchMenu, fetchMenus, fetchOrphanedTables, fetchPasskeys, fetchPlugin, fetchPlugins, fetchProviderMedia, fetchRedirects, fetchRevision, fetchRevisions, fetchSection, fetchSections, fetchSettings, fetchTaxonomyDef, fetchTaxonomyDefs, fetchTerms, fetchTheme, fetchTranslations, fetchTrashedContent, fetchUser, fetchUsers, fetchWidgetArea, fetchWidgetAreas, fetchWidgetComponents, generatePreviewUrl, getDraftStatus, getPreviewUrl, hasAllowedDomains, importWxrMedia, installMarketplacePlugin, inviteUser, parseApiResponse, permanentDeleteContent, prepareWxrImport, probeImportUrl, publishContent, registerOrphanedTable, renamePasskey, reorderFields, reorderMenuItems, reorderWidgets, requestSignup, resolveLocale, restoreContent, restoreRevision, revokeApiToken, rewriteContentUrls, scheduleContent, searchMarketplace, searchThemes, sendRecoveryLink, sendTestEmail, setSearchEnabled, throwResponseError, uninstallMarketplacePlugin, unpublishContent, unscheduleContent, updateAllowedDomain, updateByline, updateCollection, updateCommentStatus, updateContent, updateField, updateMarketplacePlugin, updateMedia, updateMenu, updateMenuItem, updateRedirect, updateSection, updateSettings, updateTerm, updateUser, updateWidget, uploadMedia, uploadToProvider, useCurrentUser, useLocale, useNavigate, useParams, usePluginAdmins, usePluginField, usePluginHasPages, usePluginHasWidgets, usePluginPage, usePluginWidget, verifySignupToken };
|
|
26844
27673
|
//# sourceMappingURL=index.js.map
|