Jelajahi Sumber

feat(dashboard): Add rich text editor

Michael Bromley 9 bulan lalu
induk
melakukan
fde9f78abb

+ 554 - 56
package-lock.json

@@ -11344,6 +11344,16 @@
         "node": ">=14"
       }
     },
+    "node_modules/@popperjs/core": {
+      "version": "2.11.8",
+      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+      "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/popperjs"
+      }
+    },
     "node_modules/@protobufjs/aspromise": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
@@ -12519,6 +12529,12 @@
       "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==",
       "license": "MIT"
     },
+    "node_modules/@remirror/core-constants": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz",
+      "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==",
+      "license": "MIT"
+    },
     "node_modules/@repeaterjs/repeater": {
       "version": "3.0.6",
       "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.6.tgz",
@@ -14785,6 +14801,391 @@
         "url": "https://github.com/sponsors/tannerlinsley"
       }
     },
+    "node_modules/@tiptap/core": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.11.5.tgz",
+      "integrity": "sha512-jb0KTdUJaJY53JaN7ooY3XAxHQNoMYti/H6ANo707PsLXVeEqJ9o8+eBup1JU5CuwzrgnDc2dECt2WIGX9f8Jw==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-blockquote": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.11.5.tgz",
+      "integrity": "sha512-MZfcRIzKRD8/J1hkt/eYv49060GTL6qGR3NY/oTDuw2wYzbQXXLEbjk8hxAtjwNn7G+pWQv3L+PKFzZDxibLuA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-bold": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.11.5.tgz",
+      "integrity": "sha512-OAq03MHEbl7MtYCUzGuwb0VpOPnM0k5ekMbEaRILFU5ZC7cEAQ36XmPIw1dQayrcuE8GZL35BKub2qtRxyC9iA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-bubble-menu": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.11.5.tgz",
+      "integrity": "sha512-rx+rMd7EEdht5EHLWldpkzJ56SWYA9799b33ustePqhXd6linnokJCzBqY13AfZ9+xp3RsR6C0ZHI9GGea0tIA==",
+      "license": "MIT",
+      "dependencies": {
+        "tippy.js": "^6.3.7"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-bullet-list": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.11.5.tgz",
+      "integrity": "sha512-VXwHlX6A/T6FAspnyjbKDO0TQ+oetXuat6RY1/JxbXphH42nLuBaGWJ6pgy6xMl6XY8/9oPkTNrfJw/8/eeRwA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-code": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.11.5.tgz",
+      "integrity": "sha512-xOvHevNIQIcCCVn9tpvXa1wBp0wHN/2umbAZGTVzS+AQtM7BTo0tz8IyzwxkcZJaImONcUVYLOLzt2AgW1LltA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-code-block": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.11.5.tgz",
+      "integrity": "sha512-ksxMMvqLDlC+ftcQLynqZMdlJT1iHYZorXsXw/n+wuRd7YElkRkd6YWUX/Pq/njFY6lDjKiqFLEXBJB8nrzzBA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-document": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.11.5.tgz",
+      "integrity": "sha512-7I4BRTpIux2a0O2qS3BDmyZ5LGp3pszKbix32CmeVh7lN9dV7W5reDqtJJ9FCZEEF+pZ6e1/DQA362dflwZw2g==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-dropcursor": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.11.5.tgz",
+      "integrity": "sha512-uIN7L3FU0904ec7FFFbndO7RQE/yiON4VzAMhNn587LFMyWO8US139HXIL4O8dpZeYwYL3d1FnDTflZl6CwLlg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-floating-menu": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.11.5.tgz",
+      "integrity": "sha512-HsMI0hV5Lwzm530Z5tBeyNCBNG38eJ3qjfdV2OHlfSf3+KOEfn6a5AUdoNaZO02LF79/8+7BaYU2drafag9cxQ==",
+      "license": "MIT",
+      "dependencies": {
+        "tippy.js": "^6.3.7"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-gapcursor": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.11.5.tgz",
+      "integrity": "sha512-kcWa+Xq9cb6lBdiICvLReuDtz/rLjFKHWpW3jTTF3FiP3wx4H8Rs6bzVtty7uOVTfwupxZRiKICAMEU6iT0xrQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-hard-break": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.11.5.tgz",
+      "integrity": "sha512-q9doeN+Yg9F5QNTG8pZGYfNye3tmntOwch683v0CCVCI4ldKaLZ0jG3NbBTq+mosHYdgOH2rNbIORlRRsQ+iYQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-heading": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.11.5.tgz",
+      "integrity": "sha512-x/MV53psJ9baRcZ4k4WjnCUBMt8zCX7mPlKVT+9C/o+DEs/j/qxPLs95nHeQv70chZpSwCQCt93xMmuF0kPoAg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-history": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.11.5.tgz",
+      "integrity": "sha512-b+wOS33Dz1azw6F1i9LFTEIJ/gUui0Jwz5ZvmVDpL2ZHBhq1Ui0/spTT+tuZOXq7Y/uCbKL8Liu4WoedIvhboQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-horizontal-rule": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.11.5.tgz",
+      "integrity": "sha512-3up2r1Du8/5/4ZYzTC0DjTwhgPI3dn8jhOCLu73m5F3OGvK/9whcXoeWoX103hYMnGDxBlfOje71yQuN35FL4A==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-italic": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.11.5.tgz",
+      "integrity": "sha512-9VGfb2/LfPhQ6TjzDwuYLRvw0A6VGbaIp3F+5Mql8XVdTBHb2+rhELbyhNGiGVR78CaB/EiKb6dO9xu/tBWSYA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-list-item": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.11.5.tgz",
+      "integrity": "sha512-Mp5RD/pbkfW1vdc6xMVxXYcta73FOwLmblQlFNn/l/E5/X1DUSA4iGhgDDH4EWO3swbs03x2f7Zka/Xoj3+WLg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-ordered-list": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.11.5.tgz",
+      "integrity": "sha512-Cu8KwruBNWAaEfshRQR0yOSaUKAeEwxW7UgbvF9cN/zZuKgK5uZosPCPTehIFCcRe+TBpRtZQh+06f/gNYpYYg==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-paragraph": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.11.5.tgz",
+      "integrity": "sha512-YFBWeg7xu/sBnsDIF/+nh9Arf7R0h07VZMd0id5Ydd2Qe3c1uIZwXxeINVtH0SZozuPIQFAT8ICe9M0RxmE+TA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-strike": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.11.5.tgz",
+      "integrity": "sha512-PVfUiCqrjvsLpbIoVlegSY8RlkR64F1Rr2RYmiybQfGbg+AkSZXDeO0eIrc03//4gua7D9DfIozHmAKv1KN3ow==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-text": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.11.5.tgz",
+      "integrity": "sha512-Gq1WwyhFpCbEDrLPIHt5A8aLSlf8bfz4jm417c8F/JyU0J5dtYdmx0RAxjnLw1i7ZHE7LRyqqAoS0sl7JHDNSQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/extension-text-style": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.11.5.tgz",
+      "integrity": "sha512-YUmYl0gILSd/u/ZkOmNxjNXVw+mu8fpC2f8G4I4tLODm0zCx09j9DDEJXSrM5XX72nxJQqtSQsCpNKnL0hfeEQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0"
+      }
+    },
+    "node_modules/@tiptap/pm": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.11.5.tgz",
+      "integrity": "sha512-z9JFtqc5ZOsdQLd9vRnXfTCQ8v5ADAfRt9Nm7SqP6FUHII8E1hs38ACzf5xursmth/VonJYb5+73Pqxk1hGIPw==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-changeset": "^2.2.1",
+        "prosemirror-collab": "^1.3.1",
+        "prosemirror-commands": "^1.6.2",
+        "prosemirror-dropcursor": "^1.8.1",
+        "prosemirror-gapcursor": "^1.3.2",
+        "prosemirror-history": "^1.4.1",
+        "prosemirror-inputrules": "^1.4.0",
+        "prosemirror-keymap": "^1.2.2",
+        "prosemirror-markdown": "^1.13.1",
+        "prosemirror-menu": "^1.2.4",
+        "prosemirror-model": "^1.23.0",
+        "prosemirror-schema-basic": "^1.2.3",
+        "prosemirror-schema-list": "^1.4.1",
+        "prosemirror-state": "^1.4.3",
+        "prosemirror-tables": "^1.6.3",
+        "prosemirror-trailing-node": "^3.0.0",
+        "prosemirror-transform": "^1.10.2",
+        "prosemirror-view": "^1.37.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      }
+    },
+    "node_modules/@tiptap/react": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.11.5.tgz",
+      "integrity": "sha512-Dp8eHL1G+R/C4+QzAczyb3t1ovexEIZx9ln7SGEM+cT1KHKAw9XGPRgsp92+NQaYI+EdEb/YqoBOSzQcd18/OQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@tiptap/extension-bubble-menu": "^2.11.5",
+        "@tiptap/extension-floating-menu": "^2.11.5",
+        "@types/use-sync-external-store": "^0.0.6",
+        "fast-deep-equal": "^3",
+        "use-sync-external-store": "^1"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.7.0",
+        "@tiptap/pm": "^2.7.0",
+        "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+        "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+      }
+    },
+    "node_modules/@tiptap/starter-kit": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.11.5.tgz",
+      "integrity": "sha512-SLI7Aj2ruU1t//6Mk8f+fqW+18uTqpdfLUJYgwu0CkqBckrkRZYZh6GVLk/02k3H2ki7QkFxiFbZrdbZdng0JA==",
+      "license": "MIT",
+      "dependencies": {
+        "@tiptap/core": "^2.11.5",
+        "@tiptap/extension-blockquote": "^2.11.5",
+        "@tiptap/extension-bold": "^2.11.5",
+        "@tiptap/extension-bullet-list": "^2.11.5",
+        "@tiptap/extension-code": "^2.11.5",
+        "@tiptap/extension-code-block": "^2.11.5",
+        "@tiptap/extension-document": "^2.11.5",
+        "@tiptap/extension-dropcursor": "^2.11.5",
+        "@tiptap/extension-gapcursor": "^2.11.5",
+        "@tiptap/extension-hard-break": "^2.11.5",
+        "@tiptap/extension-heading": "^2.11.5",
+        "@tiptap/extension-history": "^2.11.5",
+        "@tiptap/extension-horizontal-rule": "^2.11.5",
+        "@tiptap/extension-italic": "^2.11.5",
+        "@tiptap/extension-list-item": "^2.11.5",
+        "@tiptap/extension-ordered-list": "^2.11.5",
+        "@tiptap/extension-paragraph": "^2.11.5",
+        "@tiptap/extension-strike": "^2.11.5",
+        "@tiptap/extension-text": "^2.11.5",
+        "@tiptap/extension-text-style": "^2.11.5",
+        "@tiptap/pm": "^2.11.5"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      }
+    },
     "node_modules/@tokenizer/token": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
