elseware-ui 2.31.1 → 2.31.2

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/index.mjs CHANGED
@@ -22,7 +22,7 @@ import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
22
22
  import { MdUpload, MdOutlineDone, MdOutlineRemoveCircleOutline } from 'react-icons/md';
23
23
  import '@mdxeditor/editor/style.css';
24
24
  import { MDXEditor, headingsPlugin, linkPlugin, listsPlugin, imagePlugin, tablePlugin, linkDialogPlugin, thematicBreakPlugin, quotePlugin, toolbarPlugin, UndoRedo, Separator, BlockTypeSelect, BoldItalicUnderlineToggles, StrikeThroughSupSubToggles, ListsToggle, CreateLink, InsertImage, InsertTable, InsertThematicBreak, markdownShortcutPlugin, frontmatterPlugin, codeBlockPlugin, codeMirrorPlugin } from '@mdxeditor/editor';
25
- import { BiDotsVerticalRounded, BiEdit, BiTrash, BiFlag, BiLike, BiDislike, BiChevronDown, BiChevronUp } from 'react-icons/bi';
25
+ import { BiDotsVerticalRounded, BiEdit, BiTrash, BiFlag, BiSolidLike, BiLike, BiSolidDislike, BiDislike, BiChevronDown, BiChevronUp } from 'react-icons/bi';
26
26
 
27
27
  // node_modules/clsx/dist/clsx.mjs
28
28
  function r(e) {
@@ -3104,7 +3104,7 @@ var ShapeSwitch = () => {
3104
3104
  {
3105
3105
  value: currentShape,
3106
3106
  onChange: handleChange,
3107
- className: "\r\n px-3 py-2 rounded-md border border-gray-300\r\n bg-white dark:bg-gray-800\r\n text-sm shadow-sm\r\n focus:outline-none\r\n ",
3107
+ className: "\n px-3 py-2 rounded-md border border-gray-300\n bg-white dark:bg-gray-800\n text-sm shadow-sm\n focus:outline-none\n ",
3108
3108
  children: Object.keys(Shape).map((shape) => /* @__PURE__ */ jsx("option", { value: shape, children: shape }, shape))
3109
3109
  }
3110
3110
  ) });
@@ -16098,7 +16098,7 @@ function MarkdownTOC({ title = "Table of Contents" }) {
16098
16098
  /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
16099
16099
  "h2",
16100
16100
  {
16101
- className: "\r\n text-sm\r\n font-semibold\r\n uppercase\r\n tracking-wide\r\n text-gray-900\r\n dark:text-gray-100\r\n ",
16101
+ className: "\n text-sm\n font-semibold\n uppercase\n tracking-wide\n text-gray-900\n dark:text-gray-100\n ",
16102
16102
  children: title
16103
16103
  }
16104
16104
  ) }),
