@ampless/admin 0.2.0-alpha.22 → 0.2.0-alpha.24
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/api/index.d.ts +1 -1
- package/dist/{chunk-W6BXESPW.js → chunk-2U3POKAZ.js} +1 -1
- package/dist/{chunk-5Q6KVRZ2.js → chunk-6NPYUTV6.js} +2 -2
- package/dist/{chunk-CQY55RDG.js → chunk-6SB7YICQ.js} +1 -1
- package/dist/{chunk-JOASK4AM.js → chunk-CFQPS5NT.js} +1 -1
- package/dist/{chunk-S66L5CDS.js → chunk-CTGFMK2J.js} +1 -1
- package/dist/{chunk-A3SWBQA6.js → chunk-F7VFVKY5.js} +1 -1
- package/dist/{chunk-BC4B6DLO.js → chunk-G4IY757H.js} +2 -2
- package/dist/{chunk-QXJIIBUQ.js → chunk-KQOE5CT6.js} +2 -2
- package/dist/{chunk-CVJCMTYB.js → chunk-LITTIDB3.js} +397 -152
- package/dist/{chunk-XY4JWSMS.js → chunk-Q66BLMNJ.js} +1 -1
- package/dist/{chunk-SRNH2IVA.js → chunk-TZ5F24BG.js} +1 -1
- package/dist/{chunk-ILSBPHVE.js → chunk-V5FWGILB.js} +2 -2
- package/dist/{chunk-OSUTPPAU.js → chunk-WL4IBW2D.js} +24 -0
- package/dist/{chunk-5JKOPRCO.js → chunk-WOMPYZNV.js} +2 -2
- package/dist/components/admin-dashboard.js +3 -3
- package/dist/components/edit-post-view.js +5 -5
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +6 -6
- package/dist/components/login-view.js +3 -3
- package/dist/components/mcp-tokens-view.js +3 -3
- package/dist/components/media-view.js +5 -5
- package/dist/components/new-post-view.js +5 -5
- package/dist/components/posts-list-view.js +3 -3
- package/dist/components/users-list-view.js +3 -3
- package/dist/{i18n-MWvAMHzn.d.ts → i18n-BhMBRfio.d.ts} +36 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/metafile-esm.json +1 -1
- package/dist/pages/index.d.ts +1 -1
- package/dist/pages/index.js +14 -14
- package/package.json +18 -9
|
@@ -5,13 +5,13 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
ImageUploadDialog,
|
|
7
7
|
getMediaProcessingDefaults
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-CTGFMK2J.js";
|
|
9
9
|
import {
|
|
10
10
|
publicMediaUrl
|
|
11
11
|
} from "./chunk-2ITWLRYF.js";
|
|
12
12
|
import {
|
|
13
13
|
useT
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-Q66BLMNJ.js";
|
|
15
15
|
|
|
16
16
|
// src/lib/upload.ts
|
|
17
17
|
import { uploadData } from "aws-amplify/storage";
|
|
@@ -177,7 +177,7 @@ function MediaPicker({ trigger, onSelect }) {
|
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
// src/components/post-form.tsx
|
|
180
|
-
import { useRef as
|
|
180
|
+
import { useRef as useRef3, useState as useState4 } from "react";
|
|
181
181
|
import { useRouter } from "next/navigation";
|
|
182
182
|
import { Image as ImageIcon3 } from "lucide-react";
|
|
183
183
|
import {
|
|
@@ -193,39 +193,197 @@ import {
|
|
|
193
193
|
markdownToHtml,
|
|
194
194
|
htmlToMarkdown
|
|
195
195
|
} from "@ampless/runtime";
|
|
196
|
-
import { Button as
|
|
196
|
+
import { Button as Button6, Input, Label, Textarea } from "@ampless/runtime/ui";
|
|
197
197
|
|
|
198
198
|
// src/editor/tiptap-editor.tsx
|
|
199
199
|
import { useEditor, EditorContent } from "@tiptap/react";
|
|
200
200
|
import StarterKit from "@tiptap/starter-kit";
|
|
201
201
|
import Link from "@tiptap/extension-link";
|
|
202
202
|
import Image from "@tiptap/extension-image";
|
|
203
|
+
import { Table } from "@tiptap/extension-table";
|
|
204
|
+
import { TableRow } from "@tiptap/extension-table-row";
|
|
205
|
+
import { TableHeader } from "@tiptap/extension-table-header";
|
|
206
|
+
import { TableCell } from "@tiptap/extension-table-cell";
|
|
207
|
+
import { TaskList } from "@tiptap/extension-task-list";
|
|
208
|
+
import { TaskItem } from "@tiptap/extension-task-item";
|
|
209
|
+
import { Underline as Underline2 } from "@tiptap/extension-underline";
|
|
210
|
+
import { Highlight } from "@tiptap/extension-highlight";
|
|
211
|
+
import { TextAlign } from "@tiptap/extension-text-align";
|
|
203
212
|
|
|
204
213
|
// src/editor/toolbar.tsx
|
|
205
214
|
import {
|
|
206
215
|
Bold,
|
|
207
216
|
Italic,
|
|
217
|
+
Underline,
|
|
218
|
+
Strikethrough,
|
|
219
|
+
Highlighter,
|
|
208
220
|
Heading1,
|
|
209
221
|
Heading2,
|
|
210
222
|
List,
|
|
211
223
|
ListOrdered,
|
|
224
|
+
ListChecks,
|
|
212
225
|
Code,
|
|
226
|
+
Quote,
|
|
227
|
+
Minus,
|
|
228
|
+
TextAlignStart,
|
|
229
|
+
TextAlignCenter,
|
|
230
|
+
TextAlignEnd,
|
|
231
|
+
TextAlignJustify,
|
|
213
232
|
Link as LinkIcon,
|
|
214
233
|
Image as ImageIcon
|
|
215
234
|
} from "lucide-react";
|
|
235
|
+
import { Button as Button3, cn as cn2 } from "@ampless/runtime/ui";
|
|
236
|
+
|
|
237
|
+
// src/editor/table-controls.tsx
|
|
238
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
239
|
+
import { Table as TableIcon } from "lucide-react";
|
|
216
240
|
import { Button as Button2, cn } from "@ampless/runtime/ui";
|
|
217
241
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
242
|
+
function TableControls({ editor }) {
|
|
243
|
+
const t = useT();
|
|
244
|
+
const [open, setOpen] = useState2(false);
|
|
245
|
+
const rootRef = useRef2(null);
|
|
246
|
+
useEffect2(() => {
|
|
247
|
+
if (!open) return;
|
|
248
|
+
function onPointerDown(e) {
|
|
249
|
+
if (!rootRef.current) return;
|
|
250
|
+
if (e.target instanceof Node && rootRef.current.contains(e.target)) return;
|
|
251
|
+
setOpen(false);
|
|
252
|
+
}
|
|
253
|
+
function onKey(e) {
|
|
254
|
+
if (e.key === "Escape") setOpen(false);
|
|
255
|
+
}
|
|
256
|
+
document.addEventListener("mousedown", onPointerDown);
|
|
257
|
+
document.addEventListener("keydown", onKey);
|
|
258
|
+
return () => {
|
|
259
|
+
document.removeEventListener("mousedown", onPointerDown);
|
|
260
|
+
document.removeEventListener("keydown", onKey);
|
|
261
|
+
};
|
|
262
|
+
}, [open]);
|
|
263
|
+
const inTable = editor.isActive("table");
|
|
264
|
+
const items = [
|
|
265
|
+
{
|
|
266
|
+
key: "insert",
|
|
267
|
+
label: t("editor.table.insert"),
|
|
268
|
+
run: () => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(),
|
|
269
|
+
enabled: !inTable
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
key: "addRowBefore",
|
|
273
|
+
label: t("editor.table.addRowBefore"),
|
|
274
|
+
run: () => editor.chain().focus().addRowBefore().run(),
|
|
275
|
+
enabled: inTable && editor.can().addRowBefore()
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
key: "addRowAfter",
|
|
279
|
+
label: t("editor.table.addRowAfter"),
|
|
280
|
+
run: () => editor.chain().focus().addRowAfter().run(),
|
|
281
|
+
enabled: inTable && editor.can().addRowAfter()
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
key: "addColumnBefore",
|
|
285
|
+
label: t("editor.table.addColumnBefore"),
|
|
286
|
+
run: () => editor.chain().focus().addColumnBefore().run(),
|
|
287
|
+
enabled: inTable && editor.can().addColumnBefore()
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
key: "addColumnAfter",
|
|
291
|
+
label: t("editor.table.addColumnAfter"),
|
|
292
|
+
run: () => editor.chain().focus().addColumnAfter().run(),
|
|
293
|
+
enabled: inTable && editor.can().addColumnAfter()
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
key: "deleteRow",
|
|
297
|
+
label: t("editor.table.deleteRow"),
|
|
298
|
+
run: () => editor.chain().focus().deleteRow().run(),
|
|
299
|
+
enabled: inTable && editor.can().deleteRow()
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
key: "deleteColumn",
|
|
303
|
+
label: t("editor.table.deleteColumn"),
|
|
304
|
+
run: () => editor.chain().focus().deleteColumn().run(),
|
|
305
|
+
enabled: inTable && editor.can().deleteColumn()
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
key: "toggleHeaderRow",
|
|
309
|
+
label: t("editor.table.toggleHeaderRow"),
|
|
310
|
+
run: () => editor.chain().focus().toggleHeaderRow().run(),
|
|
311
|
+
enabled: inTable && editor.can().toggleHeaderRow()
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
key: "deleteTable",
|
|
315
|
+
label: t("editor.table.deleteTable"),
|
|
316
|
+
run: () => editor.chain().focus().deleteTable().run(),
|
|
317
|
+
enabled: inTable && editor.can().deleteTable()
|
|
318
|
+
}
|
|
319
|
+
];
|
|
320
|
+
return /* @__PURE__ */ jsxs2("div", { ref: rootRef, className: "relative", children: [
|
|
321
|
+
/* @__PURE__ */ jsx2(
|
|
322
|
+
Button2,
|
|
323
|
+
{
|
|
324
|
+
type: "button",
|
|
325
|
+
variant: "ghost",
|
|
326
|
+
size: "icon",
|
|
327
|
+
onClick: () => setOpen((v) => !v),
|
|
328
|
+
className: cn(inTable && "bg-accent text-accent-foreground"),
|
|
329
|
+
title: t("editor.table.title"),
|
|
330
|
+
"aria-expanded": open,
|
|
331
|
+
"aria-haspopup": "menu",
|
|
332
|
+
children: /* @__PURE__ */ jsx2(TableIcon, { className: "h-4 w-4" })
|
|
333
|
+
}
|
|
334
|
+
),
|
|
335
|
+
open && /* @__PURE__ */ jsx2(
|
|
336
|
+
"div",
|
|
337
|
+
{
|
|
338
|
+
role: "menu",
|
|
339
|
+
className: "absolute left-0 top-full z-50 mt-1 min-w-[12rem] rounded-md border bg-popover p-1 shadow",
|
|
340
|
+
children: items.map((item) => /* @__PURE__ */ jsx2(
|
|
341
|
+
"button",
|
|
342
|
+
{
|
|
343
|
+
type: "button",
|
|
344
|
+
role: "menuitem",
|
|
345
|
+
disabled: !item.enabled,
|
|
346
|
+
onClick: () => {
|
|
347
|
+
if (!item.enabled) return;
|
|
348
|
+
item.run();
|
|
349
|
+
setOpen(false);
|
|
350
|
+
},
|
|
351
|
+
className: cn(
|
|
352
|
+
"block w-full rounded-sm px-2 py-1 text-left text-sm",
|
|
353
|
+
item.enabled ? "hover:bg-accent hover:text-accent-foreground" : "cursor-not-allowed text-muted-foreground opacity-50"
|
|
354
|
+
),
|
|
355
|
+
children: item.label
|
|
356
|
+
},
|
|
357
|
+
item.key
|
|
358
|
+
))
|
|
359
|
+
}
|
|
360
|
+
)
|
|
361
|
+
] });
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// src/editor/toolbar.tsx
|
|
365
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
218
366
|
function Toolbar({ editor }) {
|
|
219
367
|
const t = useT();
|
|
220
368
|
if (!editor) return null;
|
|
221
369
|
const tools = [
|
|
222
370
|
{ name: "bold", icon: Bold, action: () => editor.chain().focus().toggleBold().run(), isActive: () => editor.isActive("bold") },
|
|
223
371
|
{ name: "italic", icon: Italic, action: () => editor.chain().focus().toggleItalic().run(), isActive: () => editor.isActive("italic") },
|
|
372
|
+
{ name: "underline", icon: Underline, action: () => editor.chain().focus().toggleUnderline().run(), isActive: () => editor.isActive("underline") },
|
|
373
|
+
{ name: "strike", icon: Strikethrough, action: () => editor.chain().focus().toggleStrike().run(), isActive: () => editor.isActive("strike") },
|
|
374
|
+
{ name: "highlight", icon: Highlighter, action: () => editor.chain().focus().toggleHighlight().run(), isActive: () => editor.isActive("highlight") },
|
|
224
375
|
{ name: "h1", icon: Heading1, action: () => editor.chain().focus().toggleHeading({ level: 1 }).run(), isActive: () => editor.isActive("heading", { level: 1 }) },
|
|
225
376
|
{ name: "h2", icon: Heading2, action: () => editor.chain().focus().toggleHeading({ level: 2 }).run(), isActive: () => editor.isActive("heading", { level: 2 }) },
|
|
226
377
|
{ name: "bulletList", icon: List, action: () => editor.chain().focus().toggleBulletList().run(), isActive: () => editor.isActive("bulletList") },
|
|
227
378
|
{ name: "orderedList", icon: ListOrdered, action: () => editor.chain().focus().toggleOrderedList().run(), isActive: () => editor.isActive("orderedList") },
|
|
228
|
-
{ name: "
|
|
379
|
+
{ name: "taskList", icon: ListChecks, action: () => editor.chain().focus().toggleTaskList().run(), isActive: () => editor.isActive("taskList") },
|
|
380
|
+
{ name: "code", icon: Code, action: () => editor.chain().focus().toggleCodeBlock().run(), isActive: () => editor.isActive("codeBlock") },
|
|
381
|
+
{ name: "blockquote", icon: Quote, action: () => editor.chain().focus().toggleBlockquote().run(), isActive: () => editor.isActive("blockquote") },
|
|
382
|
+
{ name: "hr", icon: Minus, action: () => editor.chain().focus().setHorizontalRule().run(), isActive: () => false },
|
|
383
|
+
{ name: "alignLeft", icon: TextAlignStart, action: () => editor.chain().focus().setTextAlign("left").run(), isActive: () => editor.isActive({ textAlign: "left" }) },
|
|
384
|
+
{ name: "alignCenter", icon: TextAlignCenter, action: () => editor.chain().focus().setTextAlign("center").run(), isActive: () => editor.isActive({ textAlign: "center" }) },
|
|
385
|
+
{ name: "alignRight", icon: TextAlignEnd, action: () => editor.chain().focus().setTextAlign("right").run(), isActive: () => editor.isActive({ textAlign: "right" }) },
|
|
386
|
+
{ name: "alignJustify", icon: TextAlignJustify, action: () => editor.chain().focus().setTextAlign("justify").run(), isActive: () => editor.isActive({ textAlign: "justify" }) }
|
|
229
387
|
];
|
|
230
388
|
const setLink = () => {
|
|
231
389
|
const previousUrl = editor.getAttributes("link").href ?? "";
|
|
@@ -240,48 +398,49 @@ function Toolbar({ editor }) {
|
|
|
240
398
|
const insertImage = (url) => {
|
|
241
399
|
editor.chain().focus().setImage({ src: url }).run();
|
|
242
400
|
};
|
|
243
|
-
return /* @__PURE__ */
|
|
401
|
+
return /* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap gap-1 border-b p-2", children: [
|
|
244
402
|
tools.map((tool) => {
|
|
245
403
|
const Icon = tool.icon;
|
|
246
|
-
return /* @__PURE__ */
|
|
247
|
-
|
|
404
|
+
return /* @__PURE__ */ jsx3(
|
|
405
|
+
Button3,
|
|
248
406
|
{
|
|
249
407
|
type: "button",
|
|
250
408
|
variant: "ghost",
|
|
251
409
|
size: "icon",
|
|
252
410
|
onClick: tool.action,
|
|
253
|
-
className:
|
|
254
|
-
children: /* @__PURE__ */
|
|
411
|
+
className: cn2(tool.isActive() && "bg-accent text-accent-foreground"),
|
|
412
|
+
children: /* @__PURE__ */ jsx3(Icon, { className: "h-4 w-4" })
|
|
255
413
|
},
|
|
256
414
|
tool.name
|
|
257
415
|
);
|
|
258
416
|
}),
|
|
259
|
-
/* @__PURE__ */
|
|
260
|
-
|
|
417
|
+
/* @__PURE__ */ jsx3(
|
|
418
|
+
Button3,
|
|
261
419
|
{
|
|
262
420
|
type: "button",
|
|
263
421
|
variant: "ghost",
|
|
264
422
|
size: "icon",
|
|
265
423
|
onClick: setLink,
|
|
266
|
-
className:
|
|
267
|
-
children: /* @__PURE__ */
|
|
424
|
+
className: cn2(editor.isActive("link") && "bg-accent text-accent-foreground"),
|
|
425
|
+
children: /* @__PURE__ */ jsx3(LinkIcon, { className: "h-4 w-4" })
|
|
268
426
|
}
|
|
269
427
|
),
|
|
270
|
-
/* @__PURE__ */
|
|
428
|
+
/* @__PURE__ */ jsx3(
|
|
271
429
|
MediaPicker,
|
|
272
430
|
{
|
|
273
431
|
onSelect: insertImage,
|
|
274
|
-
trigger: /* @__PURE__ */
|
|
432
|
+
trigger: /* @__PURE__ */ jsx3(Button3, { type: "button", variant: "ghost", size: "icon", children: /* @__PURE__ */ jsx3(ImageIcon, { className: "h-4 w-4" }) })
|
|
275
433
|
}
|
|
276
|
-
)
|
|
434
|
+
),
|
|
435
|
+
/* @__PURE__ */ jsx3(TableControls, { editor })
|
|
277
436
|
] });
|
|
278
437
|
}
|
|
279
438
|
|
|
280
439
|
// src/editor/image-bubble-menu.tsx
|
|
281
440
|
import { BubbleMenu } from "@tiptap/react/menus";
|
|
282
441
|
import { Trash2, Pencil, ImageIcon as ImageIcon2, Maximize2 } from "lucide-react";
|
|
283
|
-
import { Button as
|
|
284
|
-
import { jsx as
|
|
442
|
+
import { Button as Button4, cn as cn3 } from "@ampless/runtime/ui";
|
|
443
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
285
444
|
function ImageBubbleMenu({ editor }) {
|
|
286
445
|
const t = useT();
|
|
287
446
|
const editAlt = () => {
|
|
@@ -299,50 +458,50 @@ function ImageBubbleMenu({ editor }) {
|
|
|
299
458
|
editor.chain().focus().updateAttributes("image", { display: next }).run();
|
|
300
459
|
};
|
|
301
460
|
const currentDisplay = editor.getAttributes("image").display ?? null;
|
|
302
|
-
return /* @__PURE__ */
|
|
461
|
+
return /* @__PURE__ */ jsx4(
|
|
303
462
|
BubbleMenu,
|
|
304
463
|
{
|
|
305
464
|
editor,
|
|
306
465
|
shouldShow: ({ editor: editor2 }) => editor2.isActive("image"),
|
|
307
466
|
options: { placement: "top" },
|
|
308
|
-
children: /* @__PURE__ */
|
|
309
|
-
/* @__PURE__ */
|
|
310
|
-
|
|
467
|
+
children: /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-1 rounded-md border bg-popover p-1 shadow", children: [
|
|
468
|
+
/* @__PURE__ */ jsxs4(
|
|
469
|
+
Button4,
|
|
311
470
|
{
|
|
312
471
|
type: "button",
|
|
313
472
|
variant: "ghost",
|
|
314
473
|
size: "sm",
|
|
315
474
|
onClick: () => setDisplay("inline"),
|
|
316
|
-
className:
|
|
475
|
+
className: cn3(currentDisplay === "inline" && "bg-accent text-accent-foreground"),
|
|
317
476
|
title: t("editor.image.inlineTitle"),
|
|
318
477
|
children: [
|
|
319
|
-
/* @__PURE__ */
|
|
478
|
+
/* @__PURE__ */ jsx4(ImageIcon2, { className: "mr-1 h-3 w-3" }),
|
|
320
479
|
t("editor.image.inline")
|
|
321
480
|
]
|
|
322
481
|
}
|
|
323
482
|
),
|
|
324
|
-
/* @__PURE__ */
|
|
325
|
-
|
|
483
|
+
/* @__PURE__ */ jsxs4(
|
|
484
|
+
Button4,
|
|
326
485
|
{
|
|
327
486
|
type: "button",
|
|
328
487
|
variant: "ghost",
|
|
329
488
|
size: "sm",
|
|
330
489
|
onClick: () => setDisplay("lightbox"),
|
|
331
|
-
className:
|
|
490
|
+
className: cn3(currentDisplay === "lightbox" && "bg-accent text-accent-foreground"),
|
|
332
491
|
title: t("editor.image.lightboxTitle"),
|
|
333
492
|
children: [
|
|
334
|
-
/* @__PURE__ */
|
|
493
|
+
/* @__PURE__ */ jsx4(Maximize2, { className: "mr-1 h-3 w-3" }),
|
|
335
494
|
t("editor.image.lightbox")
|
|
336
495
|
]
|
|
337
496
|
}
|
|
338
497
|
),
|
|
339
|
-
/* @__PURE__ */
|
|
340
|
-
/* @__PURE__ */
|
|
341
|
-
/* @__PURE__ */
|
|
498
|
+
/* @__PURE__ */ jsx4("span", { className: "mx-1 h-4 w-px bg-border" }),
|
|
499
|
+
/* @__PURE__ */ jsxs4(Button4, { type: "button", variant: "ghost", size: "sm", onClick: editAlt, children: [
|
|
500
|
+
/* @__PURE__ */ jsx4(Pencil, { className: "mr-1 h-3 w-3" }),
|
|
342
501
|
t("editor.image.alt")
|
|
343
502
|
] }),
|
|
344
|
-
/* @__PURE__ */
|
|
345
|
-
/* @__PURE__ */
|
|
503
|
+
/* @__PURE__ */ jsxs4(Button4, { type: "button", variant: "ghost", size: "sm", onClick: remove2, children: [
|
|
504
|
+
/* @__PURE__ */ jsx4(Trash2, { className: "mr-1 h-3 w-3" }),
|
|
346
505
|
t("editor.image.delete")
|
|
347
506
|
] })
|
|
348
507
|
] })
|
|
@@ -351,7 +510,7 @@ function ImageBubbleMenu({ editor }) {
|
|
|
351
510
|
}
|
|
352
511
|
|
|
353
512
|
// src/editor/tiptap-editor.tsx
|
|
354
|
-
import { jsx as
|
|
513
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
355
514
|
var AmplessImage = Image.extend({
|
|
356
515
|
addAttributes() {
|
|
357
516
|
return {
|
|
@@ -367,12 +526,97 @@ var AmplessImage = Image.extend({
|
|
|
367
526
|
};
|
|
368
527
|
}
|
|
369
528
|
});
|
|
529
|
+
var EDITOR_STYLES = `
|
|
530
|
+
.ProseMirror .tiptap-table,
|
|
531
|
+
.ProseMirror table {
|
|
532
|
+
border-collapse: collapse;
|
|
533
|
+
table-layout: fixed;
|
|
534
|
+
width: 100%;
|
|
535
|
+
margin: 0.75em 0;
|
|
536
|
+
overflow: hidden;
|
|
537
|
+
}
|
|
538
|
+
.ProseMirror .tiptap-table td,
|
|
539
|
+
.ProseMirror .tiptap-table th,
|
|
540
|
+
.ProseMirror table td,
|
|
541
|
+
.ProseMirror table th {
|
|
542
|
+
border: 1px solid var(--border);
|
|
543
|
+
padding: 0.4em 0.6em;
|
|
544
|
+
min-width: 1em;
|
|
545
|
+
vertical-align: top;
|
|
546
|
+
position: relative;
|
|
547
|
+
}
|
|
548
|
+
.ProseMirror .tiptap-table th,
|
|
549
|
+
.ProseMirror table th {
|
|
550
|
+
background: var(--muted);
|
|
551
|
+
font-weight: 600;
|
|
552
|
+
text-align: left;
|
|
553
|
+
}
|
|
554
|
+
.ProseMirror .tiptap-table .selectedCell,
|
|
555
|
+
.ProseMirror table .selectedCell {
|
|
556
|
+
background: var(--accent);
|
|
557
|
+
}
|
|
558
|
+
.ProseMirror .tableWrapper {
|
|
559
|
+
overflow-x: auto;
|
|
560
|
+
margin: 0.75em 0;
|
|
561
|
+
}
|
|
562
|
+
.ProseMirror .column-resize-handle {
|
|
563
|
+
position: absolute;
|
|
564
|
+
right: -2px;
|
|
565
|
+
top: 0;
|
|
566
|
+
bottom: 0;
|
|
567
|
+
width: 4px;
|
|
568
|
+
background: var(--ring);
|
|
569
|
+
pointer-events: none;
|
|
570
|
+
}
|
|
571
|
+
.ProseMirror.resize-cursor {
|
|
572
|
+
cursor: col-resize;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
.ProseMirror ul[data-type='taskList'] {
|
|
576
|
+
list-style: none;
|
|
577
|
+
padding-left: 0;
|
|
578
|
+
}
|
|
579
|
+
.ProseMirror ul[data-type='taskList'] li {
|
|
580
|
+
display: flex;
|
|
581
|
+
align-items: flex-start;
|
|
582
|
+
gap: 0.5em;
|
|
583
|
+
}
|
|
584
|
+
.ProseMirror ul[data-type='taskList'] li > label {
|
|
585
|
+
flex: 0 0 auto;
|
|
586
|
+
margin-top: 0.25em;
|
|
587
|
+
user-select: none;
|
|
588
|
+
}
|
|
589
|
+
.ProseMirror ul[data-type='taskList'] li > div {
|
|
590
|
+
flex: 1 1 auto;
|
|
591
|
+
min-width: 0;
|
|
592
|
+
}
|
|
593
|
+
.ProseMirror ul[data-type='taskList'] li[data-checked='true'] > div {
|
|
594
|
+
text-decoration: line-through;
|
|
595
|
+
color: var(--muted-foreground);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
.ProseMirror mark {
|
|
599
|
+
background: #fef08a;
|
|
600
|
+
color: inherit;
|
|
601
|
+
padding: 0 0.1em;
|
|
602
|
+
border-radius: 2px;
|
|
603
|
+
}
|
|
604
|
+
`;
|
|
370
605
|
function TiptapEditor({ initialContent, onChange }) {
|
|
371
606
|
const editor = useEditor({
|
|
372
607
|
extensions: [
|
|
373
608
|
StarterKit,
|
|
374
609
|
Link.configure({ openOnClick: false }),
|
|
375
|
-
AmplessImage.configure({ inline: false, allowBase64: false })
|
|
610
|
+
AmplessImage.configure({ inline: false, allowBase64: false }),
|
|
611
|
+
Table.configure({ resizable: true, HTMLAttributes: { class: "tiptap-table" } }),
|
|
612
|
+
TableRow,
|
|
613
|
+
TableHeader,
|
|
614
|
+
TableCell,
|
|
615
|
+
TaskList,
|
|
616
|
+
TaskItem.configure({ nested: true }),
|
|
617
|
+
Underline2,
|
|
618
|
+
Highlight.configure({ multicolor: false }),
|
|
619
|
+
TextAlign.configure({ types: ["heading", "paragraph"] })
|
|
376
620
|
],
|
|
377
621
|
content: initialContent ?? { type: "doc", content: [{ type: "paragraph" }] },
|
|
378
622
|
immediatelyRender: false,
|
|
@@ -388,17 +632,18 @@ function TiptapEditor({ initialContent, onChange }) {
|
|
|
388
632
|
onChange?.(editor2.getJSON());
|
|
389
633
|
}
|
|
390
634
|
});
|
|
391
|
-
return /* @__PURE__ */
|
|
392
|
-
/* @__PURE__ */
|
|
393
|
-
|
|
394
|
-
/* @__PURE__ */
|
|
635
|
+
return /* @__PURE__ */ jsxs5("div", { className: "rounded-md border", children: [
|
|
636
|
+
/* @__PURE__ */ jsx5("style", { children: EDITOR_STYLES }),
|
|
637
|
+
/* @__PURE__ */ jsx5(Toolbar, { editor }),
|
|
638
|
+
editor && /* @__PURE__ */ jsx5(ImageBubbleMenu, { editor }),
|
|
639
|
+
/* @__PURE__ */ jsx5(EditorContent, { editor })
|
|
395
640
|
] });
|
|
396
641
|
}
|
|
397
642
|
|
|
398
643
|
// src/components/static-uploader.tsx
|
|
399
|
-
import { useState as
|
|
644
|
+
import { useState as useState3 } from "react";
|
|
400
645
|
import { FileText, AlertTriangle, FileArchive, X } from "lucide-react";
|
|
401
|
-
import { Button as
|
|
646
|
+
import { Button as Button5 } from "@ampless/runtime/ui";
|
|
402
647
|
|
|
403
648
|
// src/lib/static-bundle.ts
|
|
404
649
|
import JSZip from "jszip";
|
|
@@ -590,13 +835,13 @@ function pickDefaultEntrypoint(files) {
|
|
|
590
835
|
}
|
|
591
836
|
|
|
592
837
|
// src/components/static-uploader.tsx
|
|
593
|
-
import { jsx as
|
|
838
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
594
839
|
function StaticUploader({ initial, onFilesReady, onClear }) {
|
|
595
840
|
const t = useT();
|
|
596
|
-
const [pending, setPending] =
|
|
597
|
-
const [issues, setIssues] =
|
|
598
|
-
const [busy, setBusy] =
|
|
599
|
-
const [error, setError] =
|
|
841
|
+
const [pending, setPending] = useState3(null);
|
|
842
|
+
const [issues, setIssues] = useState3([]);
|
|
843
|
+
const [busy, setBusy] = useState3(false);
|
|
844
|
+
const [error, setError] = useState3(null);
|
|
600
845
|
async function handleZip(file) {
|
|
601
846
|
setBusy(true);
|
|
602
847
|
setError(null);
|
|
@@ -670,11 +915,11 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
|
|
|
670
915
|
onClear();
|
|
671
916
|
}
|
|
672
917
|
const showCurrent = !pending && initial && initial.files.length > 0;
|
|
673
|
-
return /* @__PURE__ */
|
|
674
|
-
/* @__PURE__ */
|
|
675
|
-
/* @__PURE__ */
|
|
676
|
-
/* @__PURE__ */
|
|
677
|
-
/* @__PURE__ */
|
|
918
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-4", children: [
|
|
919
|
+
/* @__PURE__ */ jsxs6("div", { className: "rounded-md border border-dashed p-4", children: [
|
|
920
|
+
/* @__PURE__ */ jsxs6("label", { className: "flex flex-col items-start gap-2 text-sm", children: [
|
|
921
|
+
/* @__PURE__ */ jsx6("span", { className: "font-medium", children: t("posts.form.static.pick") }),
|
|
922
|
+
/* @__PURE__ */ jsx6(
|
|
678
923
|
"input",
|
|
679
924
|
{
|
|
680
925
|
type: "file",
|
|
@@ -684,13 +929,13 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
|
|
|
684
929
|
disabled: busy
|
|
685
930
|
}
|
|
686
931
|
),
|
|
687
|
-
/* @__PURE__ */
|
|
932
|
+
/* @__PURE__ */ jsx6("span", { className: "text-xs text-muted-foreground", children: t("posts.form.static.pickHint") })
|
|
688
933
|
] }),
|
|
689
|
-
busy && /* @__PURE__ */
|
|
690
|
-
error && /* @__PURE__ */
|
|
934
|
+
busy && /* @__PURE__ */ jsx6("p", { className: "mt-2 text-sm text-muted-foreground", children: t("common.loading") }),
|
|
935
|
+
error && /* @__PURE__ */ jsx6("p", { className: "mt-2 text-sm text-destructive", children: error })
|
|
691
936
|
] }),
|
|
692
|
-
showCurrent && /* @__PURE__ */
|
|
693
|
-
pending && /* @__PURE__ */
|
|
937
|
+
showCurrent && /* @__PURE__ */ jsx6(CurrentBundle, { body: initial }),
|
|
938
|
+
pending && /* @__PURE__ */ jsx6(
|
|
694
939
|
PendingBundle,
|
|
695
940
|
{
|
|
696
941
|
files: pending,
|
|
@@ -702,15 +947,15 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
|
|
|
702
947
|
}
|
|
703
948
|
function CurrentBundle({ body }) {
|
|
704
949
|
const t = useT();
|
|
705
|
-
return /* @__PURE__ */
|
|
706
|
-
/* @__PURE__ */
|
|
707
|
-
/* @__PURE__ */
|
|
950
|
+
return /* @__PURE__ */ jsxs6("div", { className: "rounded-md border bg-muted/30 p-3", children: [
|
|
951
|
+
/* @__PURE__ */ jsxs6("div", { className: "mb-2 flex items-center gap-2 text-sm font-medium", children: [
|
|
952
|
+
/* @__PURE__ */ jsx6(FileArchive, { className: "h-4 w-4" }),
|
|
708
953
|
t("posts.form.static.currentBundle", {
|
|
709
954
|
count: body.files.length,
|
|
710
955
|
entrypoint: body.entrypoint
|
|
711
956
|
})
|
|
712
957
|
] }),
|
|
713
|
-
/* @__PURE__ */
|
|
958
|
+
/* @__PURE__ */ jsx6(FileList, { files: body.files })
|
|
714
959
|
] });
|
|
715
960
|
}
|
|
716
961
|
function PendingBundle({
|
|
@@ -720,49 +965,49 @@ function PendingBundle({
|
|
|
720
965
|
}) {
|
|
721
966
|
const t = useT();
|
|
722
967
|
const totalBytes = files.reduce((sum, f) => sum + f.data.byteLength, 0);
|
|
723
|
-
return /* @__PURE__ */
|
|
724
|
-
/* @__PURE__ */
|
|
725
|
-
/* @__PURE__ */
|
|
726
|
-
/* @__PURE__ */
|
|
968
|
+
return /* @__PURE__ */ jsxs6("div", { className: "rounded-md border p-3", children: [
|
|
969
|
+
/* @__PURE__ */ jsxs6("div", { className: "mb-2 flex items-center justify-between gap-2 text-sm font-medium", children: [
|
|
970
|
+
/* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-2", children: [
|
|
971
|
+
/* @__PURE__ */ jsx6(FileArchive, { className: "h-4 w-4" }),
|
|
727
972
|
t("posts.form.static.pendingBundle", {
|
|
728
973
|
count: files.length,
|
|
729
974
|
size: formatBytes(totalBytes)
|
|
730
975
|
})
|
|
731
976
|
] }),
|
|
732
|
-
/* @__PURE__ */
|
|
733
|
-
/* @__PURE__ */
|
|
977
|
+
/* @__PURE__ */ jsxs6(Button5, { type: "button", variant: "ghost", size: "sm", onClick: onClear, children: [
|
|
978
|
+
/* @__PURE__ */ jsx6(X, { className: "mr-1 h-3 w-3" }),
|
|
734
979
|
t("common.cancel")
|
|
735
980
|
] })
|
|
736
981
|
] }),
|
|
737
|
-
issues.length > 0 && /* @__PURE__ */
|
|
738
|
-
/* @__PURE__ */
|
|
739
|
-
/* @__PURE__ */
|
|
982
|
+
issues.length > 0 && /* @__PURE__ */ jsxs6("div", { className: "mb-3 rounded-md border border-destructive/40 bg-destructive/5 p-2 text-sm", children: [
|
|
983
|
+
/* @__PURE__ */ jsxs6("div", { className: "mb-1 flex items-center gap-2 font-medium text-destructive", children: [
|
|
984
|
+
/* @__PURE__ */ jsx6(AlertTriangle, { className: "h-4 w-4" }),
|
|
740
985
|
t("posts.form.static.issuesTitle", { count: issues.length })
|
|
741
986
|
] }),
|
|
742
|
-
/* @__PURE__ */
|
|
743
|
-
issues.slice(0, 20).map((issue, idx) => /* @__PURE__ */
|
|
987
|
+
/* @__PURE__ */ jsxs6("ul", { className: "space-y-0.5 text-xs", children: [
|
|
988
|
+
issues.slice(0, 20).map((issue, idx) => /* @__PURE__ */ jsxs6("li", { className: "font-mono", children: [
|
|
744
989
|
issue.path,
|
|
745
990
|
": ",
|
|
746
991
|
issue.reason
|
|
747
992
|
] }, `${issue.path}-${idx}`)),
|
|
748
|
-
issues.length > 20 && /* @__PURE__ */
|
|
993
|
+
issues.length > 20 && /* @__PURE__ */ jsxs6("li", { className: "font-mono text-muted-foreground", children: [
|
|
749
994
|
"\u2026 ",
|
|
750
995
|
issues.length - 20,
|
|
751
996
|
" more"
|
|
752
997
|
] })
|
|
753
998
|
] }),
|
|
754
|
-
/* @__PURE__ */
|
|
999
|
+
/* @__PURE__ */ jsx6("p", { className: "mt-2 text-xs text-muted-foreground", children: t("posts.form.static.issuesHint") })
|
|
755
1000
|
] }),
|
|
756
|
-
/* @__PURE__ */
|
|
1001
|
+
/* @__PURE__ */ jsx6(FileList, { files: files.map((f) => f.path) })
|
|
757
1002
|
] });
|
|
758
1003
|
}
|
|
759
1004
|
function FileList({ files }) {
|
|
760
|
-
return /* @__PURE__ */
|
|
761
|
-
files.slice(0, 40).map((path) => /* @__PURE__ */
|
|
762
|
-
/* @__PURE__ */
|
|
1005
|
+
return /* @__PURE__ */ jsxs6("ul", { className: "space-y-0.5 text-xs", children: [
|
|
1006
|
+
files.slice(0, 40).map((path) => /* @__PURE__ */ jsxs6("li", { className: "flex items-center gap-1.5 font-mono text-muted-foreground", children: [
|
|
1007
|
+
/* @__PURE__ */ jsx6(FileText, { className: "h-3 w-3 shrink-0" }),
|
|
763
1008
|
path
|
|
764
1009
|
] }, path)),
|
|
765
|
-
files.length > 40 && /* @__PURE__ */
|
|
1010
|
+
files.length > 40 && /* @__PURE__ */ jsxs6("li", { className: "font-mono text-xs text-muted-foreground", children: [
|
|
766
1011
|
"\u2026 ",
|
|
767
1012
|
files.length - 40,
|
|
768
1013
|
" more"
|
|
@@ -785,7 +1030,7 @@ function guessEntrypoint(files) {
|
|
|
785
1030
|
}
|
|
786
1031
|
|
|
787
1032
|
// src/components/post-form.tsx
|
|
788
|
-
import { jsx as
|
|
1033
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
789
1034
|
var EMPTY_TIPTAP_DOC = { type: "doc", content: [{ type: "paragraph" }] };
|
|
790
1035
|
var IMAGE_URL_RE = /\.(jpe?g|png|gif|webp|avif|svg|bmp|tiff?)(\?|$)/i;
|
|
791
1036
|
var STYLESHEET_URL_RE = /\.css(\?|$)/i;
|
|
@@ -815,19 +1060,19 @@ function PostForm({ post }) {
|
|
|
815
1060
|
const router = useRouter();
|
|
816
1061
|
const t = useT();
|
|
817
1062
|
const isEdit = !!post;
|
|
818
|
-
const bodyTextareaRef =
|
|
819
|
-
const [title, setTitle] =
|
|
820
|
-
const [slug, setSlug] =
|
|
821
|
-
const [excerpt, setExcerpt] =
|
|
822
|
-
const [format, setFormat] =
|
|
823
|
-
const [body, setBody] =
|
|
824
|
-
const [status, setStatus] =
|
|
825
|
-
const [tagsInput, setTagsInput] =
|
|
826
|
-
const [noLayout, setNoLayout] =
|
|
827
|
-
const [saving, setSaving] =
|
|
828
|
-
const [error, setError] =
|
|
829
|
-
const [view, setView] =
|
|
830
|
-
const [pendingBundle, setPendingBundle] =
|
|
1063
|
+
const bodyTextareaRef = useRef3(null);
|
|
1064
|
+
const [title, setTitle] = useState4(post?.title ?? "");
|
|
1065
|
+
const [slug, setSlug] = useState4(post?.slug ?? "");
|
|
1066
|
+
const [excerpt, setExcerpt] = useState4(post?.excerpt ?? "");
|
|
1067
|
+
const [format, setFormat] = useState4(post?.format ?? "tiptap");
|
|
1068
|
+
const [body, setBody] = useState4(post?.body ?? EMPTY_TIPTAP_DOC);
|
|
1069
|
+
const [status, setStatus] = useState4(post?.status ?? "draft");
|
|
1070
|
+
const [tagsInput, setTagsInput] = useState4((post?.tags ?? []).join(", "));
|
|
1071
|
+
const [noLayout, setNoLayout] = useState4(post?.metadata?.no_layout === true);
|
|
1072
|
+
const [saving, setSaving] = useState4(false);
|
|
1073
|
+
const [error, setError] = useState4(null);
|
|
1074
|
+
const [view, setView] = useState4("edit");
|
|
1075
|
+
const [pendingBundle, setPendingBundle] = useState4(null);
|
|
831
1076
|
const initialStaticBody = isStaticBody(post?.body) ? post.body : null;
|
|
832
1077
|
function buildMetadata() {
|
|
833
1078
|
const next = { ...post?.metadata ?? {} };
|
|
@@ -988,9 +1233,9 @@ function PostForm({ post }) {
|
|
|
988
1233
|
publishedAt: status === "published" ? post?.publishedAt ?? (/* @__PURE__ */ new Date()).toISOString() : void 0,
|
|
989
1234
|
tags: parseTags(tagsInput)
|
|
990
1235
|
};
|
|
991
|
-
return /* @__PURE__ */
|
|
992
|
-
/* @__PURE__ */
|
|
993
|
-
/* @__PURE__ */
|
|
1236
|
+
return /* @__PURE__ */ jsxs7("form", { onSubmit: save, className: "space-y-6", children: [
|
|
1237
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex gap-1 border-b", children: [
|
|
1238
|
+
/* @__PURE__ */ jsx7(
|
|
994
1239
|
"button",
|
|
995
1240
|
{
|
|
996
1241
|
type: "button",
|
|
@@ -1000,7 +1245,7 @@ function PostForm({ post }) {
|
|
|
1000
1245
|
children: t("posts.form.tabEdit")
|
|
1001
1246
|
}
|
|
1002
1247
|
),
|
|
1003
|
-
/* @__PURE__ */
|
|
1248
|
+
/* @__PURE__ */ jsx7(
|
|
1004
1249
|
"button",
|
|
1005
1250
|
{
|
|
1006
1251
|
type: "button",
|
|
@@ -1011,24 +1256,24 @@ function PostForm({ post }) {
|
|
|
1011
1256
|
}
|
|
1012
1257
|
)
|
|
1013
1258
|
] }),
|
|
1014
|
-
view === "preview" && /* @__PURE__ */
|
|
1015
|
-
/* @__PURE__ */
|
|
1016
|
-
/* @__PURE__ */
|
|
1017
|
-
/* @__PURE__ */
|
|
1018
|
-
previewPost.publishedAt ? /* @__PURE__ */
|
|
1019
|
-
/* @__PURE__ */
|
|
1020
|
-
/* @__PURE__ */
|
|
1259
|
+
view === "preview" && /* @__PURE__ */ jsxs7("article", { className: "space-y-4", children: [
|
|
1260
|
+
/* @__PURE__ */ jsxs7("header", { className: "border-b pb-4", children: [
|
|
1261
|
+
/* @__PURE__ */ jsx7("h1", { className: "text-3xl font-bold tracking-tight", children: title || /* @__PURE__ */ jsx7("span", { className: "text-muted-foreground italic", children: t("posts.form.previewNoTitle") }) }),
|
|
1262
|
+
/* @__PURE__ */ jsxs7("p", { className: "mt-2 text-sm text-muted-foreground", children: [
|
|
1263
|
+
previewPost.publishedAt ? /* @__PURE__ */ jsx7("time", { dateTime: previewPost.publishedAt, children: formatDate(previewPost.publishedAt) }) : /* @__PURE__ */ jsx7("span", { children: t("common.draft") }),
|
|
1264
|
+
/* @__PURE__ */ jsx7("span", { className: "mx-2", children: "\xB7" }),
|
|
1265
|
+
/* @__PURE__ */ jsx7("span", { className: "font-mono text-xs uppercase", children: format })
|
|
1021
1266
|
] }),
|
|
1022
|
-
excerpt && /* @__PURE__ */
|
|
1267
|
+
excerpt && /* @__PURE__ */ jsx7("p", { className: "mt-3 text-base text-muted-foreground", children: excerpt })
|
|
1023
1268
|
] }),
|
|
1024
|
-
format === "static" ? /* @__PURE__ */
|
|
1269
|
+
format === "static" ? /* @__PURE__ */ jsx7("p", { className: "text-sm text-muted-foreground", children: t("posts.form.static.previewHint") }) : /* @__PURE__ */ jsx7(
|
|
1025
1270
|
"div",
|
|
1026
1271
|
{
|
|
1027
1272
|
className: "prose prose-neutral dark:prose-invert max-w-none",
|
|
1028
1273
|
dangerouslySetInnerHTML: { __html: renderBody(previewPost) }
|
|
1029
1274
|
}
|
|
1030
1275
|
),
|
|
1031
|
-
previewPost.tags && previewPost.tags.length > 0 && /* @__PURE__ */
|
|
1276
|
+
previewPost.tags && previewPost.tags.length > 0 && /* @__PURE__ */ jsx7("div", { className: "flex flex-wrap gap-2 border-t pt-4 text-sm", children: previewPost.tags.map((tag) => /* @__PURE__ */ jsxs7(
|
|
1032
1277
|
"span",
|
|
1033
1278
|
{
|
|
1034
1279
|
className: "rounded-full border px-2 py-0.5 text-xs text-muted-foreground",
|
|
@@ -1039,12 +1284,12 @@ function PostForm({ post }) {
|
|
|
1039
1284
|
},
|
|
1040
1285
|
tag
|
|
1041
1286
|
)) }),
|
|
1042
|
-
/* @__PURE__ */
|
|
1287
|
+
/* @__PURE__ */ jsx7("p", { className: "text-xs text-muted-foreground", children: t("posts.form.previewHint") })
|
|
1043
1288
|
] }),
|
|
1044
|
-
/* @__PURE__ */
|
|
1045
|
-
/* @__PURE__ */
|
|
1046
|
-
/* @__PURE__ */
|
|
1047
|
-
/* @__PURE__ */
|
|
1289
|
+
/* @__PURE__ */ jsxs7("div", { className: view === "edit" ? "space-y-6" : "hidden", children: [
|
|
1290
|
+
/* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
|
|
1291
|
+
/* @__PURE__ */ jsx7(Label, { htmlFor: "title", children: t("posts.form.title") }),
|
|
1292
|
+
/* @__PURE__ */ jsx7(
|
|
1048
1293
|
Input,
|
|
1049
1294
|
{
|
|
1050
1295
|
id: "title",
|
|
@@ -1057,9 +1302,9 @@ function PostForm({ post }) {
|
|
|
1057
1302
|
}
|
|
1058
1303
|
)
|
|
1059
1304
|
] }),
|
|
1060
|
-
/* @__PURE__ */
|
|
1061
|
-
/* @__PURE__ */
|
|
1062
|
-
/* @__PURE__ */
|
|
1305
|
+
/* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
|
|
1306
|
+
/* @__PURE__ */ jsx7(Label, { htmlFor: "slug", children: t("posts.form.slug") }),
|
|
1307
|
+
/* @__PURE__ */ jsx7(
|
|
1063
1308
|
Input,
|
|
1064
1309
|
{
|
|
1065
1310
|
id: "slug",
|
|
@@ -1069,9 +1314,9 @@ function PostForm({ post }) {
|
|
|
1069
1314
|
}
|
|
1070
1315
|
)
|
|
1071
1316
|
] }),
|
|
1072
|
-
/* @__PURE__ */
|
|
1073
|
-
/* @__PURE__ */
|
|
1074
|
-
/* @__PURE__ */
|
|
1317
|
+
/* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
|
|
1318
|
+
/* @__PURE__ */ jsx7(Label, { htmlFor: "excerpt", children: t("posts.form.excerpt") }),
|
|
1319
|
+
/* @__PURE__ */ jsx7(
|
|
1075
1320
|
Textarea,
|
|
1076
1321
|
{
|
|
1077
1322
|
id: "excerpt",
|
|
@@ -1081,9 +1326,9 @@ function PostForm({ post }) {
|
|
|
1081
1326
|
}
|
|
1082
1327
|
)
|
|
1083
1328
|
] }),
|
|
1084
|
-
/* @__PURE__ */
|
|
1085
|
-
/* @__PURE__ */
|
|
1086
|
-
/* @__PURE__ */
|
|
1329
|
+
/* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
|
|
1330
|
+
/* @__PURE__ */ jsx7(Label, { htmlFor: "format", children: t("posts.form.format") }),
|
|
1331
|
+
/* @__PURE__ */ jsxs7(
|
|
1087
1332
|
"select",
|
|
1088
1333
|
{
|
|
1089
1334
|
id: "format",
|
|
@@ -1091,41 +1336,41 @@ function PostForm({ post }) {
|
|
|
1091
1336
|
onChange: (e) => changeFormat(e.target.value),
|
|
1092
1337
|
className: "flex h-9 w-full max-w-xs rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm",
|
|
1093
1338
|
children: [
|
|
1094
|
-
/* @__PURE__ */
|
|
1095
|
-
/* @__PURE__ */
|
|
1096
|
-
/* @__PURE__ */
|
|
1097
|
-
/* @__PURE__ */
|
|
1339
|
+
/* @__PURE__ */ jsx7("option", { value: "tiptap", children: "Tiptap (rich editor)" }),
|
|
1340
|
+
/* @__PURE__ */ jsx7("option", { value: "markdown", children: "Markdown" }),
|
|
1341
|
+
/* @__PURE__ */ jsx7("option", { value: "html", children: "HTML" }),
|
|
1342
|
+
/* @__PURE__ */ jsx7("option", { value: "static", children: t("posts.form.formatStaticLabel") })
|
|
1098
1343
|
]
|
|
1099
1344
|
}
|
|
1100
1345
|
),
|
|
1101
|
-
/* @__PURE__ */
|
|
1346
|
+
/* @__PURE__ */ jsx7("p", { className: "text-xs text-muted-foreground", children: t("posts.form.formatHint") })
|
|
1102
1347
|
] }),
|
|
1103
|
-
/* @__PURE__ */
|
|
1104
|
-
/* @__PURE__ */
|
|
1105
|
-
/* @__PURE__ */
|
|
1348
|
+
/* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
|
|
1349
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between", children: [
|
|
1350
|
+
/* @__PURE__ */ jsx7(Label, { children: t("posts.form.body") }),
|
|
1106
1351
|
format !== "tiptap" && format !== "static" && // For textarea-based formats (markdown / html) there's no
|
|
1107
1352
|
// embedded toolbar, so we surface the MediaPicker as a
|
|
1108
1353
|
// standalone button. Selecting an asset inserts a
|
|
1109
1354
|
// format-aware snippet at the cursor.
|
|
1110
|
-
/* @__PURE__ */
|
|
1355
|
+
/* @__PURE__ */ jsx7(
|
|
1111
1356
|
MediaPicker,
|
|
1112
1357
|
{
|
|
1113
1358
|
onSelect: insertMediaSnippet,
|
|
1114
|
-
trigger: /* @__PURE__ */
|
|
1115
|
-
/* @__PURE__ */
|
|
1359
|
+
trigger: /* @__PURE__ */ jsxs7(Button6, { type: "button", variant: "outline", size: "sm", children: [
|
|
1360
|
+
/* @__PURE__ */ jsx7(ImageIcon3, { className: "mr-2 h-3 w-3" }),
|
|
1116
1361
|
t("posts.form.insertMedia")
|
|
1117
1362
|
] })
|
|
1118
1363
|
}
|
|
1119
1364
|
)
|
|
1120
1365
|
] }),
|
|
1121
|
-
format === "tiptap" ? /* @__PURE__ */
|
|
1366
|
+
format === "tiptap" ? /* @__PURE__ */ jsx7(TiptapEditor, { initialContent: body, onChange: setBody }) : format === "static" ? /* @__PURE__ */ jsx7(
|
|
1122
1367
|
StaticUploader,
|
|
1123
1368
|
{
|
|
1124
1369
|
initial: initialStaticBody,
|
|
1125
1370
|
onFilesReady: (files, entrypoint) => setPendingBundle({ files, entrypoint }),
|
|
1126
1371
|
onClear: () => setPendingBundle(null)
|
|
1127
1372
|
}
|
|
1128
|
-
) : /* @__PURE__ */
|
|
1373
|
+
) : /* @__PURE__ */ jsx7(
|
|
1129
1374
|
Textarea,
|
|
1130
1375
|
{
|
|
1131
1376
|
ref: bodyTextareaRef,
|
|
@@ -1136,9 +1381,9 @@ function PostForm({ post }) {
|
|
|
1136
1381
|
}
|
|
1137
1382
|
)
|
|
1138
1383
|
] }),
|
|
1139
|
-
/* @__PURE__ */
|
|
1140
|
-
/* @__PURE__ */
|
|
1141
|
-
/* @__PURE__ */
|
|
1384
|
+
/* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
|
|
1385
|
+
/* @__PURE__ */ jsx7(Label, { htmlFor: "tags", children: t("posts.form.tags") }),
|
|
1386
|
+
/* @__PURE__ */ jsx7(
|
|
1142
1387
|
Input,
|
|
1143
1388
|
{
|
|
1144
1389
|
id: "tags",
|
|
@@ -1147,11 +1392,11 @@ function PostForm({ post }) {
|
|
|
1147
1392
|
placeholder: t("posts.form.tagsPlaceholder")
|
|
1148
1393
|
}
|
|
1149
1394
|
),
|
|
1150
|
-
/* @__PURE__ */
|
|
1395
|
+
/* @__PURE__ */ jsx7("p", { className: "text-xs text-muted-foreground", children: t("posts.form.tagsHint") })
|
|
1151
1396
|
] }),
|
|
1152
|
-
/* @__PURE__ */
|
|
1153
|
-
/* @__PURE__ */
|
|
1154
|
-
/* @__PURE__ */
|
|
1397
|
+
/* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
|
|
1398
|
+
/* @__PURE__ */ jsx7(Label, { htmlFor: "status", children: t("posts.form.status") }),
|
|
1399
|
+
/* @__PURE__ */ jsxs7(
|
|
1155
1400
|
"select",
|
|
1156
1401
|
{
|
|
1157
1402
|
id: "status",
|
|
@@ -1159,14 +1404,14 @@ function PostForm({ post }) {
|
|
|
1159
1404
|
onChange: (e) => setStatus(e.target.value),
|
|
1160
1405
|
className: "flex h-9 w-full max-w-xs rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm",
|
|
1161
1406
|
children: [
|
|
1162
|
-
/* @__PURE__ */
|
|
1163
|
-
/* @__PURE__ */
|
|
1407
|
+
/* @__PURE__ */ jsx7("option", { value: "draft", children: t("common.draft") }),
|
|
1408
|
+
/* @__PURE__ */ jsx7("option", { value: "published", children: t("common.published") })
|
|
1164
1409
|
]
|
|
1165
1410
|
}
|
|
1166
1411
|
)
|
|
1167
1412
|
] }),
|
|
1168
|
-
format === "html" && /* @__PURE__ */
|
|
1169
|
-
/* @__PURE__ */
|
|
1413
|
+
format === "html" && /* @__PURE__ */ jsx7("div", { className: "space-y-2", children: /* @__PURE__ */ jsxs7("label", { className: "flex items-start gap-2 text-sm", children: [
|
|
1414
|
+
/* @__PURE__ */ jsx7(
|
|
1170
1415
|
"input",
|
|
1171
1416
|
{
|
|
1172
1417
|
type: "checkbox",
|
|
@@ -1175,15 +1420,15 @@ function PostForm({ post }) {
|
|
|
1175
1420
|
className: "mt-1"
|
|
1176
1421
|
}
|
|
1177
1422
|
),
|
|
1178
|
-
/* @__PURE__ */
|
|
1179
|
-
/* @__PURE__ */
|
|
1180
|
-
/* @__PURE__ */
|
|
1423
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
1424
|
+
/* @__PURE__ */ jsx7("span", { className: "font-medium", children: t("posts.form.noLayout") }),
|
|
1425
|
+
/* @__PURE__ */ jsx7("span", { className: "block text-xs text-muted-foreground", children: t("posts.form.noLayoutHint") })
|
|
1181
1426
|
] })
|
|
1182
1427
|
] }) }),
|
|
1183
|
-
error && /* @__PURE__ */
|
|
1184
|
-
/* @__PURE__ */
|
|
1185
|
-
/* @__PURE__ */
|
|
1186
|
-
isEdit && /* @__PURE__ */
|
|
1428
|
+
error && /* @__PURE__ */ jsx7("p", { className: "text-sm text-destructive", children: error }),
|
|
1429
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
|
|
1430
|
+
/* @__PURE__ */ jsx7(Button6, { type: "submit", disabled: saving, children: saving ? t("common.saving") : isEdit ? t("posts.form.saveChanges") : t("posts.form.createPost") }),
|
|
1431
|
+
isEdit && /* @__PURE__ */ jsx7(Button6, { type: "button", variant: "destructive", onClick: handleDelete, disabled: saving, children: t("posts.form.delete") })
|
|
1187
1432
|
] })
|
|
1188
1433
|
] })
|
|
1189
1434
|
] });
|