@@ -15451,6 +15852,12 @@
         "@types/koa": "*"
       }
     },
+    "node_modules/@types/linkify-it": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
+      "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
+      "license": "MIT"
+    },
     "node_modules/@types/localtunnel": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/@types/localtunnel/-/localtunnel-2.0.4.tgz",
@@ -15467,6 +15874,22 @@
       "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==",
       "license": "MIT"
     },
+    "node_modules/@types/markdown-it": {
+      "version": "14.1.2",
+      "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
+      "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/linkify-it": "^5",
+        "@types/mdurl": "^2"
+      }
+    },
+    "node_modules/@types/mdurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
+      "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
+      "license": "MIT"
+    },
     "node_modules/@types/mime": {
       "version": "1.3.5",
       "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
@@ -15849,6 +16272,12 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/@types/use-sync-external-store": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
+      "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
+      "license": "MIT"
+    },
     "node_modules/@types/vinyl": {
       "version": "2.0.12",
       "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.12.tgz",
@@ -30089,6 +30518,15 @@
         "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
       }
     },
+    "node_modules/linkify-it": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
+      "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+      "license": "MIT",
+      "dependencies": {
+        "uc.micro": "^2.0.0"
+      }
+    },
     "node_modules/lint-staged": {
       "version": "10.5.4",
       "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.5.4.tgz",
@@ -30999,6 +31437,23 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/markdown-it": {
+      "version": "14.1.0",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
+      "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "entities": "^4.4.0",
+        "linkify-it": "^5.0.0",
+        "mdurl": "^2.0.0",
+        "punycode.js": "^2.3.1",
+        "uc.micro": "^2.1.0"
+      },
+      "bin": {
+        "markdown-it": "bin/markdown-it.mjs"
+      }
+    },
     "node_modules/math-intrinsics": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -31008,6 +31463,12 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/mdurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+      "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+      "license": "MIT"