@@ -17427,7 +17427,7 @@ var GlowWrapper = ({
17427
17427
  /* @__PURE__ */ jsx(
17428
17428
  "span",
17429
17429
  {
17430
- className: "\r\n pointer-events-none absolute inset-0 opacity-0 \r\n group-hover:opacity-100 transition-opacity duration-300\r\n ",
17430
+ className: "\n pointer-events-none absolute inset-0 opacity-0 \n group-hover:opacity-100 transition-opacity duration-300\n ",
17431
17431
  style: { background: "var(--glow-bg)" }
17432
17432
  }
17433
17433
  ),
@@ -17459,49 +17459,60 @@ function ShowMore({ text, limit }) {
17459
17459
  }
17460
17460
  var ShowMore_default = ShowMore;
17461
17461
  function CommentComposer({
17462
+ avatar,
17462
17463
  placeholder = "Add a comment...",
17463
17464
  submitLabel = "Comment",
17465
+ disabled,
17466
+ loading,
17464
17467
  onSubmit
17465
17468
  }) {
17466
17469
  const [value, setValue] = useState("");
17467
17470
  const [focused, setFocused] = useState(false);
17468
17471
  async function handleSubmit() {
17469
- if (!value.trim()) return;
17470
- await onSubmit?.(value);
17472
+ const content = value.trim();
17473
+ if (!content) {
17474
+ return;
17475
+ }
17476
+ await onSubmit?.(content);
17477
+ setValue("");
17478
+ setFocused(false);
17479
+ }
17480
+ function handleCancel() {
17471
17481
  setValue("");
17472
17482
  setFocused(false);
17473
17483
  }
17474
17484
  return /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
17475
- /* @__PURE__ */ jsx(Avatar, { size: "md" }),
17485
+ /* @__PURE__ */ jsx(Avatar, { src: avatar, size: "md" }),
17476
17486
  /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col gap-3", children: [
17477
17487
  /* @__PURE__ */ jsx(
17478
17488
  "textarea",
17479
17489
  {
17480
17490
  value,
17491
+ disabled: disabled || loading,
17481
17492
  placeholder,
17482
17493
  onFocus: () => setFocused(true),
17483
17494
  onChange: (e) => setValue(e.target.value),
17484
- className: "w-full min-h-[48px] bg-transparent border-b border-gray-300 dark:border-neutral-700 outline-none resize-none pb-2 text-sm"
17495
+ className: "\n w-full\n min-h-[56px]\n resize-none\n bg-transparent\n border-b\n border-gray-300\n dark:border-neutral-700\n outline-none\n pb-2\n text-sm\n "
17485
17496
  }
17486
17497
  ),
17487
17498
  (focused || value.length > 0) && /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
17488
17499
  /* @__PURE__ */ jsx(
17489
17500
  Button_default,
17490
17501
  {
17502
+ text: "Cancel",
17491
17503
  variant: "secondary",
17492
17504
  appearance: "ghost",
17493
- text: "Cancel",
17494
- onClick: () => {
17495
- setValue("");
17496
- setFocused(false);
17497
- }
17505
+ disabled: loading,
17506
+ onClick: handleCancel
17498
17507
  }
17499
17508
  ),
17500
17509
  /* @__PURE__ */ jsx(
17501
17510
  Button_default,
17502
17511
  {
17503
- variant: "primary",
17504
17512
  text: submitLabel,
17513
+ variant: "primary",
17514
+ loading,
17515
+ disabled: !value.trim(),
17505
17516
  onClick: handleSubmit
17506
17517
  }
17507
17518
  )
@@ -17510,6 +17521,78 @@ function CommentComposer({
17510
17521
  ] });
17511
17522
  }
17512
17523
  var CommentComposer_default = CommentComposer;
17524
+ function CommentActions({
17525
+ likes = 0,
17526
+ dislikes = 0,
17527
+ liked = false,
17528
+ disliked = false,
17529
+ canReply = true,
17530
+ onLike,
17531
+ onDislike,
17532
+ onReply
17533
+ }) {
17534
+ return /* @__PURE__ */ jsxs(
17535
+ "div",
17536
+ {
17537
+ className: "\n flex\n items-center\n gap-5\n text-sm\n text-gray-500\n dark:text-gray-400\n ",
17538
+ children: [
17539
+ /* @__PURE__ */ jsxs(
17540
+ "button",
17541
+ {
17542
+ onClick: onLike,
17543
+ className: `
17544
+ inline-flex
17545
+ items-center
17546
+ gap-1
17547
+ transition-colors
17548
+ ${liked ? "text-blue-500" : "hover:text-gray-900 dark:hover:text-gray-100"}
17549
+ `,
17550
+ children: [
17551
+ liked ? /* @__PURE__ */ jsx(BiSolidLike, { size: 18 }) : /* @__PURE__ */ jsx(BiLike, { size: 18 }),
17552
+ /* @__PURE__ */ jsx("span", { children: likes })
17553
+ ]
17554
+ }
17555
+ ),
17556
+ /* @__PURE__ */ jsxs(
17557
+ "button",
17558
+ {
17559
+ onClick: onDislike,
17560
+ className: `
17561
+ inline-flex
17562
+ items-center
17563
+ gap-1
17564
+ transition-colors
17565
+ ${disliked ? "text-red-500" : "hover:text-gray-900 dark:hover:text-gray-100"}
17566
+ `,
17567
+ children: [
17568
+ disliked ? /* @__PURE__ */ jsx(BiSolidDislike, { size: 18 }) : /* @__PURE__ */ jsx(BiDislike, { size: 18 }),
17569
+ /* @__PURE__ */ jsx("span", { children: dislikes })
17570
+ ]
17571
+ }
17572
+ ),
17573
+ canReply && /* @__PURE__ */ jsx(
17574
+ "button",
17575
+ {
17576
+ onClick: onReply,
17577
+ className: "\n font-medium\n transition-colors\n hover:text-gray-900\n dark:hover:text-gray-100\n ",
17578
+ children: "Reply"
17579
+ }
17580
+ )
17581
+ ]
17582
+ }
17583
+ );
17584
+ }
17585
+ var CommentActions_default = CommentActions;
17586
+ function CommentContent({ content }) {
17587
+ return /* @__PURE__ */ jsx(
17588
+ "div",
17589
+ {
17590
+ className: "\n text-sm\n leading-relaxed\n whitespace-pre-wrap\n break-words\n text-gray-700\n dark:text-gray-300\n ",
17591
+ children: content
17592
+ }
17593
+ );
17594
+ }
17595
+ var CommentContent_default = CommentContent;
17513
17596
 
17514
17597
  // src/compositions/comment-thread/utils/formatCommentDate.ts
17515
17598
  function formatCommentDate(date) {
@@ -17517,11 +17600,26 @@ function formatCommentDate(date) {
17517
17600
  const target = new Date(date);
17518
17601
  const seconds = Math.floor((now.getTime() - target.getTime()) / 1e3);
17519
17602
  const intervals = [
17520
- { label: "year", seconds: 31536e3 },
17521
- { label: "month", seconds: 2592e3 },
17522
- { label: "day", seconds: 86400 },
17523
- { label: "hour", seconds: 3600 },
17524
- { label: "minute", seconds: 60 }
17603
+ {
17604
+ label: "year",
17605
+ seconds: 31536e3
17606
+ },
17607
+ {
17608
+ label: "month",
17609
+ seconds: 2592e3
17610
+ },
17611
+ {
17612
+ label: "day",
17613
+ seconds: 86400
17614
+ },
17615
+ {
17616
+ label: "hour",
17617
+ seconds: 3600
17618
+ },
17619
+ {
17620
+ label: "minute",
17621
+ seconds: 60
17622
+ }
17525
17623
  ];
17526
17624
  for (const interval of intervals) {
17527
17625
  const count = Math.floor(seconds / interval.seconds);
@@ -17534,67 +17632,27 @@ function formatCommentDate(date) {
17534
17632
  function CommentHeader({
17535
17633
  avatar,
17536
17634
  username,
17635
+ firstName,
17636
+ lastName,
17537
17637
  createdAt,
17538
17638
  edited
17539
17639
  }) {
17640
+ const displayName = firstName || lastName ? `${firstName ?? ""} ${lastName ?? ""}`.trim() : username;
17540
17641
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
17541
17642
  /* @__PURE__ */ jsx(Avatar, { src: avatar, size: "sm" }),
17542
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm flex-wrap", children: [
17543
- /* @__PURE__ */ jsxs("span", { className: "font-semibold text-gray-900 dark:text-gray-100", children: [
17643
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap min-w-0", children: [
17644
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-sm text-gray-900 dark:text-gray-100", children: displayName }),
17645
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
17544
17646
  "@",
17545
17647
  username
17546
17648
  ] }),
17547
- /* @__PURE__ */ jsx("span", { className: "text-gray-500 dark:text-gray-400", children: formatCommentDate(createdAt) }),
17548
- edited && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400", children: "edited" })
17649
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "\xB7" }),
17650
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: formatCommentDate(createdAt) }),
17651
+ edited && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400 dark:text-gray-500", children: "(edited)" })
17549
17652
  ] })
