diff --git a/components.json b/components.json index f29e3f1..458a624 100644 --- a/components.json +++ b/components.json @@ -10,11 +10,15 @@ "cssVariables": true, "prefix": "" }, + "iconLibrary": "lucide", "aliases": { "components": "@/components", "utils": "@/lib/utils", "ui": "@/components/ui", "lib": "@/lib", "hooks": "@/hooks" + }, + "registries": { + "@shadcn-editor": "https://shadcn-editor.vercel.app/r/{name}.json" } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 69d8bd1..ffc885f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,13 @@ "@fontsource-variable/inter": "^5.2.6", "@getalby/sdk": "^5.1.1", "@hookform/resolvers": "^3.9.0", + "@lexical/code": "^0.36.2", + "@lexical/link": "^0.36.2", + "@lexical/list": "^0.36.2", + "@lexical/markdown": "^0.36.2", + "@lexical/react": "^0.36.2", + "@lexical/rich-text": "^0.36.2", + "@lexical/selection": "^0.36.2", "@nostrify/nostrify": "npm:@jsr/nostrify__nostrify@^0.46.4", "@nostrify/react": "npm:@jsr/nostrify__react@^0.2.8", "@radix-ui/react-accordion": "^1.2.0", @@ -33,13 +40,13 @@ "@radix-ui/react-select": "^2.1.1", "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-slider": "^1.2.0", - "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-switch": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-toast": "^1.2.1", "@radix-ui/react-toggle": "^1.1.0", "@radix-ui/react-toggle-group": "^1.1.0", - "@radix-ui/react-tooltip": "^1.1.4", + "@radix-ui/react-tooltip": "^1.2.8", "@tanstack/react-query": "^5.56.2", "@unhead/addons": "^2.0.10", "@unhead/react": "^2.0.10", @@ -49,6 +56,7 @@ "date-fns": "^3.6.0", "embla-carousel-react": "^8.3.0", "input-otp": "^1.2.4", + "lexical": "^0.36.2", "lucide-react": "^0.462.0", "nostr-tools": "^2.13.0", "qrcode": "^1.5.4", @@ -909,31 +917,46 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.0.tgz", - "integrity": "sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.9" + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.0.tgz", - "integrity": "sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.0", - "@floating-ui/utils": "^0.2.9" + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.27.16", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.16.tgz", + "integrity": "sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.6", + "@floating-ui/utils": "^0.2.10", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", - "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.0.0" + "@floating-ui/dom": "^1.7.4" }, "peerDependencies": { "react": ">=16.8.0", @@ -941,9 +964,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", - "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, "node_modules/@fontsource-variable/inter": { @@ -1201,6 +1224,281 @@ "resolved": "https://npm.jsr.io/~/11/@jsr/std__encoding/0.224.3.tgz", "integrity": "sha512-zAuX2QV1zwJ5RSmrnDGVerAtN3pBXpYYNlGzhERW9AiQ1UJd2/xruyB3i5NdTWy2OK2pjETswOj+0+prYTPlxQ==" }, + "node_modules/@lexical/clipboard": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.36.2.tgz", + "integrity": "sha512-l7z52jltlMz1HmJRmG7ZdxySPjheRRxdV/75QEnzalMtqfLPgh4G5IpycISjbX+95PgEaC6rXbcjPix0CyHDJg==", + "license": "MIT", + "dependencies": { + "@lexical/html": "0.36.2", + "@lexical/list": "0.36.2", + "@lexical/selection": "0.36.2", + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/code": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.36.2.tgz", + "integrity": "sha512-dfS62rNo3uKwNAJQ39zC+8gYX0k8UAoW7u+JPIqx+K2VPukZlvpsPLNGft15pdWBkHc7Pv+o9gJlB6gGv+EBfA==", + "license": "MIT", + "dependencies": { + "@lexical/utils": "0.36.2", + "lexical": "0.36.2", + "prismjs": "^1.30.0" + } + }, + "node_modules/@lexical/devtools-core": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/devtools-core/-/devtools-core-0.36.2.tgz", + "integrity": "sha512-G+XW7gR/SCx3YgX4FK9wAIn6AIOkC+j8zRPWrS3GQNZ15CE0QkwQl3IyQ7XW9KzWmdRMs6yTmTVnENFa1JLzXg==", + "license": "MIT", + "dependencies": { + "@lexical/html": "0.36.2", + "@lexical/link": "0.36.2", + "@lexical/mark": "0.36.2", + "@lexical/table": "0.36.2", + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + }, + "peerDependencies": { + "react": ">=17.x", + "react-dom": ">=17.x" + } + }, + "node_modules/@lexical/dragon": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.36.2.tgz", + "integrity": "sha512-VWNjYaH74uQ8MFKkl80pTofojpEnTYSX2sgHyZmo1Lk1cKLHK25pMnWgAxPAMLQD5/RW/2PtZcK+j0Kfoe5lSQ==", + "license": "MIT", + "dependencies": { + "@lexical/extension": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/extension": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/extension/-/extension-0.36.2.tgz", + "integrity": "sha512-NWxtqMFMzScq4Eemqp1ST2KREIfj57fUbn7qHv+mMnYgQZK4iIhrHKo5klonxi1oBURcxUZMIbdtH7MJ4BdisA==", + "license": "MIT", + "dependencies": { + "@lexical/utils": "0.36.2", + "@preact/signals-core": "^1.11.0", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/hashtag": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.36.2.tgz", + "integrity": "sha512-WdmKtzXFcahQT3ShFDeHF6LCR5C8yvFCj3ImI09rZwICrYeonbMrzsBUxS1joBz0HQ+ufF9Tx+RxLvGWx6WxzQ==", + "license": "MIT", + "dependencies": { + "@lexical/text": "0.36.2", + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/history": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.36.2.tgz", + "integrity": "sha512-pnS36gyMWz1yq/3Z2jv0gUxjJfas5j0GZOM4rFTzDAHjRVc5q3Ua4ElwekdcLaPPGpUlcg3jghIGWa2pSeoPvA==", + "license": "MIT", + "dependencies": { + "@lexical/extension": "0.36.2", + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/html": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.36.2.tgz", + "integrity": "sha512-fgqALzgKnoy93G0yFyYD4C4qJTSMZyUt4JE5kj/POFwWNOnXThIqJhQGwBvH/ibImpIfOeds2TrSr8PbStlrNg==", + "license": "MIT", + "dependencies": { + "@lexical/selection": "0.36.2", + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/link": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.36.2.tgz", + "integrity": "sha512-Zb+DeHA1po8VMiOAAXsBmAHhfWmQttsUkI5oiZUmOXJruRuQ2rVr01NoxHpoEpLwHOABVNzD3PMbwov+g3c7lg==", + "license": "MIT", + "dependencies": { + "@lexical/extension": "0.36.2", + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/list": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.36.2.tgz", + "integrity": "sha512-JpaIaE0lgNUrAR7iaCaIoETcCKG9EvZjM3G71VxiexTs7PltmEMq36LUlO2goafWurP7knG2rUpVnTcuSbYYeA==", + "license": "MIT", + "dependencies": { + "@lexical/extension": "0.36.2", + "@lexical/selection": "0.36.2", + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/mark": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.36.2.tgz", + "integrity": "sha512-n0MNXtGH+1i43hglgHjpQV0093HmIiFR7Budg2BJb8ZNzO1KZRqeXAHlA5ZzJ698FkAnS4R5bqG9tZ0JJHgAuA==", + "license": "MIT", + "dependencies": { + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/markdown": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.36.2.tgz", + "integrity": "sha512-jI4McaVKUo8ADOYNCB5LnYyxXDyOWBOofM05r42R9QIMyUxGryo43WNPMAYXzCgtHlkQv+FNles9OlQY0IlAag==", + "license": "MIT", + "dependencies": { + "@lexical/code": "0.36.2", + "@lexical/link": "0.36.2", + "@lexical/list": "0.36.2", + "@lexical/rich-text": "0.36.2", + "@lexical/text": "0.36.2", + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/offset": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.36.2.tgz", + "integrity": "sha512-+QQNwzFW/joes3DhNINpGdEX6O5scUTs4n8pYDyM/3pWb+8oCHRaRtEmpUU9HStbdy/pK2kQ9XdztkrNvP/ilA==", + "license": "MIT", + "dependencies": { + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/overflow": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.36.2.tgz", + "integrity": "sha512-bLaEe93iZIJH5wDh6e/DTZVNz7xO7lMS5akcJW8CIwopr4I/Qv2uCvc4G1bMMHx2xM1gVxstn5rFgIUP8/Gqlg==", + "license": "MIT", + "dependencies": { + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/plain-text": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.36.2.tgz", + "integrity": "sha512-c9F/+WHl2QuXVhu+1bBVo6BIrSjCcixLe5ePKxoUpy+B7W72s3VCoAQZp+pmtPIyodDLmZAx78hZBBlzoIOeeg==", + "license": "MIT", + "dependencies": { + "@lexical/clipboard": "0.36.2", + "@lexical/dragon": "0.36.2", + "@lexical/selection": "0.36.2", + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/react": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.36.2.tgz", + "integrity": "sha512-mPVm1BmeuMsMpVyUplgc0btOI8+Vm9bZj4AftgfMSkvzkr8i6NkLn8LV5IlEnoRvxXkjOExwlwBwdQte5ZGvNw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.27.16", + "@lexical/devtools-core": "0.36.2", + "@lexical/dragon": "0.36.2", + "@lexical/extension": "0.36.2", + "@lexical/hashtag": "0.36.2", + "@lexical/history": "0.36.2", + "@lexical/link": "0.36.2", + "@lexical/list": "0.36.2", + "@lexical/mark": "0.36.2", + "@lexical/markdown": "0.36.2", + "@lexical/overflow": "0.36.2", + "@lexical/plain-text": "0.36.2", + "@lexical/rich-text": "0.36.2", + "@lexical/table": "0.36.2", + "@lexical/text": "0.36.2", + "@lexical/utils": "0.36.2", + "@lexical/yjs": "0.36.2", + "lexical": "0.36.2", + "react-error-boundary": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.x", + "react-dom": ">=17.x" + } + }, + "node_modules/@lexical/rich-text": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.36.2.tgz", + "integrity": "sha512-dZ7zAIv5NBrh1ApxIT9bayn96zfQHHdnT+oaqmR+q100Vo2uROeR/ZF5igeAuwYGM1Z3ZWDBvNxRKd1d6FWiZw==", + "license": "MIT", + "dependencies": { + "@lexical/clipboard": "0.36.2", + "@lexical/dragon": "0.36.2", + "@lexical/selection": "0.36.2", + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/selection": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.36.2.tgz", + "integrity": "sha512-n96joW3HCKBmPeESR172BxVE+m8V9SdidQm4kKb9jOZ1Ota+tnam2386TeI6795TWwgjDQJPK3HZNKcX6Gb+Bg==", + "license": "MIT", + "dependencies": { + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/table": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.36.2.tgz", + "integrity": "sha512-96rNNPiVbC65i+Jn1QzIsehCS7UVUc69ovrh9Bt4+pXDebZSdZai153Q7RUq8q3AQ5ocK4/SA2kLQfMu0grj3Q==", + "license": "MIT", + "dependencies": { + "@lexical/clipboard": "0.36.2", + "@lexical/extension": "0.36.2", + "@lexical/utils": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/text": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.36.2.tgz", + "integrity": "sha512-IbbqgRdMAD6Uk9b2+qSVoy+8RVcczrz6OgXvg39+EYD+XEC7Rbw7kDTWzuNSJJpP7vxSO8YDZSaIlP5gNH3qKA==", + "license": "MIT", + "dependencies": { + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/utils": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.36.2.tgz", + "integrity": "sha512-P9+t2Ob10YNGYT/PWEER+1EqH8SAjCNRn+7SBvKbr0IdleGF2JvzbJwAWaRwZs1c18P11XdQZ779dGvWlfwBIw==", + "license": "MIT", + "dependencies": { + "@lexical/list": "0.36.2", + "@lexical/selection": "0.36.2", + "@lexical/table": "0.36.2", + "lexical": "0.36.2" + } + }, + "node_modules/@lexical/yjs": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.36.2.tgz", + "integrity": "sha512-gZ66Mw+uKXTO8KeX/hNKAinXbFg3gnNYraG76lBXCwb/Ka3q34upIY9FUeGOwGVaau3iIDQhE49I+6MugAX2FQ==", + "license": "MIT", + "dependencies": { + "@lexical/offset": "0.36.2", + "@lexical/selection": "0.36.2", + "lexical": "0.36.2" + }, + "peerDependencies": { + "yjs": ">=13.5.22" + } + }, "node_modules/@noble/ciphers": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.5.3.tgz", @@ -1317,6 +1615,16 @@ "node": ">=14" } }, + "node_modules/@preact/signals-core": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.12.1.tgz", + "integrity": "sha512-BwbTXpj+9QutoZLQvbttRg5x3l5468qaV2kufh+51yha1c53ep5dY4kTuZR35+3pAZxpfQerGJiQqg34ZNZ6uA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, "node_modules/@radix-ui/number": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", @@ -1388,6 +1696,24 @@ } } }, + "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", + "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-arrow": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.4.tgz", @@ -1547,6 +1873,24 @@ } } }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", + "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", @@ -1641,6 +1985,24 @@ } } }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", + "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-direction": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", @@ -1864,6 +2226,24 @@ } } }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", + "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-menubar": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.12.tgz", @@ -1969,6 +2349,24 @@ } } }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", + "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.4.tgz", @@ -2072,6 +2470,24 @@ } } }, + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", + "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-progress": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.4.tgz", @@ -2233,6 +2649,24 @@ } } }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", + "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-separator": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.4.tgz", @@ -2290,9 +2724,9 @@ } }, "node_modules/@radix-ui/react-slot": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", - "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2455,23 +2889,205 @@ } }, "node_modules/@radix-ui/react-tooltip": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.4.tgz", - "integrity": "sha512-DyW8VVeeMSSLFvAmnVnCwvI3H+1tpJFHT50r+tdOoMse9XqYDBCcyux8u3G2y+LOpt7fPQ6KKH0mhs+ce1+Z5w==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.2", + "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.7", + "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.4", - "@radix-ui/react-portal": "1.1.6", - "@radix-ui/react-presence": "1.1.4", - "@radix-ui/react-primitive": "2.1.0", - "@radix-ui/react-slot": "1.2.0", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-visually-hidden": "1.2.0" + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", @@ -5907,6 +6523,17 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, + "node_modules/isomorphic.js": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", + "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==", + "license": "MIT", + "peer": true, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -6047,6 +6674,34 @@ "node": ">= 0.8.0" } }, + "node_modules/lexical": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.36.2.tgz", + "integrity": "sha512-gIDJCmSAhtxD7h95WK17Nz19wCZu92Zn0p1/R45X01S/KAsLCwEtVJ2fTvIJNFTyx3QNJTuGcm5mYgRMUwq8rg==", + "license": "MIT" + }, + "node_modules/lib0": { + "version": "0.2.114", + "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.114.tgz", + "integrity": "sha512-gcxmNFzA4hv8UYi8j43uPlQ7CGcyMJ2KQb5kZASw6SnAKAf10hK12i2fjrS3Cl/ugZa5Ui6WwIu1/6MIXiHttQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "isomorphic.js": "^0.2.4" + }, + "bin": { + "0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js", + "0gentesthtml": "bin/gentesthtml.js", + "0serve": "bin/0serve.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -7674,6 +8329,15 @@ "license": "MIT", "peer": true }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -7787,6 +8451,18 @@ "react": "^18.3.1" } }, + "node_modules/react-error-boundary": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-6.0.0.tgz", + "integrity": "sha512-gdlJjD7NWr0IfkPlaREN2d9uUZUlksrfOx7SX62VRerwXbMY6ftGCIZua1VG1aXFNOimhISsTq+Owp725b9SiA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-hook-form": { "version": "7.56.1", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.56.1.tgz", @@ -8580,6 +9256,12 @@ "dev": true, "license": "MIT" }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", @@ -9835,6 +10517,24 @@ "node": ">=8" } }, + "node_modules/yjs": { + "version": "13.6.27", + "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.27.tgz", + "integrity": "sha512-OIDwaflOaq4wC6YlPBy2L6ceKeKuF7DeTxx+jPzv1FHn9tCZ0ZwSRnUBxD05E3yed46fv/FWJbvR+Ud7x0L7zw==", + "license": "MIT", + "peer": true, + "dependencies": { + "lib0": "^0.2.99" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 6aa3461..9d7832b 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,13 @@ "@fontsource-variable/inter": "^5.2.6", "@getalby/sdk": "^5.1.1", "@hookform/resolvers": "^3.9.0", + "@lexical/code": "^0.36.2", + "@lexical/link": "^0.36.2", + "@lexical/list": "^0.36.2", + "@lexical/markdown": "^0.36.2", + "@lexical/react": "^0.36.2", + "@lexical/rich-text": "^0.36.2", + "@lexical/selection": "^0.36.2", "@nostrify/nostrify": "npm:@jsr/nostrify__nostrify@^0.46.4", "@nostrify/react": "npm:@jsr/nostrify__react@^0.2.8", "@radix-ui/react-accordion": "^1.2.0", @@ -35,13 +42,13 @@ "@radix-ui/react-select": "^2.1.1", "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-slider": "^1.2.0", - "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-switch": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-toast": "^1.2.1", "@radix-ui/react-toggle": "^1.1.0", "@radix-ui/react-toggle-group": "^1.1.0", - "@radix-ui/react-tooltip": "^1.1.4", + "@radix-ui/react-tooltip": "^1.2.8", "@tanstack/react-query": "^5.56.2", "@unhead/addons": "^2.0.10", "@unhead/react": "^2.0.10", @@ -51,6 +58,7 @@ "date-fns": "^3.6.0", "embla-carousel-react": "^8.3.0", "input-otp": "^1.2.4", + "lexical": "^0.36.2", "lucide-react": "^0.462.0", "nostr-tools": "^2.13.0", "qrcode": "^1.5.4", diff --git a/src/components/ProfessionalBlogPostForm.tsx b/src/components/ProfessionalBlogPostForm.tsx new file mode 100644 index 0000000..359848f --- /dev/null +++ b/src/components/ProfessionalBlogPostForm.tsx @@ -0,0 +1,485 @@ +import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { nip19 } from 'nostr-tools'; +import { SerializedEditorState } from 'lexical'; +import { useCurrentUser } from '@/hooks/useCurrentUser'; +import { usePublishBlogPost } from '@/hooks/usePublishBlogPost'; +import { useBlogPost } from '@/hooks/useBlogPost'; +import { useUploadFile } from '@/hooks/useUploadFile'; +import { useIsMobile } from '@/hooks/useIsMobile'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Textarea } from '@/components/ui/textarea'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Separator } from '@/components/ui/separator'; +import { Alert, AlertDescription } from '@/components/ui/alert'; +import { AlertCircle, Loader2, Upload, Image as ImageIcon, FileText, Hash, Calendar } from 'lucide-react'; +import { Editor } from '@/components/blocks/editor-00/editor'; + +interface ProfessionalBlogPostFormProps { + /** Existing post identifier for editing (optional) */ + editIdentifier?: string; +} + +const initialEditorState = { + root: { + children: [ + { + children: [], + direction: "ltr", + format: "", + indent: 0, + type: "paragraph", + version: 1, + }, + ], + direction: "ltr", + format: "", + indent: 0, + type: "root", + version: 1, + }, +} as unknown as SerializedEditorState; + +export function ProfessionalBlogPostForm({ editIdentifier }: ProfessionalBlogPostFormProps) { + const { user } = useCurrentUser(); + const navigate = useNavigate(); + const isMobile = useIsMobile(); + const { mutateAsync: publishPost, isPending: isPublishing } = usePublishBlogPost(); + const { mutateAsync: uploadFile, isPending: isUploading } = useUploadFile(); + + // Load existing post if editing (using the current user's pubkey) + const { data: existingPost, isLoading: isLoadingPost } = useBlogPost( + user?.pubkey || '', + editIdentifier || '' + ); + + const [editorState, setEditorState] = useState(initialEditorState); + const [metadata, setMetadata] = useState({ + identifier: '', + title: '', + summary: '', + image: '', + hashtags: '', + }); + const [showMetadata, setShowMetadata] = useState(true); + + // Load existing post data when editing + useEffect(() => { + if (existingPost && editIdentifier) { + const d = existingPost.tags.find(([name]) => name === 'd')?.[1] || ''; + const title = existingPost.tags.find(([name]) => name === 'title')?.[1] || ''; + const summary = existingPost.tags.find(([name]) => name === 'summary')?.[1] || ''; + const image = existingPost.tags.find(([name]) => name === 'image')?.[1] || ''; + const hashtags = existingPost.tags + .filter(([name]) => name === 't') + .map(([, value]) => value) + .join(', '); + + setMetadata({ + identifier: d, + title, + summary, + image, + hashtags, + }); + + // Convert markdown content to editor state + // We'll use a simple approach - the editor will handle the markdown + // For now, we'll just set it as the initial state + if (existingPost.content) { + try { + // Create a simple editor state with the markdown content as text + // The Lexical markdown plugin should handle conversion + const contentState = { + root: { + children: [ + { + children: [ + { + detail: 0, + format: 0, + mode: "normal", + style: "", + text: existingPost.content, + type: "text", + version: 1, + }, + ], + direction: "ltr", + format: "", + indent: 0, + type: "paragraph", + version: 1, + }, + ], + direction: "ltr", + format: "", + indent: 0, + type: "root", + version: 1, + }, + } as unknown as SerializedEditorState; + setEditorState(contentState); + } catch (error) { + console.error('Failed to parse existing content:', error); + } + } + } + }, [existingPost, editIdentifier]); + + const handleMetadataChange = (field: keyof typeof metadata, value: string) => { + setMetadata(prev => ({ ...prev, [field]: value })); + }; + + const handleImageUpload = async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + + try { + const [[_, url]] = await uploadFile(file); + setMetadata(prev => ({ ...prev, image: url })); + } catch (error) { + console.error('Failed to upload image:', error); + } + }; + + const getMarkdownFromEditor = (): string => { + // Extract text content from the editor state + // In a full implementation, you'd use $convertToMarkdownString with proper transformers + try { + interface EditorNode { + children?: Array<{ text?: string }>; + } + + const root = editorState.root as { children?: EditorNode[] }; + const content = (root.children || []) + .map((child: EditorNode) => { + if (child.children && Array.isArray(child.children)) { + return child.children + .map((textNode) => textNode.text || '') + .join(''); + } + return ''; + }) + .join('\n\n'); + return content; + } catch (error) { + console.error('Failed to extract markdown:', error); + return ''; + } + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!metadata.identifier.trim()) { + alert('Please provide a unique identifier for your post'); + return; + } + + if (!metadata.title.trim()) { + alert('Please provide a title for your post'); + return; + } + + const markdownContent = getMarkdownFromEditor(); + + if (!markdownContent.trim()) { + alert('Please write some content for your post'); + return; + } + + try { + const publishedAt = editIdentifier && existingPost + ? parseInt(existingPost.tags.find(([name]) => name === 'published_at')?.[1] || '0') + : Math.floor(Date.now() / 1000); + + const event = await publishPost({ + identifier: metadata.identifier, + title: metadata.title, + summary: metadata.summary || undefined, + image: metadata.image || undefined, + content: markdownContent, + hashtags: metadata.hashtags + ? metadata.hashtags.split(',').map(t => t.trim()).filter(Boolean) + : undefined, + publishedAt: publishedAt || undefined, + }); + + // Navigate to the post + const naddr = nip19.naddrEncode({ + kind: 30023, + pubkey: event.pubkey, + identifier: metadata.identifier, + }); + navigate(`/${naddr}`); + } catch (error) { + console.error('Failed to publish post:', error); + alert('Failed to publish post. Please try again.'); + } + }; + + if (!user) { + return ( + + + + You must be logged in to create a blog post. + + + ); + } + + // Check if user is trying to edit someone else's post + if (editIdentifier && existingPost && existingPost.pubkey !== user.pubkey) { + return ( + + + + You can only edit your own posts. + + + ); + } + + if (isLoadingPost) { + return ( +
+ +
+ ); + } + + return ( +
+ {/* Header */} +
+
+

+ {editIdentifier ? 'Edit Article' : 'New Article'} +

+

+ {editIdentifier ? 'Update your article' : 'Share your thoughts with the world'} +

+
+
+ + +
+
+ + + + {/* Metadata Section */} + + setShowMetadata(!showMetadata)}> +
+ + + Article Metadata + + +
+
+ {showMetadata && ( + + {/* Identifier */} +
+ + handleMetadataChange('identifier', e.target.value)} + placeholder="my-awesome-article" + required + disabled={!!editIdentifier} + className="font-mono" + /> +

+ URL-friendly identifier (e.g., "my-awesome-article"). Cannot be changed after publishing. +

+
+ + {/* Title */} +
+ + handleMetadataChange('title', e.target.value)} + placeholder="The Amazing Story of..." + required + className="text-lg" + /> +
+ + {/* Summary */} +
+ +