+    },
     "node_modules/media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -35055,6 +35516,24 @@
         "node": ">= 8"
       }
     },
+    "node_modules/prosemirror-changeset": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz",
+      "integrity": "sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-transform": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-collab": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz",
+      "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==",
+      "license": "MIT",
+      "dependencies": {
+        "prosemirror-state": "^1.0.0"
+      }
+    },
     "node_modules/prosemirror-commands": {
       "version": "1.7.0",
       "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.0.tgz",
@@ -35102,9 +35581,9 @@
       }
     },
     "node_modules/prosemirror-inputrules": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz",
-      "integrity": "sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==",
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.0.tgz",
+      "integrity": "sha512-K0xJRCmt+uSw7xesnHmcn72yBGTbY45vm8gXI4LZXbx2Z0jwh5aF9xrGQgrVPu0WbyFVFF3E/o9VhJYz6SQWnA==",
       "license": "MIT",
       "dependencies": {
         "prosemirror-state": "^1.0.0",
@@ -35121,6 +35600,17 @@
         "w3c-keyname": "^2.2.0"
       }
     },
+    "node_modules/prosemirror-markdown": {
+      "version": "1.13.2",
+      "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.2.tgz",
+      "integrity": "sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/markdown-it": "^14.0.0",
+        "markdown-it": "^14.0.0",
+        "prosemirror-model": "^1.25.0"
+      }
+    },
     "node_modules/prosemirror-menu": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz",