17550
17653
  ] });
17551
17654
  }
17552
17655
  var CommentHeader_default = CommentHeader;
17553
- function CommentContent({ content }) {
17554
- return /* @__PURE__ */ jsx("div", { className: "text-sm leading-relaxed whitespace-pre-wrap text-gray-700 dark:text-gray-300", children: content });
17555
- }
17556
- var CommentContent_default = CommentContent;
17557
- function CommentActions({
17558
- likes = 0,
17559
- dislikes = 0,
17560
- onLike,
17561
- onDislike,
17562
- onReply
17563
- }) {
17564
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-5 text-sm text-gray-500 dark:text-gray-400", children: [
17565
- /* @__PURE__ */ jsxs(
17566
- "button",
17567
- {
17568
- onClick: onLike,
17569
- className: "inline-flex items-center gap-1 hover:text-gray-900 dark:hover:text-gray-100 transition-colors",
17570
- children: [
17571
- /* @__PURE__ */ jsx(BiLike, { size: 18 }),
17572
- /* @__PURE__ */ jsx("span", { children: likes })
17573
- ]
17574
- }
17575
- ),
17576
- /* @__PURE__ */ jsxs(
17577
- "button",
17578
- {
17579
- onClick: onDislike,
17580
- className: "inline-flex items-center gap-1 hover:text-gray-900 dark:hover:text-gray-100 transition-colors",
17581
- children: [
17582
- /* @__PURE__ */ jsx(BiDislike, { size: 18 }),
17583
- /* @__PURE__ */ jsx("span", { children: dislikes })
17584
- ]
17585
- }
17586
- ),
17587
- /* @__PURE__ */ jsx(
17588
- "button",
17589
- {
17590
- onClick: onReply,
17591
- className: "font-medium hover:text-gray-900 dark:hover:text-gray-100 transition-colors",
17592
- children: "Reply"
17593
- }
17594
- )
17595
- ] });
17596
- }
17597
- var CommentActions_default = CommentActions;
17598
17656
  function CommentMenu({
17599
17657
  canEdit,
17600
17658
  canDelete,
@@ -17614,28 +17672,34 @@ function CommentMenu({
17614
17672
  document.addEventListener("mousedown", handleOutsideClick);
17615
17673
  return () => document.removeEventListener("mousedown", handleOutsideClick);
17616
17674
  }, []);
17675
+ const hasActions = canEdit || canDelete || canReport;
17676
+ if (!hasActions) {
17677
+ return null;
17678
+ }
17617
17679
  return /* @__PURE__ */ jsxs("div", { ref, className: "relative", children: [
17618
17680
  /* @__PURE__ */ jsx(
17619
17681
  "button",
17620
17682
  {
17683
+ type: "button",
17621
17684
  onClick: () => setOpen((prev) => !prev),
17622
- className: "text-gray-500 hover:text-gray-900 dark:hover:text-gray-100 transition-colors",
17685
+ className: "\n text-gray-500\n hover:text-gray-900\n dark:hover:text-gray-100\n transition-colors\n ",
17623
17686
  children: /* @__PURE__ */ jsx(BiDotsVerticalRounded, { size: 18 })
17624
17687
  }
17625
17688
  ),
17626
17689
  open && /* @__PURE__ */ jsxs(
17627
17690
  "div",
17628
17691
  {
17629
- className: "\r\n absolute\r\n right-0\r\n top-full\r\n mt-2\r\n min-w-[160px]\r\n overflow-hidden\r\n rounded-xl\r\n border\r\n border-gray-200\r\n dark:border-neutral-800\r\n bg-white\r\n dark:bg-neutral-900\r\n shadow-xl\r\n z-50\r\n ",
17692
+ className: "\n absolute\n right-0\n top-full\n mt-2\n min-w-[180px]\n overflow-hidden\n rounded-xl\n border\n border-gray-200\n dark:border-neutral-800\n bg-white\n dark:bg-neutral-900\n shadow-xl\n z-50\n ",
17630
17693
  children: [
17631
17694
  canEdit && /* @__PURE__ */ jsxs(
17632
17695
  "button",
17633
17696
  {
17697
+ type: "button",
17634
17698
  onClick: () => {
17635
17699
  setOpen(false);
17636
17700
  onEdit?.();
17637
17701
  },
17638
- className: "w-full flex items-center gap-2 px-4 py-3 text-sm hover:bg-gray-100 dark:hover:bg-neutral-800",
17702
+ className: "\n w-full\n flex\n items-center\n gap-2\n px-4\n py-3\n text-sm\n hover:bg-gray-100\n dark:hover:bg-neutral-800\n ",
17639
17703
  children: [
17640
17704
  /* @__PURE__ */ jsx(BiEdit, {}),
17641
17705
  "Edit"
@@ -17645,11 +17709,12 @@ function CommentMenu({
17645
17709
  canDelete && /* @__PURE__ */ jsxs(
17646
17710
  "button",
17647
17711
  {
17712
+ type: "button",
17648
17713
  onClick: () => {
17649
17714
  setOpen(false);
17650
17715
  onDelete?.();
17651
17716
  },
17652
- className: "w-full flex items-center gap-2 px-4 py-3 text-sm hover:bg-gray-100 dark:hover:bg-neutral-800",
17717
+ className: "\n w-full\n flex\n items-center\n gap-2\n px-4\n py-3\n text-sm\n text-red-500\n hover:bg-gray-100\n dark:hover:bg-neutral-800\n ",
17653
17718
  children: [
17654
17719
  /* @__PURE__ */ jsx(BiTrash, {}),
17655
17720
  "Delete"
@@ -17659,11 +17724,12 @@ function CommentMenu({
17659
17724
  canReport && /* @__PURE__ */ jsxs(
17660
17725
  "button",
17661
17726
  {
17727
+ type: "button",
17662
17728
  onClick: () => {
17663
17729
  setOpen(false);
17664
17730
  onReport?.();
17665
17731
  },
17666
- className: "w-full flex items-center gap-2 px-4 py-3 text-sm hover:bg-gray-100 dark:hover:bg-neutral-800",
17732
+ className: "\n w-full\n flex\n items-center\n gap-2\n px-4\n py-3\n text-sm\n hover:bg-gray-100\n dark:hover:bg-neutral-800\n ",
17667
17733
  children: [
17668
17734
  /* @__PURE__ */ jsx(BiFlag, {}),
17669
17735
  "Report"
@@ -17681,25 +17747,37 @@ function CommentRepliesToggle({
17681
17747
  collapsed,
17682
17748
  onToggle
17683
17749
  }) {
17750
+ if (repliesCount <= 0) {
17751
+ return null;
17752
+ }
17753
+ const label = collapsed ? `View ${repliesCount} ${repliesCount === 1 ? "reply" : "replies"}` : "Hide replies";
17684
17754
  return /* @__PURE__ */ jsxs(
17685
17755
  "button",
17686
17756
  {
17757
+ type: "button",
17687
17758
  onClick: onToggle,
17688
- className: "inline-flex items-center gap-1 text-sm font-medium text-blue-500 hover:text-blue-400 transition-colors w-fit",
17759
+ className: "\n inline-flex\n items-center\n gap-1\n w-fit\n text-sm\n font-medium\n text-blue-500\n hover:text-blue-400\n transition-colors\n ",
17689
17760
  children: [
17690
17761
  collapsed ? /* @__PURE__ */ jsx(BiChevronDown, { size: 18 }) : /* @__PURE__ */ jsx(BiChevronUp, { size: 18 }),
17691
- /* @__PURE__ */ jsx("span", { children: collapsed ? `View ${repliesCount} repl${repliesCount > 1 ? "ies" : "y"}` : "Hide replies" })
17762
+ /* @__PURE__ */ jsx("span", { children: label })
17692
17763
  ]
17693
17764
  }
17694
17765
  );
17695
17766
  }
17696
17767
  var CommentRepliesToggle_default = CommentRepliesToggle;
17697
- function ReplyComposer({ username, onSubmit }) {
17768
+ function ReplyComposer({
17769
+ avatar,
17770
+ username,
17771
+ loading,
17772
+ onSubmit
17773
+ }) {
17698
17774
  return /* @__PURE__ */ jsx("div", { className: "pt-2", children: /* @__PURE__ */ jsx(
17699
17775
  CommentComposer_default,
17700
17776
  {
17701
- placeholder: `Reply to @${username}`,
17777
+ avatar,
17778
+ loading,
17702
17779
  submitLabel: "Reply",
17780
+ placeholder: `Reply to @${username}`,
17703
17781
  onSubmit
17704
17782
  }
17705
17783
  ) });
@@ -17708,7 +17786,7 @@ var ReplyComposer_default = ReplyComposer;
17708
17786
 
17709
17787
  // src/compositions/comment-thread/constants/comment.constants.ts
17710
17788
  var MAX_COMMENT_DEPTH = 5;
17711
- var COMMENT_INDENTATION = 0;
17789
+ var COMMENT_INDENTATION = 24;
17712
17790
  function CommentItem({
17713
17791
  comment,
17714
17792
  depth = 0,
@@ -17723,7 +17801,7 @@ function CommentItem({
17723
17801
  const [isReplying, setIsReplying] = useState(false);
17724
17802
  const resolvedDepth = Math.min(depth, MAX_COMMENT_DEPTH);
17725
17803
  async function handleReply(content) {
17726
- console.log(content);
17804
+ await onReply?.(comment, content);
17727
17805
  setIsReplying(false);
17728
17806
  }
17729
17807
  return /* @__PURE__ */ jsxs(
@@ -17731,16 +17809,18 @@ function CommentItem({
17731
17809
  {
17732
17810
  className: "flex flex-col gap-4",
17733
17811
  style: {
17734
- paddingLeft: `${resolvedDepth * COMMENT_INDENTATION}px`
17812
+ paddingLeft: resolvedDepth * COMMENT_INDENTATION
17735
17813
  },
17736
17814
  children: [
17737
- /* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col gap-3 min-w-0", children: [
17815
+ /* @__PURE__ */ jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-3 min-w-0", children: [
17738
17816
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
17739
17817
  /* @__PURE__ */ jsx(
17740
17818
  CommentHeader_default,
17741
17819
  {
17742
- avatar: comment.author.avatar,
17743
- username: comment.author.username,
17820
+ avatar: comment.author?.avatar,
17821
+ username: comment.author?.username ?? "unknown",
17822
+ firstName: comment.author?.firstName,
17823
+ lastName: comment.author?.lastName,
17744
17824
  createdAt: comment.createdAt,
17745
17825
  edited: comment.edited
17746
17826
  }
@@ -17763,18 +17843,19 @@ function CommentItem({
17763
17843
  {
17764
17844
  likes: comment.likes,
17765
17845
  dislikes: comment.dislikes,
17846
+ liked: comment.liked,
17847
+ disliked: comment.disliked,
17848
+ canReply: comment.permissions?.canReply,
17766
17849
  onLike: () => onLike?.(comment),
17767
17850
  onDislike: () => onDislike?.(comment),
17768
- onReply: () => {
17769
- setIsReplying((prev) => !prev);
17770
- onReply?.(comment);
17771
- }
17851
+ onReply: () => setIsReplying((prev) => !prev)
17772
17852
  }
17773
17853
  ),
17774
17854
  isReplying && /* @__PURE__ */ jsx(
17775
17855
  ReplyComposer_default,
17776
17856
  {
17777
- username: comment.author.username,
17857
+ avatar: comment.author?.avatar,
17858
+ username: comment.author?.username,
17778
17859
  onSubmit: handleReply
17779
17860
  }
17780
17861
  ),
@@ -17824,6 +17905,9 @@ function CommentList({
17824
17905
  onDelete,
17825
17906
  onReport
17826
17907
  }) {
17908
+ if (!comments.length) {
17909
+ return null;
17910
+ }
17827
17911
  return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-8", children: comments.map((comment) => /* @__PURE__ */ jsx(
17828
17912
  CommentItem_default,
17829
17913
  {
@@ -17840,52 +17924,356 @@ function CommentList({
17840
17924
  )) });
17841
17925
  }
17842
17926
  var CommentList_default = CommentList;
17843
- var CommentThreadContext = createContext(null);
17844
- function useCommentThread(initialComments) {
17845
- const [comments, setComments] = useState(initialComments);
17846
- return {
17847
- comments,
17848
- setComments
17849
- };
17927
+ function EditCommentModal({
17928
+ show,
17929
+ comment,
17930
+ handleCloseModal,
17931
+ onSubmit
17932
+ }) {
17933
+ if (!comment) return null;
17934
+ return /* @__PURE__ */ jsx(Modal_default, { title: "Edit Comment", show, handleOnClose: handleCloseModal, children: /* @__PURE__ */ jsx(
17935
+ Form,
17936
+ {
17937
+ enableReinitialize: true,
17938
+ initialValues: {
17939
+ content: comment.content
17940
+ },
17941
+ onSubmit: async (values) => {
17942
+ await onSubmit?.(comment, values.content);
17943
+ handleCloseModal();
17944
+ },
17945
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
17946
+ /* @__PURE__ */ jsx(TextArea_default, { name: "content", rows: 5, placeholder: "Comment" }),
17947
+ /* @__PURE__ */ jsx(Button_default, { type: "submit", variant: "success", text: "Save Changes" })
17948
+ ] })
17949
+ }
17950
+ ) });
17850
17951
  }
17851
- function CommentThread({
17852
- comments: initialComments = [],
17853
- onCommentCreate,
17854
- onLike,
17855
- onDislike,
17856
- onReply,
17857
- onEdit,
17858
- onDelete,
17859
- onReport
17952
+ var EditCommentModal_default = EditCommentModal;
17953
+ function DeleteCommentModal({
17954
+ show,
17955
+ comment,
17956
+ handleCloseModal,
17957
+ onDelete
17860
17958
  }) {
17861
- const { comments, setComments } = useCommentThread(initialComments);
17862
- async function handleCreateComment(content) {
17863
- await onCommentCreate?.(content);
17959
+ if (!comment) return null;
17960
+ return /* @__PURE__ */ jsx(Modal_default, { title: "Delete Comment", show, handleOnClose: handleCloseModal, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
17961
+ /* @__PURE__ */ jsx(Typography.Paragraph, { children: "Are you sure you want to permanently delete this comment?" }),
17962
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-3 justify-end", children: [
17963
+ /* @__PURE__ */ jsx(Button_default, { text: "Cancel", appearance: "ghost", onClick: handleCloseModal }),
17964
+ /* @__PURE__ */ jsx(
17965
+ Button_default,
17966
+ {
17967
+ text: "Delete",
17968
+ variant: "danger",
17969
+ onClick: async () => {
17970
+ await onDelete?.(comment);
17971
+ handleCloseModal();
17972
+ }
17973
+ }
17974
+ )
17975
+ ] })
17976
+ ] }) });
17977
+ }
17978
+ var DeleteCommentModal_default = DeleteCommentModal;
17979
+ var REPORT_REASONS = [
17980
+ {
17981
+ label: "Spam",
17982
+ value: "spam"
17983
+ },
17984
+ {
17985
+ label: "Harassment",
17986
+ value: "harassment"
17987
+ },
17988
+ {
17989
+ label: "Hate Speech",
17990
+ value: "hate_speech"
17991
+ },
17992
+ {
17993
+ label: "Misleading Information",
17994
+ value: "misleading_information"
17995
+ },
17996
+ {
17997
+ label: "Other",
17998
+ value: "other"
17864
17999
  }
17865
- return /* @__PURE__ */ jsx(
17866
- CommentThreadContext.Provider,
18000
+ ];
18001
+ function ReportCommentModal({
18002
+ show,
18003
+ comment,
18004
+ handleCloseModal,
18005
+ onSubmit
18006
+ }) {
18007
+ if (!comment) return null;
18008
+ return /* @__PURE__ */ jsx(Modal_default, { title: "Report Comment", show, handleOnClose: handleCloseModal, children: /* @__PURE__ */ jsx(
18009
+ Form,
17867
18010
  {
17868
- value: {
17869
- comments,
17870
- setComments
18011
+ initialValues: {
18012
+ reason: "",
18013
+ description: ""
18014
+ },
18015
+ onSubmit: async (values) => {
18016
+ await onSubmit?.(comment, {
18017
+ reason: values.reason,
18018
+ description: values.description
18019
+ });
18020
+ handleCloseModal();
17871
18021
  },
17872
- children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-8 w-full", children: [
17873
- /* @__PURE__ */ jsx(CommentComposer_default, { onSubmit: handleCreateComment }),
18022
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
18023
+ /* @__PURE__ */ jsx(Select_default, { name: "reason", placeholder: "Reason", options: REPORT_REASONS }),
17874
18024
  /* @__PURE__ */ jsx(
17875
- CommentList_default,
18025
+ TextArea_default,
17876
18026
  {
17877
- comments,
17878
- onLike,
17879
- onDislike,
17880
- onReply,
17881
- onEdit,
17882
- onDelete,
17883
- onReport
18027
+ name: "description",
18028
+ rows: 4,
18029
+ placeholder: "Additional details"
17884
18030
  }
17885
- )
18031
+ ),
18032
+ /* @__PURE__ */ jsx(Button_default, { type: "submit", variant: "danger", text: "Submit Report" })
17886
18033
  ] })
17887
18034
  }
18035
+ ) });
18036
+ }
18037
+ var ReportCommentModal_default = ReportCommentModal;
18038
+ function useCommentModals() {
18039
+ const [showEditModal, setShowEditModal] = useState(false);
18040
+ const [showDeleteModal, setShowDeleteModal] = useState(false);
18041
+ const [showReportModal, setShowReportModal] = useState(false);
18042
+ return {
18043
+ showEditModal,
18044
+ openEditModal: () => setShowEditModal(true),
18045
+ closeEditModal: () => setShowEditModal(false),
18046
+ showDeleteModal,
18047
+ openDeleteModal: () => setShowDeleteModal(true),
18048
+ closeDeleteModal: () => setShowDeleteModal(false),
18049
+ showReportModal,
18050
+ openReportModal: () => setShowReportModal(true),
18051
+ closeReportModal: () => setShowReportModal(false)
18052
+ };
18053
+ }
18054
+ function useCommentSelection() {
18055
+ const [selectedComment, setSelectedComment] = useState(
18056
+ null
17888
18057
  );
18058
+ function selectComment(comment) {
18059
+ setSelectedComment(comment);
18060
+ }
18061
+ function clearSelection() {
18062
+ setSelectedComment(null);
18063
+ }
18064
+ return {
18065
+ selectedComment,
18066
+ selectComment,
18067
+ clearSelection
18068
+ };
18069
+ }
18070
+
18071
+ // src/compositions/comment-thread/utils/buildCommentTree.ts
18072
+ function buildCommentTree(comments) {
18073
+ const map = /* @__PURE__ */ new Map();
18074
+ const roots = [];
18075
+ comments.forEach((comment) => {
18076
+ map.set(comment.id, {
18077
+ ...comment,
18078
+ replies: []
18079
+ });
18080
+ });
18081
+ comments.forEach((comment) => {
18082
+ const current = map.get(comment.id);
18083
+ if (!comment.parentCommentId) {
18084
+ roots.push(current);
18085
+ return;
18086
+ }
18087
+ const parent = map.get(comment.parentCommentId);
18088
+ if (parent) {
18089
+ parent.replies.push(current);
18090
+ }
18091
+ });
18092
+ return roots;
18093
+ }
18094
+
18095
+ // src/compositions/comment-thread/utils/updateComment.ts
18096
+ function updateComment(comments, commentId, updater) {
18097
+ return comments.map((comment) => {
18098
+ if (comment.id === commentId) {
18099
+ return updater(comment);
18100
+ }
18101
+ return {
18102
+ ...comment,
18103
+ replies: comment.replies ? updateComment(comment.replies, commentId, updater) : []
18104
+ };
18105
+ });
18106
+ }
18107
+
18108
+ // src/compositions/comment-thread/utils/removeComment.ts
18109
+ function removeComment(comments, commentId) {
18110
+ return comments.filter((comment) => comment.id !== commentId).map((comment) => ({
18111
+ ...comment,
18112
+ replies: comment.replies ? removeComment(comment.replies, commentId) : []
18113
+ }));
18114
+ }
18115
+
18116
+ // src/compositions/comment-thread/utils/insertReply.ts
18117
+ function insertReply(comments, parentId, reply) {
18118
+ return comments.map((comment) => {
18119
+ if (comment.id === parentId) {
18120
+ return {
18121
+ ...comment,
18122
+ replies: [...comment.replies || [], reply]
18123
+ };
18124
+ }
18125
+ return {
18126
+ ...comment,
18127
+ replies: comment.replies ? insertReply(comment.replies, parentId, reply) : []
18128
+ };
18129
+ });
18130
+ }
18131
+ function CommentThread({
18132
+ postId,
18133
+ currentUser,
18134
+ dataSource,
18135
+ loading = false,
18136
+ onEdit,
18137
+ onDelete,
18138
+ onReport
18139
+ }) {
18140
+ const [comments, setComments] = useState([]);
18141
+ const [isLoadingComments, setIsLoadingComments] = useState(true);
18142
+ const selection = useCommentSelection();
18143
+ const modals = useCommentModals();
18144
+ useEffect(() => {
18145
+ async function loadComments() {
18146
+ try {
18147
+ const result = await dataSource.getComments();
18148
+ setComments(buildCommentTree(result));
18149
+ } finally {
18150
+ setIsLoadingComments(false);
18151
+ }
18152
+ }
18153
+ loadComments();
18154
+ }, [dataSource]);
18155
+ async function handleCreateComment(content) {
18156
+ const comment = await dataSource.createComment({
18157
+ content,
18158
+ parentCommentId: null
18159
+ });
18160
+ setComments((prev) => [comment, ...prev]);
18161
+ }
18162
+ async function handleReply(parentComment, content) {
18163
+ const reply = await dataSource.createComment({
18164
+ content,
18165
+ parentCommentId: parentComment.id
18166
+ });
18167
+ setComments((prev) => insertReply(prev, parentComment.id, reply));
18168
+ }
18169
+ async function handleLike(comment) {
18170
+ const result = await dataSource.toggleLike(comment.id);
18171
+ setComments(
18172
+ (prev) => updateComment(prev, comment.id, (item) => ({
18173
+ ...item,
18174
+ likes: result.likes,
18175
+ dislikes: result.dislikes,
18176
+ liked: result.liked,
18177
+ disliked: result.disliked
18178
+ }))
18179
+ );
18180
+ }
18181
+ async function handleDislike(comment) {
18182
+ const result = await dataSource.toggleDislike(comment.id);
18183
+ setComments(
18184
+ (prev) => updateComment(prev, comment.id, (item) => ({
18185
+ ...item,
18186
+ likes: result.likes,
18187
+ dislikes: result.dislikes,
18188
+ liked: result.liked,
18189
+ disliked: result.disliked
18190
+ }))
18191
+ );
18192
+ }
18193
+ async function handleUpdateComment(comment, content) {
18194
+ const updated = await dataSource.updateComment({
18195
+ id: comment.id,
18196
+ content
18197
+ });
18198
+ setComments((prev) => updateComment(prev, comment.id, () => updated));
18199
+ }
18200
+ async function handleDeleteComment(comment) {
18201
+ await dataSource.deleteComment(comment.id);
18202
+ setComments((prev) => removeComment(prev, comment.id));
18203
+ onDelete?.(comment);
18204
+ }
18205
+ async function handleReportComment(comment, payload) {
18206
+ await dataSource.reportComment?.(
18207
+ comment.id,
18208
+ payload.reason,
18209
+ payload.description
18210
+ );
18211
+ onReport?.(comment);
18212
+ }
18213
+ if (loading || isLoadingComments) {
18214
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-6", children: "Loading comments..." });
18215
+ }
18216
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
18217
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-8", children: [
18218
+ /* @__PURE__ */ jsx(
18219
+ CommentComposer_default,
18220
+ {
18221
+ avatar: currentUser.avatar,
18222
+ onSubmit: handleCreateComment
18223
+ }
18224
+ ),
18225
+ /* @__PURE__ */ jsx(
18226
+ CommentList_default,
18227
+ {
18228
+ comments,
18229
+ onLike: handleLike,
18230
+ onDislike: handleDislike,
18231
+ onReply: handleReply,
18232
+ onEdit: (comment) => {
18233
+ selection.selectComment(comment);
18234
+ onEdit?.(comment);
18235
+ modals.openEditModal();
18236
+ },
18237
+ onDelete: (comment) => {
18238
+ selection.selectComment(comment);
18239
+ modals.openDeleteModal();
18240
+ },
18241
+ onReport: (comment) => {
18242
+ selection.selectComment(comment);
18243
+ onReport?.(comment);
18244
+ modals.openReportModal();
18245
+ }
18246
+ }
18247
+ )
18248
+ ] }),
18249
+ /* @__PURE__ */ jsx(
18250
+ EditCommentModal_default,
18251
+ {
18252
+ show: modals.showEditModal,
18253
+ comment: selection.selectedComment,
18254
+ handleCloseModal: modals.closeEditModal,
18255
+ onSubmit: handleUpdateComment
18256
+ }
18257
+ ),
18258
+ /* @__PURE__ */ jsx(
18259
+ DeleteCommentModal_default,
18260
+ {
18261
+ show: modals.showDeleteModal,
18262
+ comment: selection.selectedComment,
18263
+ handleCloseModal: modals.closeDeleteModal,
18264
+ onDelete: handleDeleteComment
18265
+ }
18266
+ ),
18267
+ /* @__PURE__ */ jsx(
18268
+ ReportCommentModal_default,
18269
+ {
18270
+ show: modals.showReportModal,
18271
+ comment: selection.selectedComment,
18272
+ handleCloseModal: modals.closeReportModal,
18273
+ onSubmit: handleReportComment
18274
+ }
18275
+ )
18276
+ ] });
17889
18277
  }
17890
18278
  var CommentThread_default = CommentThread;
17891
18279
  function DataViewTable({