@@ -35134,27 +35624,27 @@
       }
     },
     "node_modules/prosemirror-model": {
-      "version": "1.24.1",
-      "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.24.1.tgz",
-      "integrity": "sha512-YM053N+vTThzlWJ/AtPtF1j0ebO36nvbmDy4U7qA2XQB8JVaQp1FmB9Jhrps8s+z+uxhhVTny4m20ptUvhk0Mg==",
+      "version": "1.25.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.0.tgz",
+      "integrity": "sha512-/8XUmxWf0pkj2BmtqZHYJipTBMHIdVjuvFzMvEoxrtyGNmfvdhBiRwYt/eFwy2wA9DtBW3RLqvZnjurEkHaFCw==",
       "license": "MIT",
       "dependencies": {
         "orderedmap": "^2.0.0"
       }
     },
     "node_modules/prosemirror-schema-basic": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.3.tgz",
-      "integrity": "sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==",
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz",
+      "integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==",
       "license": "MIT",
       "dependencies": {
-        "prosemirror-model": "^1.19.0"
+        "prosemirror-model": "^1.25.0"
       }
     },
     "node_modules/prosemirror-schema-list": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.0.tgz",
-      "integrity": "sha512-gg1tAfH1sqpECdhIHOA/aLg2VH3ROKBWQ4m8Qp9mBKrOxQRW61zc+gMCI8nh22gnBzd1t2u1/NPLmO3nAa3ssg==",
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz",
+      "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==",
       "license": "MIT",
       "dependencies": {
         "prosemirror-model": "^1.0.0",
@@ -35186,6 +35676,21 @@
         "prosemirror-view": "^1.37.2"
       }
     },
+    "node_modules/prosemirror-trailing-node": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz",
+      "integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@remirror/core-constants": "3.0.0",
+        "escape-string-regexp": "^4.0.0"
+      },
+      "peerDependencies": {
+        "prosemirror-model": "^1.22.1",
+        "prosemirror-state": "^1.4.2",
+        "prosemirror-view": "^1.33.8"
+      }
+    },
     "node_modules/prosemirror-transform": {
       "version": "1.10.2",
       "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.2.tgz",
@@ -35315,6 +35820,15 @@
       "devOptional": true,
       "license": "MIT"
     },
+    "node_modules/punycode.js": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+      "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/puppeteer": {
       "version": "19.11.1",
       "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.11.1.tgz",
@@ -39645,6 +40159,15 @@
         "node": ">=14.0.0"
       }
     },
+    "node_modules/tippy.js": {
+      "version": "6.3.7",
+      "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
+      "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@popperjs/core": "^2.9.0"
+      }
+    },
     "node_modules/title-case": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/title-case/-/title-case-3.0.3.tgz",
@@ -40883,6 +41406,12 @@
         "node": "*"
       }
     },
+    "node_modules/uc.micro": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+      "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+      "license": "MIT"
+    },
     "node_modules/ufo": {
       "version": "1.5.4",
       "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",
@@ -43516,19 +44045,19 @@
         "messageformat": "2.3.0",
         "ngx-pagination": "^6.0.3",
         "ngx-translate-messageformat-compiler": "^6.5.0",
-        "prosemirror-commands": "^1.5.2",
+        "prosemirror-commands": "^1.7.0",
         "prosemirror-dropcursor": "^1.8.1",
         "prosemirror-gapcursor": "^1.3.2",
-        "prosemirror-history": "^1.3.2",
-        "prosemirror-inputrules": "^1.4.0",
+        "prosemirror-history": "^1.4.1",
+        "prosemirror-inputrules": "^1.5.0",
         "prosemirror-keymap": "^1.2.2",
         "prosemirror-menu": "^1.2.4",
-        "prosemirror-schema-basic": "^1.2.2",
-        "prosemirror-schema-list": "^1.3.0",
+        "prosemirror-schema-basic": "^1.2.4",
+        "prosemirror-schema-list": "^1.5.1",
         "prosemirror-state": "^1.4.3",
-        "prosemirror-tables": "^1.3.7",
-        "react": "^18.2.0",
-        "react-dom": "^18.2.0",
+        "prosemirror-tables": "^1.6.4",
+        "react": "^19.0.0",
+        "react-dom": "^19.0.0",
         "rxjs": "^7.8.1",
         "tslib": "^2.6.2",
         "zone.js": "~0.14.4"
@@ -45783,31 +46312,6 @@
         "url": "https://github.com/sponsors/jonschlinkert"
       }
     },
-    "packages/admin-ui/node_modules/react": {
-      "version": "18.3.1",
-      "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
-      "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
-      "license": "MIT",
-      "dependencies": {
-        "loose-envify": "^1.1.0"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "packages/admin-ui/node_modules/react-dom": {
-      "version": "18.3.1",
-      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
-      "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
-      "license": "MIT",
-      "dependencies": {
-        "loose-envify": "^1.1.0",
-        "scheduler": "^0.23.2"
-      },
-      "peerDependencies": {
-        "react": "^18.3.1"
-      }
-    },
     "packages/admin-ui/node_modules/readdirp": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -45858,15 +46362,6 @@
         "node": ">=0.12.0"
       }
     },
-    "packages/admin-ui/node_modules/scheduler": {
-      "version": "0.23.2",
-      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
-      "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
-      "license": "MIT",
-      "dependencies": {
-        "loose-envify": "^1.1.0"
-      }
-    },
     "packages/admin-ui/node_modules/semver": {
       "version": "7.6.0",
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
@@ -46657,13 +47152,16 @@
         "@tanstack/react-query-devtools": "^5.68.0",
         "@tanstack/react-router": "^1.105.0",
         "@tanstack/react-table": "^8.21.2",
+        "@tiptap/pm": "^2.11.5",
+        "@tiptap/react": "^2.11.5",
+        "@tiptap/starter-kit": "^2.11.5",
         "@types/node": "^22.13.4",
         "@uidotdev/usehooks": "^2.4.1",
         "awesome-graphql-client": "^2.1.0",
         "class-variance-authority": "^0.7.1",
         "clsx": "^2.1.1",
         "cmdk": "^1.0.0",
-        "date-fns": "^4.1.0",
+        "date-fns": "^3.6.0",
         "gql.tada": "^1.8.10",
         "graphql": "~16.10.0",
         "json-edit-react": "^1.23.1",

+ 8 - 8
packages/admin-ui/package.json

@@ -61,19 +61,19 @@
         "messageformat": "2.3.0",
         "ngx-pagination": "^6.0.3",
         "ngx-translate-messageformat-compiler": "^6.5.0",
-        "prosemirror-commands": "^1.5.2",
+        "prosemirror-commands": "^1.7.0",
         "prosemirror-dropcursor": "^1.8.1",
         "prosemirror-gapcursor": "^1.3.2",
-        "prosemirror-history": "^1.3.2",
-        "prosemirror-inputrules": "^1.4.0",
+        "prosemirror-history": "^1.4.1",
+        "prosemirror-inputrules": "^1.5.0",
         "prosemirror-keymap": "^1.2.2",
         "prosemirror-menu": "^1.2.4",
-        "prosemirror-schema-basic": "^1.2.2",
-        "prosemirror-schema-list": "^1.3.0",
+        "prosemirror-schema-basic": "^1.2.4",
+        "prosemirror-schema-list": "^1.5.1",
         "prosemirror-state": "^1.4.3",
-        "prosemirror-tables": "^1.3.7",
-        "react": "^18.2.0",
-        "react-dom": "^18.2.0",
+        "prosemirror-tables": "^1.6.4",
+        "react": "^19.0.0",
+        "react-dom": "^19.0.0",
         "rxjs": "^7.8.1",
         "tslib": "^2.6.2",
         "zone.js": "~0.14.4"

+ 4 - 1
packages/dashboard/package.json

@@ -51,13 +51,16 @@
     "@tanstack/react-query-devtools": "^5.68.0",
     "@tanstack/react-router": "^1.105.0",
     "@tanstack/react-table": "^8.21.2",
+    "@tiptap/pm": "^2.11.5",
+    "@tiptap/react": "^2.11.5",
+    "@tiptap/starter-kit": "^2.11.5",
     "@types/node": "^22.13.4",
     "@uidotdev/usehooks": "^2.4.1",
     "awesome-graphql-client": "^2.1.0",
     "class-variance-authority": "^0.7.1",
     "clsx": "^2.1.1",
     "cmdk": "^1.0.0",
-    "date-fns": "^4.1.0",
+    "date-fns": "^3.6.0",
     "gql.tada": "^1.8.10",
     "graphql": "~16.10.0",
     "json-edit-react": "^1.23.1",

+ 99 - 0
packages/dashboard/src/components/data-input/richt-text-input.tsx

@@ -0,0 +1,99 @@
+import { BubbleMenu, Editor, EditorContent, useCurrentEditor, useEditor } from '@tiptap/react';
+import StarterKit from '@tiptap/starter-kit';
+import ListItem from '@tiptap/extension-list-item';
+import TextStyle from '@tiptap/extension-text-style';
+import { BoldIcon, ItalicIcon, StrikethroughIcon } from 'lucide-react';
+import { useEffect, useLayoutEffect } from 'react';
+import { Button } from '../ui/button.js';
+
+// define your extension array
+const extensions = [
+    TextStyle.configure(),
+    StarterKit.configure({
+        bulletList: {
+            keepMarks: true,
+            keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
+        },
+        orderedList: {
+            keepMarks: true,
+            keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help
+        },
+    }),
+];
+
+export interface RichTextInputProps {
+    value: string;
+    onChange: (value: string) => void;
+}
+
+export function RichTextInput({ value, onChange }: RichTextInputProps) {
+    const editor = useEditor({
+        parseOptions: {
+            preserveWhitespace: 'full',
+        },
+        extensions: extensions,
+        content: value,
+        onUpdate: ({ editor }) => {
+            onChange(editor.getHTML());
+        },
+        editorProps: {
+            attributes: {
+                class: 'border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/10 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm max-h-[500px] overflow-y-auto',
+            },
+        },
+    });
+
+    if (!editor) return null;
+
+    useLayoutEffect(() => {
+        const { from, to } = editor.state.selection;
+    
+        editor.commands.setContent(value, false);
+    
+        editor.commands.setTextSelection({ from, to });
+      }, [value]);
+
+    return (
+        <>
+            <EditorContent editor={editor} />
+            <CustomBubbleMenu editor={editor} />
+        </>
+    );
+}
+
+function CustomBubbleMenu({ editor }: { editor: Editor | null }) {
+    if (!editor) return null;
+    return (
+        <BubbleMenu editor={editor}>
+            <div className="flex items-center gap-2 bg-background p-2 rounded-md border">
+                <Button
+                    type="button"
+                    variant="ghost"
+                    size="icon"
+                    onClick={() => editor.chain().focus().toggleBold().run()}
+                    className={editor.isActive('bold') ? 'bg-accent' : ''}
+                >
+                    <BoldIcon className="w-4 h-4" />
+                </Button>
+                <Button
+                    type="button"
+                    variant="ghost"
+                    size="icon"
+                    onClick={() => editor.chain().focus().toggleItalic().run()}
+                    className={editor.isActive('italic') ? 'bg-accent' : ''}
+                >
+                    <ItalicIcon className="w-4 h-4" />
+                </Button>
+                <Button
+                    type="button"
+                    variant="ghost"
+                    size="icon"
+                    onClick={() => editor.chain().focus().toggleStrike().run()}
+                    className={editor.isActive('strike') ? 'bg-accent' : ''}
+                >
+                    <StrikethroughIcon className="w-4 h-4" />
+                </Button>
+            </div>
+        </BubbleMenu>
+    );
+}

+ 9 - 17
packages/dashboard/src/components/shared/paginated-list-data-table.tsx

@@ -10,9 +10,16 @@ import { api } from '@/graphql/api.js';
 import { useMutation, useQueryClient } from '@tanstack/react-query';
 import { useDebounce } from 'use-debounce';
 
+import {
+    DropdownMenu,
+    DropdownMenuContent,
+    DropdownMenuItem,
+    DropdownMenuTrigger
+} from '@/components/ui/dropdown-menu.js';
 import { DisplayComponent } from '@/framework/component-registry/dynamic-component.js';
 import { ResultOf } from '@/graphql/graphql.js';
 import { TypedDocumentNode } from '@graphql-typed-document-node/core';
+import { Trans, useLingui } from '@lingui/react/macro';
 import { useQuery } from '@tanstack/react-query';
 import {
     ColumnFiltersState,
@@ -22,25 +29,10 @@ import {
     Table,
 } from '@tanstack/react-table';
 import { AccessorKeyColumnDef, ColumnDef, Row } from '@tanstack/table-core';
-import React, { useMemo } from 'react';
-import {
-    DropdownMenu,
-    DropdownMenuContent,
-    DropdownMenuGroup,
-    DropdownMenuItem,
-    DropdownMenuLabel,
-    DropdownMenuPortal,
-    DropdownMenuSeparator,
-    DropdownMenuShortcut,
-    DropdownMenuSub,
-    DropdownMenuSubContent,
-    DropdownMenuSubTrigger,
-    DropdownMenuTrigger,
-} from '@/components/ui/dropdown-menu.js';
-import { Button } from '../ui/button.js';
 import { EllipsisIcon, TrashIcon } from 'lucide-react';
-import { Trans, useLingui } from '@lingui/react/macro';
+import React, { useMemo } from 'react';
 import { toast } from 'sonner';
+import { Button } from '../ui/button.js';
 
 // Type that identifies a paginated list structure (has items array and totalItems)
 type IsPaginatedList<T> = T extends { items: any[]; totalItems: number } ? true : false;

+ 9 - 1
packages/dashboard/src/main.tsx

@@ -17,15 +17,23 @@ function InnerApp() {
     const auth = useAuth();
     const extendedRouter = useExtendedRouter(router);
     const serverConfig = useServerConfig();
+    const [hasSetCustomFieldsMap, setHasSetCustomFieldsMap] = React.useState(false);
 
     useEffect(() => {
         if (!serverConfig) {
             return;
         }
         setCustomFieldsMap(serverConfig.entityCustomFields);
+        setHasSetCustomFieldsMap(true);
     }, [serverConfig?.entityCustomFields]);
 
-    return <RouterProvider router={extendedRouter} context={{ auth, queryClient }} />;
+    return (
+        <>
+            {hasSetCustomFieldsMap && (
+                <RouterProvider router={extendedRouter} context={{ auth, queryClient }} />
+            )}
+        </>
+    );
 }
 
 function App() {

+ 4 - 3
packages/dashboard/src/routes/_authenticated/_collections/collections_.$id.tsx

@@ -41,6 +41,7 @@ import {
 import { CollectionContentsPreviewTable } from './components/collection-contents-preview-table.js';
 import { CollectionContentsTable } from './components/collection-contents-table.js';
 import { CollectionFiltersSelector } from './components/collection-filters-selector.js';
+import { RichTextInput } from '@/components/data-input/richt-text-input.js';
 
 export const Route = createFileRoute('/_authenticated/_collections/collections_/$id')({
     component: CollectionDetailPage,
@@ -150,20 +151,20 @@ export function CollectionDetailPage() {
                                 control={form.control}
                                 name="name"
                                 label={<Trans>Name</Trans>}
-                                render={({ field }) => <Input placeholder="" {...field} />}
+                                render={({ field }) => <Input {...field} />}
                             />
                             <TranslatableFormFieldWrapper
                                 control={form.control}
                                 name="slug"
                                 label={<Trans>Slug</Trans>}
-                                render={({ field }) => <Input placeholder="" {...field} />}
+                                render={({ field }) => <Input {...field} />}
                             />
                         </DetailFormGrid>
                         <TranslatableFormFieldWrapper
                             control={form.control}
                             name="description"
                             label={<Trans>Description</Trans>}
-                            render={({ field }) => <Textarea placeholder="" {...field} />}
+                            render={({ field }) => <RichTextInput {...field} />}
                         />
                     </PageBlock>
                     <CustomFieldsPageBlock column="main" entityType="Collection" control={form.control} />

+ 2 - 2
packages/dashboard/src/routes/_authenticated/_payment-methods/payment-methods_.$id.tsx

@@ -1,3 +1,4 @@
+import { RichTextInput } from '@/components/data-input/richt-text-input.js';
 import { ErrorPage } from '@/components/shared/error-page.js';
 import { FormFieldWrapper } from '@/components/shared/form-field-wrapper.js';
 import { PermissionGuard } from '@/components/shared/permission-guard.js';
@@ -5,7 +6,6 @@ import { TranslatableFormFieldWrapper } from '@/components/shared/translatable-f
 import { Button } from '@/components/ui/button.js';
 import { Input } from '@/components/ui/input.js';
 import { Switch } from '@/components/ui/switch.js';
-import { Textarea } from '@/components/ui/textarea.js';
 import { NEW_ENTITY_PATH } from '@/constants.js';
 import {
     CustomFieldsPageBlock,
@@ -144,7 +144,7 @@ export function PaymentMethodDetailPage() {
                                 control={form.control}
                                 name="description"
                                 label={<Trans>Description</Trans>}
-                                render={({ field }) => <Textarea {...field} />}
+                                render={({ field }) => <RichTextInput {...field} />}
                             />
                         </PageBlock>
                         <CustomFieldsPageBlock column="main" entityType="PaymentMethod" control={form.control} />

+ 2 - 1
packages/dashboard/src/routes/_authenticated/_products/products_.$id.tsx

@@ -29,6 +29,7 @@ import { toast } from 'sonner';
 import { CreateProductVariantsDialog } from './components/create-product-variants-dialog.js';
 import { ProductVariantsTable } from './components/product-variants-table.js';
 import { createProductDocument, productDetailDocument, updateProductDocument } from './products.graphql.js';
+import { RichTextInput } from '@/components/data-input/richt-text-input.js';
 
 export const Route = createFileRoute('/_authenticated/_products/products_/$id')({
     component: ProductDetailPage,
@@ -135,7 +136,7 @@ export function ProductDetailPage() {
                             control={form.control}
                             name="description"
                             label={<Trans>Description</Trans>}
-                            render={({ field }) => <Textarea className="resize-none" {...field} />}
+                            render={({ field }) => <RichTextInput {...field} />}
                         />
                     </PageBlock>
                     <CustomFieldsPageBlock column="main" entityType="Product" control={form.control} />

+ 2 - 2
packages/dashboard/src/routes/_authenticated/_promotions/promotions_.$id.tsx

@@ -1,4 +1,5 @@
 import { DateTimeInput } from '@/components/data-input/datetime-input.js';
+import { RichTextInput } from '@/components/data-input/richt-text-input.js';
 import { ErrorPage } from '@/components/shared/error-page.js';
 import { FormFieldWrapper } from '@/components/shared/form-field-wrapper.js';
 import { PermissionGuard } from '@/components/shared/permission-guard.js';
@@ -6,7 +7,6 @@ import { TranslatableFormFieldWrapper } from '@/components/shared/translatable-f
 import { Button } from '@/components/ui/button.js';
 import { Input } from '@/components/ui/input.js';
 import { Switch } from '@/components/ui/switch.js';
-import { Textarea } from '@/components/ui/textarea.js';
 import { NEW_ENTITY_PATH } from '@/constants.js';
 import {
     CustomFieldsPageBlock,
@@ -151,7 +151,7 @@ export function PromotionDetailPage() {
                                 control={form.control}
                                 name="description"
                                 label={<Trans>Description</Trans>}
-                                render={({ field }) => <Textarea {...field} />}
+                                render={({ field }) => <RichTextInput {...field} />}
                             />
                         </div>
                         <DetailFormGrid>

+ 1 - 0
packages/dashboard/src/routes/login.tsx

@@ -20,6 +20,7 @@ export const Route = createFileRoute('/login')({
 
 export default function LoginPage() {
     const auth = useAuth();
+    console.log('login page', auth);
     const isLoading = useRouterState({ select: s => s.isLoading });
     const navigate = Route.useNavigate();
     const search = Route.useSearch();