From 2f1d50af5ee4536393d05868bda5a72c9951b99d Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Tue, 10 Dec 2024 12:58:48 -0600 Subject: [PATCH] Add support for Olas media posts --- .changeset/beige-dragons-explain.md | 5 + .changeset/violet-mails-provide.md | 5 + package.json | 12 +- pnpm-lock.yaml | 428 ++++++++++-------- src/app.tsx | 11 + src/components/content/links/video.tsx | 5 +- .../event-types/embedded-reaction.tsx | 2 + .../event-reactions/reaction-group-button.tsx | 1 + src/components/media-post/media-post-card.tsx | 62 +++ .../media-post/media-post-content.tsx | 28 ++ src/components/media-post/media-slides.tsx | 141 ++++++ src/components/note/note-zap-button.tsx | 1 + .../generic-note-timeline/timeline-item.tsx | 7 +- src/components/zap/event-zap-icon-button.tsx | 43 ++ src/const.ts | 17 +- src/helpers/nostr/media.ts | 1 + src/helpers/nostr/post.ts | 2 + .../global/event-factory-provider.tsx | 11 + src/providers/global/index.tsx | 27 +- src/providers/global/publish-provider.tsx | 19 +- src/services/event-factory.ts | 32 ++ src/views/media/index.tsx | 50 ++ src/views/media/media-comments.tsx | 44 ++ src/views/media/media-post-comment-form.tsx | 67 +++ src/views/media/media-post.tsx | 120 +++++ src/views/other-stuff/apps.ts | 8 + src/views/user/about/user-recent-events.tsx | 9 + src/views/user/index.tsx | 1 + src/views/user/media-posts.tsx | 18 + 29 files changed, 950 insertions(+), 227 deletions(-) create mode 100644 .changeset/beige-dragons-explain.md create mode 100644 .changeset/violet-mails-provide.md create mode 100644 src/components/media-post/media-post-card.tsx create mode 100644 src/components/media-post/media-post-content.tsx create mode 100644 src/components/media-post/media-slides.tsx create mode 100644 src/components/zap/event-zap-icon-button.tsx create mode 100644 src/helpers/nostr/media.ts create mode 100644 src/providers/global/event-factory-provider.tsx create mode 100644 src/services/event-factory.ts create mode 100644 src/views/media/index.tsx create mode 100644 src/views/media/media-comments.tsx create mode 100644 src/views/media/media-post-comment-form.tsx create mode 100644 src/views/media/media-post.tsx create mode 100644 src/views/user/media-posts.tsx diff --git a/.changeset/beige-dragons-explain.md b/.changeset/beige-dragons-explain.md new file mode 100644 index 000000000..c5f34896d --- /dev/null +++ b/.changeset/beige-dragons-explain.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Add support for NIP-22 comments on media posts diff --git a/.changeset/violet-mails-provide.md b/.changeset/violet-mails-provide.md new file mode 100644 index 000000000..acc8b464c --- /dev/null +++ b/.changeset/violet-mails-provide.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Add support for Olas media posts diff --git a/package.json b/package.json index b64de5daf..61e30eb36 100644 --- a/package.json +++ b/package.json @@ -28,9 +28,9 @@ "@codemirror/autocomplete": "^6.18.3", "@codemirror/lang-json": "^6.0.1", "@codemirror/language": "^6.10.6", - "@codemirror/view": "^6.35.2", - "@emotion/react": "^11.13.5", - "@emotion/styled": "^11.13.5", + "@codemirror/view": "^6.35.3", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", "@getalby/bitcoin-connect": "^3.6.3", "@getalby/bitcoin-connect-react": "^3.6.3", "@noble/ciphers": "^1.1.3", @@ -45,6 +45,7 @@ "applesauce-channel": "next", "applesauce-content": "next", "applesauce-core": "next", + "applesauce-factory": "next", "applesauce-lists": "next", "applesauce-net": "next", "applesauce-react": "next", @@ -83,6 +84,7 @@ "nostr-idb": "^2.2.0", "nostr-tools": "^2.10.4", "nostr-wasm": "^0.1.0", + "nuka-carousel": "^8.1.1", "prettier": "^3.4.2", "react": "^18.3.1", "react-chartjs-2": "^5.2.0", @@ -99,7 +101,7 @@ "react-router-dom": "^6.28.0", "react-simplemde-editor": "^5.2.0", "react-singleton-hook": "^4.0.1", - "react-use": "^17.5.1", + "react-use": "^17.6.0", "react-virtualized-auto-sizer": "^1.0.24", "react-window": "^1.8.10", "remark-gfm": "^4.0.0", @@ -132,7 +134,7 @@ "@types/lodash.throttle": "^4.1.9", "@types/ngeohash": "^0.6.8", "@types/react": "^18.3.14", - "@types/react-dom": "^18.3.2", + "@types/react-dom": "^18.3.3", "@types/react-window": "^1.8.8", "@types/three": "^0.160.0", "@types/webscopeio__react-textarea-autocomplete": "^4.7.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac04d7b3b..0e81a36b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,13 +23,13 @@ importers: version: 2.0.8 '@chakra-ui/icons': specifier: ^2.2.4 - version: 2.2.4(@chakra-ui/react@2.10.4(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(framer-motion@10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 2.2.4(@chakra-ui/react@2.10.4(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(framer-motion@10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@chakra-ui/media-query': specifier: ^3.3.0 - version: 3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(react@18.3.1))(react@18.3.1) '@chakra-ui/react': specifier: ^2.10.4 - version: 2.10.4(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(framer-motion@10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.10.4(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(framer-motion@10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@chakra-ui/shared-utils': specifier: ^2.0.4 version: 2.0.4 @@ -41,7 +41,7 @@ importers: version: 2.2.6(@chakra-ui/styled-system@2.12.0(react@18.3.1))(react@18.3.1) '@codemirror/autocomplete': specifier: ^6.18.3 - version: 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3) + version: 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3) '@codemirror/lang-json': specifier: ^6.0.1 version: 6.0.1 @@ -49,14 +49,14 @@ importers: specifier: ^6.10.6 version: 6.10.6 '@codemirror/view': - specifier: ^6.35.2 - version: 6.35.2 + specifier: ^6.35.3 + version: 6.35.3 '@emotion/react': - specifier: ^11.13.5 - version: 11.13.5(@types/react@18.3.14)(react@18.3.1) + specifier: ^11.14.0 + version: 11.14.0(@types/react@18.3.14)(react@18.3.1) '@emotion/styled': - specifier: ^11.13.5 - version: 11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1) + specifier: ^11.14.0 + version: 11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1) '@getalby/bitcoin-connect': specifier: ^3.6.3 version: 3.6.3(@types/react@18.3.14)(react@18.3.1)(typescript@5.7.2) @@ -83,34 +83,37 @@ importers: version: 1.3.0 '@uiw/codemirror-theme-github': specifier: ^4.23.6 - version: 4.23.6(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2) + version: 4.23.6(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3) '@uiw/react-codemirror': specifier: ^4.23.6 - version: 4.23.6(@babel/runtime@7.26.0)(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3))(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.35.2)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 4.23.6(@babel/runtime@7.26.0)(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3))(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.0)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.35.3)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@webscopeio/react-textarea-autocomplete': specifier: ^4.9.2 version: 4.9.2(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) applesauce-channel: specifier: next - version: 0.0.0-next-20241207164640(typescript@5.7.2) + version: 0.0.0-next-20241210184957(typescript@5.7.2) applesauce-content: specifier: next - version: 0.0.0-next-20241207164640(typescript@5.7.2) + version: 0.0.0-next-20241210184957(typescript@5.7.2) applesauce-core: specifier: next - version: 0.0.0-next-20241207164640(typescript@5.7.2) + version: 0.0.0-next-20241210184957(typescript@5.7.2) + applesauce-factory: + specifier: next + version: 0.0.0-next-20241210184957(typescript@5.7.2) applesauce-lists: specifier: next - version: 0.0.0-next-20241207164640(typescript@5.7.2) + version: 0.0.0-next-20241210184957(typescript@5.7.2) applesauce-net: specifier: next - version: 0.0.0-next-20241207164640(typescript@5.7.2) + version: 0.0.0-next-20241210184957(typescript@5.7.2) applesauce-react: specifier: next - version: 0.0.0-next-20241207164640(typescript@5.7.2) + version: 0.0.0-next-20241210184957(typescript@5.7.2) applesauce-signer: specifier: next - version: 0.0.0-next-20241207164640(typescript@5.7.2) + version: 0.0.0-next-20241210184957(typescript@5.7.2) bech32: specifier: ^2.0.0 version: 2.0.0 @@ -140,7 +143,7 @@ importers: version: 6.0.1(@lezer/common@1.2.3) codemirror-json-schema: specifier: ^0.7.9 - version: 0.7.9(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3) + version: 0.7.9(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3) dayjs: specifier: ^1.11.13 version: 1.11.13 @@ -213,6 +216,9 @@ importers: nostr-wasm: specifier: ^0.1.0 version: 0.1.0 + nuka-carousel: + specifier: ^8.1.1 + version: 8.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) prettier: specifier: ^3.4.2 version: 3.4.2 @@ -262,8 +268,8 @@ importers: specifier: ^4.0.1 version: 4.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-use: - specifier: ^17.5.1 - version: 17.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^17.6.0 + version: 17.6.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-virtualized-auto-sizer: specifier: ^1.0.24 version: 1.0.24(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -357,7 +363,7 @@ importers: version: 18.3.14 '@types/react-dom': specifier: ^18.2.7 - version: 18.3.2 + version: 18.3.3(@types/react@18.3.14) '@types/react-window': specifier: ^1.8.8 version: 1.8.8 @@ -1107,8 +1113,8 @@ packages: '@codemirror/lang-json@6.0.1': resolution: {integrity: sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==} - '@codemirror/lang-yaml@6.1.1': - resolution: {integrity: sha512-HV2NzbK9bbVnjWxwObuZh5FuPCowx51mEfoFT9y3y+M37fA3+pbxx4I7uePuygFzDsAmCTwQSc/kXh/flab4uw==} + '@codemirror/lang-yaml@6.1.2': + resolution: {integrity: sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw==} '@codemirror/language@6.10.6': resolution: {integrity: sha512-KrsbdCnxEztLVbB5PycWXFxas4EOyk/fPAfruSOnDDppevQgid2XZ+KbJ9u+fDikP/e7MW7HPBTvTb8JlZK9vA==} @@ -1119,20 +1125,20 @@ packages: '@codemirror/search@6.5.8': resolution: {integrity: sha512-PoWtZvo7c1XFeZWmmyaOp2G0XVbOnm+fJzvghqGAktBW3cufwJUWvSCcNG0ppXiBEM05mZu6RhMtXPv2hpllig==} - '@codemirror/state@6.4.1': - resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} + '@codemirror/state@6.5.0': + resolution: {integrity: sha512-MwBHVK60IiIHDcoMet78lxt6iw5gJOGSbNbOIVBHWVXIH4/Nq1+GQgLLGgI1KlnN86WDXsPudVaqYHKBIx7Eyw==} '@codemirror/theme-one-dark@6.1.2': resolution: {integrity: sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==} - '@codemirror/view@6.35.2': - resolution: {integrity: sha512-u04R04XFCYCNaHoNRr37WUUAfnxKPwPdqV+370NiO6i85qB1J/qCD/WbbMJsyJfRWhXIJXAe2BG/oTzAggqv4A==} + '@codemirror/view@6.35.3': + resolution: {integrity: sha512-ScY7L8+EGdPl4QtoBiOzE4FELp7JmNUsBvgBcCakXWM2uiv/K89VAzU3BMDscf0DsACLvTKePbd5+cFDTcei6g==} '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} - '@emotion/cache@11.13.5': - resolution: {integrity: sha512-Z3xbtJ+UcK76eWkagZ1onvn/wAVb1GOMuR15s30Fm2wrMgC7jzpnO2JZXr4eujTTqoQFUrZIw/rT0c6Zzjca1g==} + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} '@emotion/css@11.13.5': resolution: {integrity: sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==} @@ -1152,8 +1158,8 @@ packages: '@emotion/memoize@0.9.0': resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} - '@emotion/react@11.13.5': - resolution: {integrity: sha512-6zeCUxUH+EPF1s+YF/2hPVODeV/7V07YU5x+2tfuRL8MdW6rv5vb2+CBEGTGwBdux0OIERcOS+RzxeK80k2DsQ==} + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} peerDependencies: '@types/react': '*' react: '>=16.8.0' @@ -1167,8 +1173,8 @@ packages: '@emotion/sheet@1.4.0': resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} - '@emotion/styled@11.13.5': - resolution: {integrity: sha512-gnOQ+nGLPvDXgIx119JqGalys64lhMdnNQA9TMxhDA4K0Hq5+++OE20Zs5GxiCV9r814xQ2K5WmtofSpHVW6BQ==} + '@emotion/styled@11.14.0': + resolution: {integrity: sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==} peerDependencies: '@emotion/react': ^11.0.0-rc.0 '@types/react': '*' @@ -1180,8 +1186,8 @@ packages: '@emotion/unitless@0.10.0': resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} - '@emotion/use-insertion-effect-with-fallbacks@1.1.0': - resolution: {integrity: sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==} + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} peerDependencies: react: '>=16.8.0' @@ -1337,8 +1343,8 @@ packages: '@getalby/bitcoin-connect@3.6.3': resolution: {integrity: sha512-mS3hmKGF8P7RH06DFtawc6T738iwz+wGz28XR46tMDKGfZjPrpcCG7R8Wy7n0w1JBgf7Nec79edQ5cDM1Pbrrw==} - '@getalby/lightning-tools@5.1.1': - resolution: {integrity: sha512-qiGWY7AMnQXywNlpEUTm/2u7Qx0C0qV0i3vlAV5ip8xV2quo4hkesHuAh6dBg/p3VC7t1fa9YUe9677hvQ3fVA==} + '@getalby/lightning-tools@5.1.2': + resolution: {integrity: sha512-BwGm8eGbPh59BVa1gI5yJMantBl/Fdps6X4p1ZACnmxz9vDINX8/3aFoOnDlF7yyA2boXWCsReVQSr26Q2yjiQ==} engines: {node: '>=14'} '@getalby/sdk@3.8.2': @@ -1396,6 +1402,9 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + '@marijn/find-cluster-break@1.0.2': + resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + '@noble/ciphers@0.5.3': resolution: {integrity: sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==} @@ -1628,20 +1637,20 @@ packages: '@scure/bip39@1.5.0': resolution: {integrity: sha512-Dop+ASYhnrwm9+HA/HwXg7j2ZqM6yk2fyLWb5znexjctFY3+E+eU8cIWI0Pql0Qx4hPZCijlGq4OL71g+Uz30A==} - '@shikijs/core@1.24.0': - resolution: {integrity: sha512-6pvdH0KoahMzr6689yh0QJ3rCgF4j1XsXRHNEeEN6M4xJTfQ6QPWrmHzIddotg+xPJUPEPzYzYCKzpYyhTI6Gw==} + '@shikijs/core@1.24.2': + resolution: {integrity: sha512-BpbNUSKIwbKrRRA+BQj0BEWSw+8kOPKDJevWeSE/xIqGX7K0xrCZQ9kK0nnEQyrzsUoka1l81ZtJ2mGaCA32HQ==} - '@shikijs/engine-javascript@1.24.0': - resolution: {integrity: sha512-ZA6sCeSsF3Mnlxxr+4wGEJ9Tto4RHmfIS7ox8KIAbH0MTVUkw3roHPHZN+LlJMOHJJOVupe6tvuAzRpN8qK1vA==} + '@shikijs/engine-javascript@1.24.2': + resolution: {integrity: sha512-EqsmYBJdLEwEiO4H+oExz34a5GhhnVp+jH9Q/XjPjmBPc6TE/x4/gD0X3i0EbkKKNqXYHHJTJUpOLRQNkEzS9Q==} - '@shikijs/engine-oniguruma@1.24.0': - resolution: {integrity: sha512-Eua0qNOL73Y82lGA4GF5P+G2+VXX9XnuUxkiUuwcxQPH4wom+tE39kZpBFXfUuwNYxHSkrSxpB1p4kyRW0moSg==} + '@shikijs/engine-oniguruma@1.24.2': + resolution: {integrity: sha512-ZN6k//aDNWRJs1uKB12pturKHh7GejKugowOFGAuG7TxDRLod1Bd5JhpOikOiFqPmKjKEPtEA6mRCf7q3ulDyQ==} - '@shikijs/markdown-it@1.24.0': - resolution: {integrity: sha512-YjYg8jJoTO0cUXUNlFHTZWWFt4wSDOcRd2nM2aB1rnX5RqRlcqwfS2x1vQjlPqmUisv+/GHClvz7uKHeK7ZDBw==} + '@shikijs/markdown-it@1.24.2': + resolution: {integrity: sha512-vLFRZYudSkrWWrtfBBZy7hM5mZjpC54zdxSNDn25nV6uVSilySmbdt70LyfiuTOtrKQ3p7fjuxojxqM/n6qVCg==} - '@shikijs/types@1.24.0': - resolution: {integrity: sha512-aptbEuq1Pk88DMlCe+FzXNnBZ17LCiLIGWAeCWhoFDzia5Q5Krx3DgnULLiouSdd6+LUM39XwXGppqYE0Ghtug==} + '@shikijs/types@1.24.2': + resolution: {integrity: sha512-bdeWZiDtajGLG9BudI0AHet0b6e7FbR0EsE4jpGaI0YwHm/XJunI9+3uZnzFtX65gsyJ6ngCIWUfA4NWRPnBkQ==} '@shikijs/vscode-textmate@9.3.0': resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==} @@ -1767,8 +1776,10 @@ packages: '@types/prop-types@15.7.14': resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} - '@types/react-dom@18.3.2': - resolution: {integrity: sha512-Fqp+rcvem9wEnGr3RY8dYNvSQ8PoLqjZ9HLgaPUOjJJD120uDyOxOjc/39M4Kddp9JQCxpGQbnhVQF0C0ncYVg==} + '@types/react-dom@18.3.3': + resolution: {integrity: sha512-uTYkxTLkYp41nq/ULXyXMtkNT1vu5fXJoqad6uTNCOGat5t9cLgF4vMNLBXsTOXpdOI44XzKPY1M5RRm0bQHuw==} + peerDependencies: + '@types/react': ^18.2.22 '@types/react-window@1.8.8': resolution: {integrity: sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==} @@ -1838,8 +1849,8 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - '@ungap/structured-clone@1.2.0': - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + '@ungap/structured-clone@1.2.1': + resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} '@vitejs/plugin-react@4.3.4': resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==} @@ -1897,26 +1908,29 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - applesauce-channel@0.0.0-next-20241207164640: - resolution: {integrity: sha512-tbyJVm8cblzcOk8lDqt5zVLaozMuyDei2X8S6bzPto0t3mHaNoy29myUSjaxr0eQLBynpfmqUMwIYh9z6e6bqA==} + applesauce-channel@0.0.0-next-20241210184957: + resolution: {integrity: sha512-Hf9hKvoIjil93o2I2BdJ40BePXlQCKcTQECA9rPboJwVpFKIGamZYt2aLaP+D5wusMeYVvYg/bKRefNyGE5lew==} + + applesauce-content@0.0.0-next-20241210184957: + resolution: {integrity: sha512-YqolYoYp3bDMDyarK/FwnFU5Vjeh/EqYPmBsLVXdzW73XLGCPKCHGhV7WRIfjX9mUUQ6tkbaW8IJBiqhpyGHng==} - applesauce-content@0.0.0-next-20241207164640: - resolution: {integrity: sha512-MGyFa5N+zeAu9D9qdq1KFq70iPqKdi1nIxDqrcSWbDaRZVM9XQnpDlRQ2c2OD69xX1zpzBVcVtpAkNDocl8ebA==} + applesauce-core@0.0.0-next-20241210184957: + resolution: {integrity: sha512-B2cF2Ivj10sUfcM2T/tGoDNOb4hR56b3r9mgcIZvxGWcn9M0Zs+4m3/axqXff/25EZCHwM0nSYTZ3YLwbiwrvw==} - applesauce-core@0.0.0-next-20241207164640: - resolution: {integrity: sha512-cxO+7jDvFi/GPyIejWcfO+rXNxYvOZBXu8XsD0lj10YW6s55Q/KqVB+IkCHKZjZeL3nTb30uE8E9OdKcS3oxUw==} + applesauce-factory@0.0.0-next-20241210184957: + resolution: {integrity: sha512-shSpfVyCsi/NC66aLm0/btvaH6nbAbMBEuUjpFJrLUnAHsN238uB0ImqF2F/OULNCwq/+2CvJJ7CkAl4VF59MQ==} - applesauce-lists@0.0.0-next-20241207164640: - resolution: {integrity: sha512-gmn0DbvkQm9rUSwG2z1zGqp16T7/sVPrsGvEPR7xGdJK2umZV9IwSCKN2Ryn3rby9HC+L81voO/UN3TA/qyQag==} + applesauce-lists@0.0.0-next-20241210184957: + resolution: {integrity: sha512-N0JoT/4VBNeMqsz0dlgB5+4x7/kF5HlZiyaz1u9dC2eRJZPMIiTYKS9W4/B+KwwqS/2+euDZd2ejiD9Wrx9nhw==} - applesauce-net@0.0.0-next-20241207164640: - resolution: {integrity: sha512-i0NSC7n9BsXS7QPwbLBZh0U6yj2gMnM75EkH7O19N3hmp/y1MjkIBNR+tF9OmHYG35UDaAp3VukjnAlju0E8Rw==} + applesauce-net@0.0.0-next-20241210184957: + resolution: {integrity: sha512-VVfb4O11NyRQvL9ArIq8HhQui5mFwd/96sep3IWsp5mRLL62oVNg82CMIFR7phuB9fLLSe5k22VKS6bBmEYDlw==} - applesauce-react@0.0.0-next-20241207164640: - resolution: {integrity: sha512-xh7yJPKMFiehsODK6MtilU2fCnWVgu6KQtEs6tg3JMj5J9GO8LIjawR/4YU3gEZ4frmMhb+DNVC/IPfQX3638Q==} + applesauce-react@0.0.0-next-20241210184957: + resolution: {integrity: sha512-a5sJlWCrHI+A/fTKD7DxNbUakqww6qlJitavriouPyiSj8b4GTsSzhsfxiLxMl7P9kTkPuq4FZzE8GMfYTWJDQ==} - applesauce-signer@0.0.0-next-20241207164640: - resolution: {integrity: sha512-nXxyjvJOqsYlta8eZXfxMqfboqyJs8O93BEYaQaIq7zgzVdeuTR2sF4QeZA5ZyLfumMRdwLgLcBS+4Hzgbg+6g==} + applesauce-signer@0.0.0-next-20241210184957: + resolution: {integrity: sha512-irQtLGViBw/YXSsSER1uHbOg2Iv3rrZUyoQiZH5NeDzfGtoAuMJ8UCuAcvc30Zuy9dAvryPJcVfj9iDLUGAGQA==} argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -2029,8 +2043,8 @@ packages: buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - call-bind-apply-helpers@1.0.0: - resolution: {integrity: sha512-CCKAP2tkPau7D3GE8+V8R6sQubA9R5foIzGp+85EXCVSCivuxBNAWqcpn72PKYiIcqoViv/kcUDpaEIMBVi1lQ==} + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} engines: {node: '>= 0.4'} call-bind@1.0.8: @@ -2394,8 +2408,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.71: - resolution: {integrity: sha512-dB68l59BI75W1BUGVTAEJy45CEVuEGy9qPVVQ8pnHyHMn36PLPPoE1mjLH+lo9rKulO3HC2OhbACI/8tCqJBcA==} + electron-to-chromium@1.5.72: + resolution: {integrity: sha512-ZpSAUOZ2Izby7qnZluSrAlGgGQzucmFbN0n64dYzocYxnxV5ufurpj3VgEe4cUp7ir9LmeLxNYo8bVnlM8bQHw==} emittery@1.0.3: resolution: {integrity: sha512-tJdCJitoy2lrC2ldJcqN4vkqJ00lT+tOWNT1hBJjO/3FDMJa5TTIiYGCKGkn/WfCyOzUMObeohbVTj00fhiLiA==} @@ -3320,8 +3334,8 @@ packages: encoding: optional: true - node-releases@2.0.18: - resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} nostr-idb@2.2.0: resolution: {integrity: sha512-hKvu+U7he+mkCGqgwPGvTDhb4D8Qt8C4KJ8fDtJwXwnLA6PBp2+bsAH4ewR62GvtD42PSeFQDXBIYttMb9X7nQ==} @@ -3351,6 +3365,12 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nuka-carousel@8.1.1: + resolution: {integrity: sha512-pOXBwKJCOxAmGh3x5f3tYypbAYNKg1GqL0pXrWIwy+TxN2oskN4EGan8Pp+m/hk6DWgAKCXkfpiplIEQ/qZcSw==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -3622,8 +3642,8 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-kapsule@2.5.1: - resolution: {integrity: sha512-XYPfv68dE34GNLTWIP1keTrMI3xH4m+HycB1G7hszPIYJj043pmhAgEkuJ8DDHGtmDgEk1w81Pa/X6vXvq/euw==} + react-kapsule@2.5.2: + resolution: {integrity: sha512-ptK3/0BBJwS958e0Akn5VkQjeVDA2tM8NrJvlctIPI3OA5zp6Q6AD/MWwvKiMCH/tTI04h8JfGsOztDwJdQHqw==} engines: {node: '>=12'} peerDependencies: react: '>=16.13.1' @@ -3723,8 +3743,8 @@ packages: react: '*' tslib: '*' - react-use@17.5.1: - resolution: {integrity: sha512-LG/uPEVRflLWMwi3j/sZqR00nF6JGqTTDblkXK2nzXsIvij06hXl1V/MZIlwj1OKIQUtlh1l9jK8gLsRyCQxMg==} + react-use@17.6.0: + resolution: {integrity: sha512-OmedEScUMKFfzn1Ir8dBxiLLSOzhKe/dPZwVxcujweSj45aNM7BEGPb9BEVIgVEqEXx6f3/TsXzwIktNgUR02g==} peerDependencies: react: '*' react-dom: '*' @@ -3927,8 +3947,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@1.24.0: - resolution: {integrity: sha512-qIneep7QRwxRd5oiHb8jaRzH15V/S8F3saCXOdjwRLgozZJr5x2yeBhQtqkO3FSzQDwYEFAYuifg4oHjpDghrg==} + shiki@1.24.2: + resolution: {integrity: sha512-TR1fi6mkRrzW+SKT5G6uKuc32Dj2EEa7Kj0k8kGqiBINb+C1TiflVOiT9ta6GqOJtC4fraxO5SLUaKBcSY38Fg==} side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} @@ -4071,8 +4091,8 @@ packages: textarea-caret@3.0.2: resolution: {integrity: sha512-gRzeti2YS4did7UJnPQ47wrjD+vp+CJIe9zbsu0bJ987d8QVLvLNG9757rqiQTIy4hGIeFauTTJt5Xkn51UkXg==} - three-forcegraph@1.42.4: - resolution: {integrity: sha512-r4n2SgntMXzax1tTT3hgnXzWUA1y/GesetEESQYfh+u//wz/rFaNTjSVswTCdV///NwqiH7ThUEa1mmFvplWnQ==} + three-forcegraph@1.42.5: + resolution: {integrity: sha512-39PVCtQ9Ayh0MxeE7/eiqKokCjRVE7seDKIRe47tTkImQDPMani6/Jzxawoy96JJyhdI8Kz3/gmlcfK6iB3EIQ==} engines: {node: '>=12'} peerDependencies: three: '>=0.118.3' @@ -4501,7 +4521,7 @@ snapshots: accessor-fn: 1.5.1 kapsule: 1.16.0 three: 0.170.0 - three-forcegraph: 1.42.4(three@0.170.0) + three-forcegraph: 1.42.5(three@0.170.0) three-render-objects: 1.32.0(three@0.170.0) '@ampproject/remapping@2.3.0': @@ -5204,17 +5224,17 @@ snapshots: framesync: 6.1.2 react: 18.3.1 - '@chakra-ui/icons@2.2.4(@chakra-ui/react@2.10.4(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(framer-motion@10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@chakra-ui/icons@2.2.4(@chakra-ui/react@2.10.4(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(framer-motion@10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: - '@chakra-ui/react': 2.10.4(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(framer-motion@10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@chakra-ui/react': 2.10.4(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(framer-motion@10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 - '@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: '@chakra-ui/breakpoint-utils': 2.0.8 '@chakra-ui/react-env': 3.1.0(react@18.3.1) '@chakra-ui/shared-utils': 2.0.5 - '@chakra-ui/system': 2.6.2(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(react@18.3.1) + '@chakra-ui/system': 2.6.2(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(react@18.3.1) react: 18.3.1 '@chakra-ui/object-utils@2.1.0': {} @@ -5233,14 +5253,14 @@ snapshots: '@chakra-ui/utils': 2.0.15 react: 18.3.1 - '@chakra-ui/react@2.10.4(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(framer-motion@10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@chakra-ui/react@2.10.4(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(framer-motion@10.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@chakra-ui/hooks': 2.4.3(react@18.3.1) '@chakra-ui/styled-system': 2.12.1(react@18.3.1) '@chakra-ui/theme': 3.4.7(@chakra-ui/styled-system@2.12.1(react@18.3.1))(react@18.3.1) '@chakra-ui/utils': 2.2.3(react@18.3.1) - '@emotion/react': 11.13.5(@types/react@18.3.14)(react@18.3.1) - '@emotion/styled': 11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1) + '@emotion/react': 11.14.0(@types/react@18.3.14)(react@18.3.1) + '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1) '@popperjs/core': 2.11.8 '@zag-js/focus-visible': 0.31.1 aria-hidden: 1.2.4 @@ -5277,7 +5297,7 @@ snapshots: csstype: 3.1.3 lodash.mergewith: 4.6.2 - '@chakra-ui/system@2.6.2(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(react@18.3.1)': + '@chakra-ui/system@2.6.2(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(react@18.3.1)': dependencies: '@chakra-ui/color-mode': 2.2.0(react@18.3.1) '@chakra-ui/object-utils': 2.1.0 @@ -5285,8 +5305,8 @@ snapshots: '@chakra-ui/styled-system': 2.9.2 '@chakra-ui/theme-utils': 2.0.21 '@chakra-ui/utils': 2.0.15 - '@emotion/react': 11.13.5(@types/react@18.3.14)(react@18.3.1) - '@emotion/styled': 11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1) + '@emotion/react': 11.14.0(@types/react@18.3.14)(react@18.3.1) + '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1) react: 18.3.1 react-fast-compare: 3.2.2 @@ -5499,18 +5519,18 @@ snapshots: human-id: 1.0.2 prettier: 2.8.8 - '@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3)': + '@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3)': dependencies: '@codemirror/language': 6.10.6 - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.35.2 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.35.3 '@lezer/common': 1.2.3 '@codemirror/commands@6.7.1': dependencies: '@codemirror/language': 6.10.6 - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.35.2 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.35.3 '@lezer/common': 1.2.3 '@codemirror/lang-json@6.0.1': @@ -5518,13 +5538,14 @@ snapshots: '@codemirror/language': 6.10.6 '@lezer/json': 1.0.2 - '@codemirror/lang-yaml@6.1.1(@codemirror/view@6.35.2)': + '@codemirror/lang-yaml@6.1.2(@codemirror/view@6.35.3)': dependencies: - '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3) + '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3) '@codemirror/language': 6.10.6 - '@codemirror/state': 6.4.1 + '@codemirror/state': 6.5.0 '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 '@lezer/yaml': 1.0.3 transitivePeerDependencies: - '@codemirror/view' @@ -5532,8 +5553,8 @@ snapshots: '@codemirror/language@6.10.6': dependencies: - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.35.2 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.35.3 '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 @@ -5541,28 +5562,30 @@ snapshots: '@codemirror/lint@6.8.4': dependencies: - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.35.2 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.35.3 crelt: 1.0.6 '@codemirror/search@6.5.8': dependencies: - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.35.2 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.35.3 crelt: 1.0.6 - '@codemirror/state@6.4.1': {} + '@codemirror/state@6.5.0': + dependencies: + '@marijn/find-cluster-break': 1.0.2 '@codemirror/theme-one-dark@6.1.2': dependencies: '@codemirror/language': 6.10.6 - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.35.2 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.35.3 '@lezer/highlight': 1.2.1 - '@codemirror/view@6.35.2': + '@codemirror/view@6.35.3': dependencies: - '@codemirror/state': 6.4.1 + '@codemirror/state': 6.5.0 style-mod: 4.1.2 w3c-keyname: 2.2.8 @@ -5582,7 +5605,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@emotion/cache@11.13.5': + '@emotion/cache@11.14.0': dependencies: '@emotion/memoize': 0.9.0 '@emotion/sheet': 1.4.0 @@ -5593,7 +5616,7 @@ snapshots: '@emotion/css@11.13.5': dependencies: '@emotion/babel-plugin': 11.13.5 - '@emotion/cache': 11.13.5 + '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 '@emotion/sheet': 1.4.0 '@emotion/utils': 1.4.2 @@ -5616,13 +5639,13 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1)': + '@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1)': dependencies: '@babel/runtime': 7.26.0 '@emotion/babel-plugin': 11.13.5 - '@emotion/cache': 11.13.5 + '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@18.3.1) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 @@ -5642,14 +5665,14 @@ snapshots: '@emotion/sheet@1.4.0': {} - '@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1)': + '@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1)': dependencies: '@babel/runtime': 7.26.0 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.3.1 - '@emotion/react': 11.13.5(@types/react@18.3.14)(react@18.3.1) + '@emotion/react': 11.14.0(@types/react@18.3.14)(react@18.3.1) '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@18.3.1) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) '@emotion/utils': 1.4.2 react: 18.3.1 optionalDependencies: @@ -5659,7 +5682,7 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@18.3.1)': + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@18.3.1)': dependencies: react: 18.3.1 @@ -5747,7 +5770,7 @@ snapshots: '@getalby/bitcoin-connect@3.6.3(@types/react@18.3.14)(react@18.3.1)(typescript@5.7.2)': dependencies: - '@getalby/lightning-tools': 5.1.1 + '@getalby/lightning-tools': 5.1.2 '@getalby/sdk': 3.8.2(typescript@5.7.2) '@lightninglabs/lnc-web': 0.3.2-alpha qrcode-generator: 1.4.4 @@ -5758,7 +5781,7 @@ snapshots: - react - typescript - '@getalby/lightning-tools@5.1.1': {} + '@getalby/lightning-tools@5.1.2': {} '@getalby/sdk@3.8.2(typescript@5.7.2)': dependencies: @@ -5837,6 +5860,8 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 + '@marijn/find-cluster-break@1.0.2': {} + '@noble/ciphers@0.5.3': {} '@noble/ciphers@1.1.3': {} @@ -6025,32 +6050,32 @@ snapshots: '@noble/hashes': 1.6.1 '@scure/base': 1.2.1 - '@shikijs/core@1.24.0': + '@shikijs/core@1.24.2': dependencies: - '@shikijs/engine-javascript': 1.24.0 - '@shikijs/engine-oniguruma': 1.24.0 - '@shikijs/types': 1.24.0 + '@shikijs/engine-javascript': 1.24.2 + '@shikijs/engine-oniguruma': 1.24.2 + '@shikijs/types': 1.24.2 '@shikijs/vscode-textmate': 9.3.0 '@types/hast': 3.0.4 hast-util-to-html: 9.0.3 - '@shikijs/engine-javascript@1.24.0': + '@shikijs/engine-javascript@1.24.2': dependencies: - '@shikijs/types': 1.24.0 + '@shikijs/types': 1.24.2 '@shikijs/vscode-textmate': 9.3.0 oniguruma-to-es: 0.7.0 - '@shikijs/engine-oniguruma@1.24.0': + '@shikijs/engine-oniguruma@1.24.2': dependencies: - '@shikijs/types': 1.24.0 + '@shikijs/types': 1.24.2 '@shikijs/vscode-textmate': 9.3.0 - '@shikijs/markdown-it@1.24.0': + '@shikijs/markdown-it@1.24.2': dependencies: markdown-it: 14.1.0 - shiki: 1.24.0 + shiki: 1.24.2 - '@shikijs/types@1.24.0': + '@shikijs/types@1.24.2': dependencies: '@shikijs/vscode-textmate': 9.3.0 '@types/hast': 3.0.4 @@ -6186,7 +6211,7 @@ snapshots: '@types/prop-types@15.7.14': {} - '@types/react-dom@18.3.2': + '@types/react-dom@18.3.3(@types/react@18.3.14)': dependencies: '@types/react': 18.3.14 @@ -6228,38 +6253,38 @@ snapshots: '@types/zen-observable@0.8.7': {} - '@uiw/codemirror-extensions-basic-setup@4.23.6(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3))(@codemirror/commands@6.7.1)(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)': + '@uiw/codemirror-extensions-basic-setup@4.23.6(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3))(@codemirror/commands@6.7.1)(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)': dependencies: - '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3) + '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3) '@codemirror/commands': 6.7.1 '@codemirror/language': 6.10.6 '@codemirror/lint': 6.8.4 '@codemirror/search': 6.5.8 - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.35.2 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.35.3 - '@uiw/codemirror-theme-github@4.23.6(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)': + '@uiw/codemirror-theme-github@4.23.6(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)': dependencies: - '@uiw/codemirror-themes': 4.23.6(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2) + '@uiw/codemirror-themes': 4.23.6(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3) transitivePeerDependencies: - '@codemirror/language' - '@codemirror/state' - '@codemirror/view' - '@uiw/codemirror-themes@4.23.6(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)': + '@uiw/codemirror-themes@4.23.6(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)': dependencies: '@codemirror/language': 6.10.6 - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.35.2 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.35.3 - '@uiw/react-codemirror@4.23.6(@babel/runtime@7.26.0)(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3))(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.35.2)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@uiw/react-codemirror@4.23.6(@babel/runtime@7.26.0)(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3))(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.0)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.35.3)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.26.0 '@codemirror/commands': 6.7.1 - '@codemirror/state': 6.4.1 + '@codemirror/state': 6.5.0 '@codemirror/theme-one-dark': 6.1.2 - '@codemirror/view': 6.35.2 - '@uiw/codemirror-extensions-basic-setup': 4.23.6(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3))(@codemirror/commands@6.7.1)(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2) + '@codemirror/view': 6.35.3 + '@uiw/codemirror-extensions-basic-setup': 4.23.6(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3))(@codemirror/commands@6.7.1)(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.8)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3) codemirror: 6.0.1(@lezer/common@1.2.3) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -6269,7 +6294,7 @@ snapshots: - '@codemirror/lint' - '@codemirror/search' - '@ungap/structured-clone@1.2.0': {} + '@ungap/structured-clone@1.2.1': {} '@vitejs/plugin-react@4.3.4(vite@5.4.11(@types/node@20.17.6)(terser@5.37.0))': dependencies: @@ -6328,22 +6353,22 @@ snapshots: dependencies: color-convert: 2.0.1 - applesauce-channel@0.0.0-next-20241207164640(typescript@5.7.2): + applesauce-channel@0.0.0-next-20241210184957(typescript@5.7.2): dependencies: - applesauce-core: 0.0.0-next-20241207164640(typescript@5.7.2) + applesauce-core: 0.0.0-next-20241210184957(typescript@5.7.2) nostr-tools: 2.10.4(typescript@5.7.2) rxjs: 7.8.1 transitivePeerDependencies: - supports-color - typescript - applesauce-content@0.0.0-next-20241207164640(typescript@5.7.2): + applesauce-content@0.0.0-next-20241210184957(typescript@5.7.2): dependencies: '@cashu/cashu-ts': 2.0.0-rc1 '@types/hast': 3.0.4 '@types/mdast': 4.0.4 '@types/unist': 3.0.3 - applesauce-core: 0.0.0-next-20241207164640(typescript@5.7.2) + applesauce-core: 0.0.0-next-20241210184957(typescript@5.7.2) mdast-util-find-and-replace: 3.0.1 nostr-tools: 2.10.4(typescript@5.7.2) remark: 15.0.1 @@ -6354,7 +6379,7 @@ snapshots: - supports-color - typescript - applesauce-core@0.0.0-next-20241207164640(typescript@5.7.2): + applesauce-core@0.0.0-next-20241210184957(typescript@5.7.2): dependencies: '@scure/base': 1.2.1 debug: 4.4.0 @@ -6368,13 +6393,22 @@ snapshots: - supports-color - typescript - applesauce-lists@0.0.0-next-20241207164640(typescript@5.7.2): + applesauce-factory@0.0.0-next-20241210184957(typescript@5.7.2): + dependencies: + applesauce-content: 0.0.0-next-20241210184957(typescript@5.7.2) + applesauce-core: 0.0.0-next-20241210184957(typescript@5.7.2) + nostr-tools: 2.10.4(typescript@5.7.2) + transitivePeerDependencies: + - supports-color + - typescript + + applesauce-lists@0.0.0-next-20241210184957(typescript@5.7.2): dependencies: '@noble/hashes': 1.6.1 '@noble/secp256k1': 1.7.1 '@scure/base': 1.2.1 '@types/dom-serial': 1.0.6 - applesauce-core: 0.0.0-next-20241207164640(typescript@5.7.2) + applesauce-core: 0.0.0-next-20241210184957(typescript@5.7.2) debug: 4.4.0 nostr-tools: 2.10.4(typescript@5.7.2) rxjs: 7.8.1 @@ -6382,9 +6416,9 @@ snapshots: - supports-color - typescript - applesauce-net@0.0.0-next-20241207164640(typescript@5.7.2): + applesauce-net@0.0.0-next-20241210184957(typescript@5.7.2): dependencies: - applesauce-core: 0.0.0-next-20241207164640(typescript@5.7.2) + applesauce-core: 0.0.0-next-20241210184957(typescript@5.7.2) nanoid: 5.0.9 nostr-tools: 2.10.4(typescript@5.7.2) rxjs: 7.8.1 @@ -6392,10 +6426,11 @@ snapshots: - supports-color - typescript - applesauce-react@0.0.0-next-20241207164640(typescript@5.7.2): + applesauce-react@0.0.0-next-20241210184957(typescript@5.7.2): dependencies: - applesauce-content: 0.0.0-next-20241207164640(typescript@5.7.2) - applesauce-core: 0.0.0-next-20241207164640(typescript@5.7.2) + applesauce-content: 0.0.0-next-20241210184957(typescript@5.7.2) + applesauce-core: 0.0.0-next-20241210184957(typescript@5.7.2) + applesauce-factory: 0.0.0-next-20241210184957(typescript@5.7.2) nostr-tools: 2.10.4(typescript@5.7.2) react: 18.3.1 rxjs: 7.8.1 @@ -6403,14 +6438,14 @@ snapshots: - supports-color - typescript - applesauce-signer@0.0.0-next-20241207164640(typescript@5.7.2): + applesauce-signer@0.0.0-next-20241210184957(typescript@5.7.2): dependencies: '@noble/hashes': 1.6.1 '@noble/secp256k1': 1.7.1 '@scure/base': 1.2.1 '@types/dom-serial': 1.0.6 - applesauce-core: 0.0.0-next-20241207164640(typescript@5.7.2) - applesauce-net: 0.0.0-next-20241207164640(typescript@5.7.2) + applesauce-core: 0.0.0-next-20241210184957(typescript@5.7.2) + applesauce-net: 0.0.0-next-20241210184957(typescript@5.7.2) debug: 4.4.0 nanoid: 5.0.9 nostr-tools: 2.10.4(typescript@5.7.2) @@ -6545,8 +6580,8 @@ snapshots: browserslist@4.24.2: dependencies: caniuse-lite: 1.0.30001687 - electron-to-chromium: 1.5.71 - node-releases: 2.0.18 + electron-to-chromium: 1.5.72 + node-releases: 2.0.19 update-browserslist-db: 1.1.1(browserslist@4.24.2) buffer-from@1.1.2: {} @@ -6556,14 +6591,14 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - call-bind-apply-helpers@1.0.0: + call-bind-apply-helpers@1.0.1: dependencies: es-errors: 1.3.0 function-bind: 1.1.2 call-bind@1.0.8: dependencies: - call-bind-apply-helpers: 1.0.0 + call-bind-apply-helpers: 1.0.1 es-define-property: 1.0.1 get-intrinsic: 1.2.5 set-function-length: 1.2.2 @@ -6636,34 +6671,34 @@ snapshots: classnames@2.5.1: {} - codemirror-json-schema@0.7.9(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3): + codemirror-json-schema@0.7.9(@codemirror/language@6.10.6)(@codemirror/lint@6.8.4)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3): dependencies: '@codemirror/language': 6.10.6 '@codemirror/lint': 6.8.4 - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.35.2 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.35.3 '@lezer/common': 1.2.3 '@sagold/json-pointer': 5.1.2 - '@shikijs/markdown-it': 1.24.0 + '@shikijs/markdown-it': 1.24.2 best-effort-json-parser: 1.1.2 json-schema: 0.4.0 json-schema-library: 9.3.5 loglevel: 1.9.2 markdown-it: 14.1.0 - shiki: 1.24.0 + shiki: 1.24.2 yaml: 2.6.1 optionalDependencies: - '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3) + '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3) '@codemirror/lang-json': 6.0.1 - '@codemirror/lang-yaml': 6.1.1(@codemirror/view@6.35.2) + '@codemirror/lang-yaml': 6.1.2(@codemirror/view@6.35.3) codemirror-json5: 1.0.3 json5: 2.2.3 codemirror-json5@1.0.3: dependencies: '@codemirror/language': 6.10.6 - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.35.2 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.35.3 '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 json5: 2.2.3 @@ -6678,13 +6713,13 @@ snapshots: codemirror@6.0.1(@lezer/common@1.2.3): dependencies: - '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.2)(@lezer/common@1.2.3) + '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3) '@codemirror/commands': 6.7.1 '@codemirror/language': 6.10.6 '@codemirror/lint': 6.8.4 '@codemirror/search': 6.5.8 - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.35.2 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.35.3 transitivePeerDependencies: - '@lezer/common' @@ -6944,7 +6979,7 @@ snapshots: dunder-proto@1.0.0: dependencies: - call-bind-apply-helpers: 1.0.0 + call-bind-apply-helpers: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 @@ -6962,7 +6997,7 @@ snapshots: dependencies: jake: 10.9.2 - electron-to-chromium@1.5.71: {} + electron-to-chromium@1.5.72: {} emittery@1.0.3: {} @@ -7236,7 +7271,7 @@ snapshots: get-intrinsic@1.2.5: dependencies: - call-bind-apply-helpers: 1.0.0 + call-bind-apply-helpers: 1.0.1 dunder-proto: 1.0.0 es-define-property: 1.0.1 es-errors: 1.3.0 @@ -7838,7 +7873,7 @@ snapshots: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.2.0 + '@ungap/structured-clone': 1.2.1 devlop: 1.1.0 micromark-util-sanitize-uri: 2.0.1 trim-lines: 3.0.1 @@ -8156,7 +8191,7 @@ snapshots: dependencies: whatwg-url: 5.0.0 - node-releases@2.0.18: {} + node-releases@2.0.19: {} nostr-idb@2.2.0(typescript@5.7.2): dependencies: @@ -8199,6 +8234,11 @@ snapshots: dependencies: boolbase: 1.0.0 + nuka-carousel@8.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + object-assign@4.1.1: {} object-inspect@1.13.3: {} @@ -8450,14 +8490,14 @@ snapshots: force-graph: 1.47.0 prop-types: 15.8.1 react: 18.3.1 - react-kapsule: 2.5.1(react@18.3.1) + react-kapsule: 2.5.2(react@18.3.1) react-force-graph-3d@1.25.1(react@18.3.1): dependencies: 3d-force-graph: 1.74.2 prop-types: 15.8.1 react: 18.3.1 - react-kapsule: 2.5.1(react@18.3.1) + react-kapsule: 2.5.2(react@18.3.1) react-hook-form@7.54.0(react@18.3.1): dependencies: @@ -8465,7 +8505,7 @@ snapshots: react-is@16.13.1: {} - react-kapsule@2.5.1(react@18.3.1): + react-kapsule@2.5.2(react@18.3.1): dependencies: jerrypick: 1.1.1 react: 18.3.1 @@ -8579,7 +8619,7 @@ snapshots: react: 18.3.1 tslib: 2.8.1 - react-use@17.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-use@17.6.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@types/js-cookie': 2.2.7 '@xobotyi/scrollbar-width': 1.9.5 @@ -8857,12 +8897,12 @@ snapshots: shebang-regex@3.0.0: {} - shiki@1.24.0: + shiki@1.24.2: dependencies: - '@shikijs/core': 1.24.0 - '@shikijs/engine-javascript': 1.24.0 - '@shikijs/engine-oniguruma': 1.24.0 - '@shikijs/types': 1.24.0 + '@shikijs/core': 1.24.2 + '@shikijs/engine-javascript': 1.24.2 + '@shikijs/engine-oniguruma': 1.24.2 + '@shikijs/types': 1.24.2 '@shikijs/vscode-textmate': 9.3.0 '@types/hast': 3.0.4 @@ -9017,7 +9057,7 @@ snapshots: textarea-caret@3.0.2: {} - three-forcegraph@1.42.4(three@0.170.0): + three-forcegraph@1.42.5(three@0.170.0): dependencies: accessor-fn: 1.5.1 d3-array: 3.2.4 diff --git a/src/app.tsx b/src/app.tsx index 565810d03..5272a0d5f 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -16,6 +16,8 @@ const DVMFeedView = lazy(() => import("./views/discovery/dvm-feed/feed")); const BlindspotHomeView = lazy(() => import("./views/discovery/blindspot")); const BlindspotFeedView = lazy(() => import("./views/discovery/blindspot/feed")); const RelayDiscoveryView = lazy(() => import("./views/discovery/relays/index")); +const MediaFeedView = lazy(() => import("./views/media/index")); +const MediaPostView = lazy(() => import("./views/media/media-post")); import SettingsView from "./views/settings"; import NostrLinkView from "./views/link"; import ProfileView from "./views/profile"; @@ -106,6 +108,7 @@ import ArticlesHomeView from "./views/articles"; import ArticleView from "./views/articles/article"; import WalletView from "./views/wallet"; import SupportView from "./views/support"; +import UserMediaPostsTab from "./views/user/media-posts"; const TracksView = lazy(() => import("./views/tracks")); const UserTracksTab = lazy(() => import("./views/user/tracks")); const UserVideosTab = lazy(() => import("./views/user/videos")); @@ -258,6 +261,7 @@ const router = createHashRouter([ { path: "about", element: }, { path: "notes", element: }, { path: "articles", element: }, + { path: "media", element: }, { path: "streams", element: }, { path: "tracks", element: }, { path: "videos", element: }, @@ -365,6 +369,13 @@ const router = createHashRouter([ }, ], }, + { + path: "media", + children: [ + { path: "", element: }, + { path: ":pointer", element: }, + ], + }, { path: "wiki", children: [ diff --git a/src/components/content/links/video.tsx b/src/components/content/links/video.tsx index 67b815140..4451f8b0f 100644 --- a/src/components/content/links/video.tsx +++ b/src/components/content/links/video.tsx @@ -1,4 +1,4 @@ -import { lazy } from "react"; +import { lazy, VideoHTMLAttributes } from "react"; import styled from "@emotion/styled"; import { isStreamURL, isVideoURL } from "../../../helpers/url"; @@ -15,7 +15,7 @@ const StyledVideo = styled.video` z-index: 1; `; -function TrustVideo({ src }: { src: string }) { +export function TrustVideo({ src, ...props }: { src: string } & VideoHTMLAttributes) { const { blurImages } = useAppSettings(); const { onClick, handleEvent, style } = useElementTrustBlur(); @@ -26,6 +26,7 @@ function TrustVideo({ src }: { src: string }) { style={blurImages ? style : undefined} onClick={blurImages ? onClick : undefined} onPlay={blurImages ? handleEvent : undefined} + {...props} /> ); } diff --git a/src/components/embed-event/event-types/embedded-reaction.tsx b/src/components/embed-event/event-types/embedded-reaction.tsx index c51413f83..041e7b110 100644 --- a/src/components/embed-event/event-types/embedded-reaction.tsx +++ b/src/components/embed-event/event-types/embedded-reaction.tsx @@ -8,6 +8,7 @@ import Timestamp from "../../timestamp"; import ReactionIcon from "../../event-reactions/reaction-icon"; import { NoteLink } from "../../note/note-link"; import { nip25 } from "nostr-tools"; +import DebugEventButton from "../../debug-modal/debug-event-button"; export default function EmbeddedReaction({ event, ...props }: Omit & { event: NostrEvent }) { const pointer = nip25.getReactedEventPointer(event); @@ -24,6 +25,7 @@ export default function EmbeddedReaction({ event, ...props }: Omit} + diff --git a/src/components/event-reactions/reaction-group-button.tsx b/src/components/event-reactions/reaction-group-button.tsx index db3d14c9b..c0bc498bc 100644 --- a/src/components/event-reactions/reaction-group-button.tsx +++ b/src/components/event-reactions/reaction-group-button.tsx @@ -10,6 +10,7 @@ export default function ReactionGroupButton({ if (count <= 1) { return } aria-label="Reaction" {...props} />; } + return ( + + + + + + {post.content.length > 0 && } + + + + + + + + + + + + + + + + + + ); +} diff --git a/src/components/media-post/media-post-content.tsx b/src/components/media-post/media-post-content.tsx new file mode 100644 index 000000000..dd3637b79 --- /dev/null +++ b/src/components/media-post/media-post-content.tsx @@ -0,0 +1,28 @@ +import { Box, BoxProps } from "@chakra-ui/react"; +import { NostrEvent } from "nostr-tools"; +import { useRenderedContent } from "applesauce-react/hooks"; +import { emojis, nostrMentions, links, hashtags } from "applesauce-content/text"; + +import { components } from "../content"; +import { renderGenericUrl } from "../content/links"; +import { nipDefinitions } from "../content/transform/nip-notation"; + +const transformers = [links, nostrMentions, emojis, hashtags, nipDefinitions]; + +const linkRenderers = [renderGenericUrl]; + +const MediaPostContentSymbol = Symbol.for("media-post-content"); + +export default function MediaPostContents({ post, ...props }: { post: NostrEvent } & Omit) { + const content = useRenderedContent(post, components, { + linkRenderers, + transformers, + cacheKey: MediaPostContentSymbol, + }); + + return ( + + {content} + + ); +} diff --git a/src/components/media-post/media-slides.tsx b/src/components/media-post/media-slides.tsx new file mode 100644 index 000000000..6b5ed33e0 --- /dev/null +++ b/src/components/media-post/media-slides.tsx @@ -0,0 +1,141 @@ +import { Box, Flex, FlexProps, IconButton, Spacer } from "@chakra-ui/react"; +import { NostrEvent } from "nostr-tools"; +import { getMediaAttachments, MediaAttachment } from "applesauce-core/helpers/media-attachment"; +import { Carousel, useCarousel } from "nuka-carousel"; +import styled from "@emotion/styled"; + +import { TrustImage, TrustVideo } from "../content/links"; +import { isImageURL, isVideoURL } from "applesauce-core/helpers"; +import { ChevronLeftIcon, ChevronRightIcon } from "../icons"; +import ZapBubbles from "../note/timeline-note/components/zap-bubbles"; + +function CustomArrows() { + const { currentPage, totalPages, wrapMode, goBack, goForward } = useCarousel(); + + const allowWrap = wrapMode === "wrap"; + const enablePrevNavButton = allowWrap || currentPage > 0; + const enableNextNavButton = allowWrap || currentPage < totalPages - 1; + + return ( + + } + onClick={goBack} + aria-label="previous image" + variant="ghost" + h="24" + w="12" + isDisabled={!enablePrevNavButton} + > + PREV + + } + onClick={goForward} + aria-label="next image" + variant="ghost" + h="24" + w="12" + isDisabled={!enableNextNavButton} + > + NEXT + + + ); +} + +function cls(...classes: string[]) { + return classes.filter(Boolean).join(" "); +} +function PageIndicators() { + const { totalPages, currentPage, goToPage } = useCarousel(); + + const className = (index: number) => + cls("nuka-page-indicator", currentPage === index ? "nuka-page-indicator-active" : ""); + + return ( +
+ {[...Array(totalPages)].map((_, index) => ( + + ))} +
+ ); +} + +function MediaAttachmentSlide({ media }: { media: MediaAttachment }) { + if (media.type?.startsWith("video/") || isVideoURL(media.url)) { + return ; + } else if (media.type?.startsWith("image/") || isImageURL(media.url)) { + return ; + } + + return ( + + Unknown media type {media.type ?? "Unknown"} + + ); +} + +const CustomCarousel = styled(Carousel)` + & { + height: 100%; + overflow: hidden; + } + + .nuka-slide-container { + height: 100%; + overflow: hidden; + } + + .nuka-overflow { + overflow-x: scroll; + overflow-y: hidden; + height: 100%; + } + + .nuka-wrapper { + height: 100%; + } +`; + +export default function MediaPostSlides({ + post, + showZaps = true, + ...props +}: { post: NostrEvent; showZaps?: boolean } & Omit) { + const attachments = getMediaAttachments(post); + + if (attachments.length === 1) + return ( + + + + + {showZaps && } + + ); + + return ( + + } + showArrows + dots={ + + {showZaps && } + + + + } + > + {attachments.map((media) => ( + + ))} + + + ); +} diff --git a/src/components/note/note-zap-button.tsx b/src/components/note/note-zap-button.tsx index 0d9ece19a..6381077cf 100644 --- a/src/components/note/note-zap-button.tsx +++ b/src/components/note/note-zap-button.tsx @@ -55,6 +55,7 @@ export default function NoteZapButton({ event, allowComment, showEventPreview, . icon={} aria-label="Zap Note" title="Zap Note" + colorScheme={hasZapped ? "primary" : undefined} {...props} onClick={onOpen} isDisabled={!canZap} diff --git a/src/components/timeline-page/generic-note-timeline/timeline-item.tsx b/src/components/timeline-page/generic-note-timeline/timeline-item.tsx index dd18ec7af..126c67c96 100644 --- a/src/components/timeline-page/generic-note-timeline/timeline-item.tsx +++ b/src/components/timeline-page/generic-note-timeline/timeline-item.tsx @@ -1,6 +1,6 @@ import { ReactNode, memo } from "react"; import { kinds } from "nostr-tools"; -import { Box, Text } from "@chakra-ui/react"; +import { Box } from "@chakra-ui/react"; import { ErrorBoundary } from "../../error-boundary"; import ReplyNote from "./reply-note"; @@ -16,6 +16,8 @@ import { TimelineNote } from "../../note/timeline-note"; import useEventIntersectionRef from "../../../hooks/use-event-intersection-ref"; import ArticleCard from "../../../views/articles/components/article-card"; import EmbeddedUnknown from "../../embed-event/event-types/embedded-unknown"; +import { MEDIA_POST_KIND } from "../../../helpers/nostr/media"; +import MediaPost from "../../media-post/media-post-card"; function TimelineItem({ event, visible, minHeight }: { event: NostrEvent; visible: boolean; minHeight?: number }) { const ref = useEventIntersectionRef(event); @@ -44,6 +46,9 @@ function TimelineItem({ event, visible, minHeight }: { event: NostrEvent; visibl case kinds.LongFormArticle: content = ; break; + case MEDIA_POST_KIND: + content = ; + break; default: content = ; break; diff --git a/src/components/zap/event-zap-icon-button.tsx b/src/components/zap/event-zap-icon-button.tsx new file mode 100644 index 000000000..b3496194a --- /dev/null +++ b/src/components/zap/event-zap-icon-button.tsx @@ -0,0 +1,43 @@ +import { IconButton, IconButtonProps, useDisclosure } from "@chakra-ui/react"; +import { getZapSender } from "applesauce-core/helpers"; + +import useCurrentAccount from "../../hooks/use-current-account"; +import useEventZaps from "../../hooks/use-event-zaps"; +import eventZapsService from "../../services/event-zaps"; +import { NostrEvent } from "../../types/nostr-event"; +import { LightningIcon } from "../icons"; +import ZapModal from "../event-zap-modal"; +import useUserLNURLMetadata from "../../hooks/use-user-lnurl-metadata"; +import { getEventUID } from "../../helpers/nostr/event"; +import { useReadRelays } from "../../hooks/use-client-relays"; + +export default function EventZapIconButton({ + event, + ...props +}: { event: NostrEvent } & Omit) { + const account = useCurrentAccount(); + const { metadata } = useUserLNURLMetadata(event.pubkey); + const zaps = useEventZaps(getEventUID(event)) ?? []; + const { isOpen, onOpen, onClose } = useDisclosure(); + + const readRelays = useReadRelays(); + const onZapped = () => { + onClose(); + eventZapsService.requestZaps(getEventUID(event), readRelays, true); + }; + + const canZap = !!metadata?.allowsNostr || event.tags.some((t) => t[0] === "zap"); + + return ( + <> + } + {...props} + onClick={onOpen} + isDisabled={!canZap} + /> + + {isOpen && } + + ); +} diff --git a/src/const.ts b/src/const.ts index 62afb4409..ac31d39e1 100644 --- a/src/const.ts +++ b/src/const.ts @@ -1,4 +1,5 @@ -import { safeRelayUrls } from "applesauce-core/helpers"; +import { getCoordinateFromAddressPointer, safeRelayUrls } from "applesauce-core/helpers"; +import { EventFactoryClient } from "applesauce-factory"; import { kinds } from "nostr-tools"; export const DEFAULT_SEARCH_RELAYS = safeRelayUrls([ @@ -47,10 +48,14 @@ export const NOSTR_CONNECT_PERMISSIONS = [ ]; export const NEVER_ATTACH_CLIENT_TAG = [kinds.EncryptedDirectMessage]; -export const NIP_89_CLIENT_TAG = [ - "client", - "noStrudel", - "31990:266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5:1686066542546", -]; + +export const NIP_89_CLIENT_APP: EventFactoryClient = { + name: "noStrudel", + address: { + kind: kinds.Handlerinformation, + pubkey: "266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5", + identifier: "1686066542546", + }, +}; export const SUPPORT_PUBKEY = "713978c3094081b34fcf2f5491733b0c22728cd3b7a6946519d40f5f08598af8"; diff --git a/src/helpers/nostr/media.ts b/src/helpers/nostr/media.ts new file mode 100644 index 000000000..f7aa33dcd --- /dev/null +++ b/src/helpers/nostr/media.ts @@ -0,0 +1 @@ +export const MEDIA_POST_KIND = 20; diff --git a/src/helpers/nostr/post.ts b/src/helpers/nostr/post.ts index c7d8f005a..406184a5b 100644 --- a/src/helpers/nostr/post.ts +++ b/src/helpers/nostr/post.ts @@ -155,6 +155,7 @@ export function ensureTagContentMentions(draft: EventTemplate) { return updated; } +/** @deprecated use includeContentHashtags from applesauce-factory instead */ export function createHashtagTags(draft: EventTemplate) { const updatedDraft: EventTemplate = { ...draft, tags: Array.from(draft.tags) }; @@ -214,6 +215,7 @@ export function addPubkeyRelayHints(draft: EventTemplate) { }; } +/** @deprecated use event factory instead */ export function finalizeNote(draft: EventTemplate) { let updated: EventTemplate = { ...draft, tags: Array.from(draft.tags) }; updated.content = correctContentMentions(updated.content); diff --git a/src/providers/global/event-factory-provider.tsx b/src/providers/global/event-factory-provider.tsx new file mode 100644 index 000000000..73cab02cb --- /dev/null +++ b/src/providers/global/event-factory-provider.tsx @@ -0,0 +1,11 @@ +import { useObservable } from "applesauce-react/hooks"; +import { FactoryProvider } from "applesauce-react/providers"; + +import eventFactoryService from "../../services/event-factory"; +import { PropsWithChildren } from "react"; + +export default function EventFactoryProvider({ children }: PropsWithChildren) { + const factory = useObservable(eventFactoryService.subject); + + return {children}; +} diff --git a/src/providers/global/index.tsx b/src/providers/global/index.tsx index c45a77760..5b97e982a 100644 --- a/src/providers/global/index.tsx +++ b/src/providers/global/index.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from "react"; import { ChakraProvider, localStorageManager } from "@chakra-ui/react"; -import { QueryStoreProvider } from "applesauce-react"; +import { QueryStoreProvider } from "applesauce-react/providers"; import { SigningProvider } from "./signing-provider"; import buildTheme from "../../theme"; @@ -12,6 +12,7 @@ import DMTimelineProvider from "./dms-provider"; import PublishProvider from "./publish-provider"; import WebOfTrustProvider from "./web-of-trust-provider"; import { queryStore } from "../../services/event-store"; +import EventFactoryProvider from "./event-factory-provider"; function ThemeProviders({ children }: { children: React.ReactNode }) { const { theme: themeName, primaryColor, maxPageWidth } = useAppSettings(); @@ -33,17 +34,19 @@ export const GlobalProviders = ({ children }: { children: React.ReactNode }) => - - - - - - {children} - - - - - + + + + + + + {children} + + + + + + diff --git a/src/providers/global/publish-provider.tsx b/src/providers/global/publish-provider.tsx index 296a8ff95..3586adc6f 100644 --- a/src/providers/global/publish-provider.tsx +++ b/src/providers/global/publish-provider.tsx @@ -1,6 +1,7 @@ import { PropsWithChildren, createContext, useCallback, useContext, useMemo, useState } from "react"; import { useToast } from "@chakra-ui/react"; -import { EventTemplate, NostrEvent, UnsignedEvent, getEventHash, kinds } from "nostr-tools"; +import { EventTemplate, NostrEvent, UnsignedEvent, kinds } from "nostr-tools"; +import { includeClientTag } from "applesauce-factory/operations"; import { useSigningContext } from "./signing-provider"; import { DraftNostrEvent } from "../../types/nostr-event"; @@ -9,11 +10,10 @@ import clientRelaysService from "../../services/client-relays"; import RelaySet from "../../classes/relay-set"; import { cloneEvent, getAllRelayHints, isReplaceable } from "../../helpers/nostr/event"; import replaceableEventsService from "../../services/replaceable-events"; -import eventReactionsService from "../../services/event-reactions"; import { localRelay } from "../../services/local-relay"; import deleteEventService from "../../services/delete-events"; import localSettings from "../../services/local-settings"; -import { NEVER_ATTACH_CLIENT_TAG, NIP_89_CLIENT_TAG } from "../../const"; +import { NEVER_ATTACH_CLIENT_TAG, NIP_89_CLIENT_APP } from "../../const"; import { eventStore } from "../../services/event-store"; import { addPubkeyRelayHints } from "../../helpers/nostr/post"; import useCurrentAccount from "../../hooks/use-current-account"; @@ -70,19 +70,24 @@ export default function PublishProvider({ children }: PropsWithChildren) { const outBoxes = useUserOutbox(account?.pubkey); const finalizeDraft = useCallback( - (event: EventTemplate | NostrEvent) => { + async (event: EventTemplate | NostrEvent) => { let draft = cloneEvent(event.kind, event); // add pubkey relay hints draft = addPubkeyRelayHints(draft); // add client tag - if (localSettings.addClientTag.value && !NEVER_ATTACH_CLIENT_TAG.includes(draft.kind)) { - draft.tags = [...draft.tags.filter((t) => t[0] !== "client"), NIP_89_CLIENT_TAG]; + if ( + localSettings.addClientTag.value && + !NEVER_ATTACH_CLIENT_TAG.includes(draft.kind) && + !draft.tags.some((t) => t[0] === "client") + ) { + // TODO: this should be removed when all events are created using the event factory + draft = await includeClientTag(NIP_89_CLIENT_APP.name, NIP_89_CLIENT_APP.address)(draft, {}); } // request signature - return signerFinalize(draft); + return await signerFinalize(draft); }, [signerFinalize], ); diff --git a/src/services/event-factory.ts b/src/services/event-factory.ts new file mode 100644 index 000000000..e3504af4a --- /dev/null +++ b/src/services/event-factory.ts @@ -0,0 +1,32 @@ +import { BehaviorSubject, Observable } from "rxjs"; +import { EventFactory } from "applesauce-factory"; +import { Account } from "../classes/accounts/account"; +import { getEventRelayHints } from "./event-relay-hint"; +import { NIP_89_CLIENT_APP } from "../const"; +import accountService from "./account"; + +class EventFactoryService { + subject = new BehaviorSubject(null); + + get factory() { + return this.subject.value; + } + + constructor(account: Observable) { + account.subscribe((current) => { + if (!current) this.subject.next(null); + else + this.subject.next( + new EventFactory({ + signer: current.signer, + getRelayHint: (event) => getEventRelayHints(event, 1)[0], + client: NIP_89_CLIENT_APP, + }), + ); + }); + } +} + +const eventFactoryService = new EventFactoryService(accountService.current); + +export default eventFactoryService; diff --git a/src/views/media/index.tsx b/src/views/media/index.tsx new file mode 100644 index 000000000..0226ae53e --- /dev/null +++ b/src/views/media/index.tsx @@ -0,0 +1,50 @@ +import { useCallback } from "react"; +import { Flex } from "@chakra-ui/react"; +import { NostrEvent } from "nostr-tools"; + +import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider"; +import useClientSideMuteFilter from "../../hooks/use-client-side-mute-filter"; +import { useReadRelays } from "../../hooks/use-client-relays"; +import useTimelineLoader from "../../hooks/use-timeline-loader"; +import { MEDIA_POST_KIND } from "../../helpers/nostr/media"; +import PeopleListSelection from "../../components/people-list-selection/people-list-selection"; +import TimelinePage from "../../components/timeline-page"; + +function MediaFeedPage() { + const muteFilter = useClientSideMuteFilter(); + const eventFilter = useCallback( + (event: NostrEvent) => { + if (muteFilter(event)) return false; + return true; + }, + [muteFilter], + ); + + const relays = useReadRelays(); + const { listId, filter } = usePeopleListContext(); + + const { loader, timeline } = useTimelineLoader( + `${listId}-media-feed`, + relays, + filter ? { ...filter, kinds: [MEDIA_POST_KIND] } : undefined, + { + eventFilter, + }, + ); + + const header = ( + + + + ); + + return ; +} + +export default function MediaFeedView() { + return ( + + + + ); +} diff --git a/src/views/media/media-comments.tsx b/src/views/media/media-comments.tsx new file mode 100644 index 000000000..e5674750e --- /dev/null +++ b/src/views/media/media-comments.tsx @@ -0,0 +1,44 @@ +import { Box, ButtonGroup } from "@chakra-ui/react"; +import { NostrEvent } from "nostr-tools"; +import { COMMENT_KIND } from "applesauce-core/helpers"; +import { useStoreQuery } from "applesauce-react/hooks"; +import { CommentsQuery } from "applesauce-core/queries"; + +import { useReadRelays } from "../../hooks/use-client-relays"; +import UserLink from "../../components/user/user-link"; +import DebugEventButton from "../../components/debug-modal/debug-event-button"; +import useTimelineLoader from "../../hooks/use-timeline-loader"; +import IntersectionObserverProvider from "../../providers/local/intersection-observer"; +import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback"; +import TextNoteContents from "../../components/note/timeline-note/text-note-contents"; +import Timestamp from "../../components/timestamp"; + +function Comment({ comment }: { comment: NostrEvent }) { + return ( + + + + + + + + + + + + ); +} + +export function MediaPostComments({ post }: { post: NostrEvent }) { + const readRelays = useReadRelays(); + const { loader } = useTimelineLoader(`${post.id}-comments`, readRelays, { kinds: [COMMENT_KIND], "#E": [post.id] }); + + const comments = useStoreQuery(CommentsQuery, [post]); + const callback = useTimelineCurserIntersectionCallback(loader); + + return ( + + {comments?.map((comment) => )} + + ); +} diff --git a/src/views/media/media-post-comment-form.tsx b/src/views/media/media-post-comment-form.tsx new file mode 100644 index 000000000..8b495cb1f --- /dev/null +++ b/src/views/media/media-post-comment-form.tsx @@ -0,0 +1,67 @@ +import { useRef } from "react"; +import { Box, ComponentWithAs, Flex, FlexProps, IconButton, useToast } from "@chakra-ui/react"; +import { useForm } from "react-hook-form"; +import { NostrEvent } from "nostr-tools"; +import { useEventFactory } from "applesauce-react/hooks"; + +import { usePublishEvent } from "../../providers/global/publish-provider"; +import { useContextEmojis } from "../../providers/global/emoji-provider"; +import { MagicInput, RefType } from "../../components/magic-textarea"; +import useTextAreaUploadFile, { useTextAreaInsertTextWithForm } from "../../hooks/use-textarea-upload-file"; +import { useWriteRelays } from "../../hooks/use-client-relays"; +import MessageSquare01 from "../../components/icons/message-square-01"; + +export default function MediaPostCommentForm({ + post, + ...props +}: { post: NostrEvent } & Omit) { + const toast = useToast(); + const publish = usePublishEvent(); + const emojis = useContextEmojis(); + const factory = useEventFactory(); + + const relays = useWriteRelays(); + const { setValue, handleSubmit, formState, reset, getValues, watch } = useForm({ + defaultValues: { content: "" }, + }); + const sendMessage = handleSubmit(async (values) => { + try { + if (!factory) throw new Error("Missing factory"); + let draft = await factory.comment(post, values.content); + const pub = await publish("Comment", draft, relays); + if (pub) reset(); + } catch (error) { + if (error instanceof Error) toast({ description: error.message, status: "error" }); + } + }); + + const textAreaRef = useRef(null); + const insertText = useTextAreaInsertTextWithForm(textAreaRef, getValues, setValue); + const { onPaste } = useTextAreaUploadFile(insertText); + + watch("content"); + + return ( + <> + + (textAreaRef.current = inst)} + placeholder="Comment" + autoComplete="off" + isRequired + value={getValues().content} + onChange={(e) => setValue("content", e.target.value, { shouldDirty: true })} + // @ts-expect-error + onPaste={onPaste} + /> + } + aria-label="Comment" + /> + + + ); +} diff --git a/src/views/media/media-post.tsx b/src/views/media/media-post.tsx new file mode 100644 index 000000000..fcaaeb003 --- /dev/null +++ b/src/views/media/media-post.tsx @@ -0,0 +1,120 @@ +import { Box, ButtonGroup, Flex, Heading, Spinner } from "@chakra-ui/react"; +import { NostrEvent } from "nostr-tools"; +import { COMMENT_KIND } from "applesauce-core/helpers"; +import { useStoreQuery } from "applesauce-react/hooks"; +import { CommentsQuery } from "applesauce-core/queries"; + +import { useReadRelays } from "../../hooks/use-client-relays"; +import useParamsEventPointer from "../../hooks/use-params-event-pointer"; +import useSingleEvent from "../../hooks/use-single-event"; +import UserAvatarLink from "../../components/user/user-avatar-link"; +import UserLink from "../../components/user/user-link"; +import UserDnsIdentity from "../../components/user/user-dns-identity"; +import MediaPostSlides from "../../components/media-post/media-slides"; +import MediaPostContents from "../../components/media-post/media-post-content"; +import { TrustProvider } from "../../providers/local/trust-provider"; +import DebugEventButton from "../../components/debug-modal/debug-event-button"; +import RepostButton from "../../components/note/timeline-note/components/repost-button"; +import QuoteEventButton from "../../components/note/quote-event-button"; +import useTimelineLoader from "../../hooks/use-timeline-loader"; +import IntersectionObserverProvider from "../../providers/local/intersection-observer"; +import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback"; +import { useBreakpointValue } from "../../providers/global/breakpoint-provider"; +import EventZapIconButton from "../../components/zap/event-zap-icon-button"; +import AddReactionButton from "../../components/note/timeline-note/components/add-reaction-button"; +import EventReactionButtons from "../../components/event-reactions/event-reactions"; +import { MediaPostComments } from "./media-comments"; +import MediaPostCommentForm from "./media-post-comment-form"; + +function Header({ post }: { post: NostrEvent }) { + return ( + + + + + + + + + + + + + + ); +} + +function Actions({ post }: { post: NostrEvent }) { + return ( + + + + + + ); +} + +function HorizontalLayout({ post }: { post: NostrEvent }) { + return ( + +
+ + + + + + + + + + + + + Comments: + + + + + + + ); +} + +function VerticalLayout({ post }: { post: NostrEvent }) { + return ( + +
+ + + + + + + + Comments: + + + + + ); +} + +function MediaPostPage({ post }: { post: NostrEvent }) { + const Layout = useBreakpointValue({ base: VerticalLayout, lg: HorizontalLayout }) || VerticalLayout; + + return ( + + + + ); +} + +export default function MediaPostView() { + const pointer = useParamsEventPointer("pointer"); + const readRelays = useReadRelays(pointer.relays); + + const post = useSingleEvent(pointer.id, readRelays); + + if (post) return ; + else return ; +} diff --git a/src/views/other-stuff/apps.ts b/src/views/other-stuff/apps.ts index 42a5f3366..c59e1ae0e 100644 --- a/src/views/other-stuff/apps.ts +++ b/src/views/other-stuff/apps.ts @@ -23,6 +23,7 @@ import MessageQuestionSquare from "../../components/icons/message-question-squar import UploadCloud01 from "../../components/icons/upload-cloud-01"; import Edit04 from "../../components/icons/edit-04"; import Users03 from "../../components/icons/users-03"; +import Camera01 from "../../components/icons/camera-01"; export const internalApps: App[] = [ { @@ -32,6 +33,13 @@ export const internalApps: App[] = [ id: "streams", to: "/streams", }, + { + title: "Media", + description: "Browser media posts", + icon: Camera01, + id: "media", + to: "/media", + }, { title: "Communities", description: "Create and manage communities", diff --git a/src/views/user/about/user-recent-events.tsx b/src/views/user/about/user-recent-events.tsx index 993fe987f..bc910d98c 100644 --- a/src/views/user/about/user-recent-events.tsx +++ b/src/views/user/about/user-recent-events.tsx @@ -22,6 +22,8 @@ import { useUserOutbox } from "../../../hooks/use-user-mailboxes"; import { useReadRelays } from "../../../hooks/use-client-relays"; import AlertTriangle from "../../../components/icons/alert-triangle"; import MessageSquare02 from "../../../components/icons/message-square-02"; +import Camera01 from "../../../components/icons/camera-01"; +import { MEDIA_POST_KIND } from "../../../helpers/nostr/media"; type KnownKind = { kind: number; @@ -75,6 +77,13 @@ const KnownKinds: KnownKind[] = [ link: (_, p) => `/u/${npubEncode(p)}/articles`, }, + { + kind: MEDIA_POST_KIND, + name: "Media", + icon: Camera01, + link: (_, p) => `/u/${npubEncode(p)}/media`, + }, + { kind: kinds.EncryptedDirectMessage, name: "Legacy DMs", diff --git a/src/views/user/index.tsx b/src/views/user/index.tsx index e8063e2f1..2fbbfbe22 100644 --- a/src/views/user/index.tsx +++ b/src/views/user/index.tsx @@ -45,6 +45,7 @@ const tabs = [ { label: "Notes", path: "notes" }, { label: "Articles", path: "articles" }, { label: "Streams", path: "streams" }, + { label: "Media", path: "media" }, { label: "Zaps", path: "zaps" }, { label: "Lists", path: "lists" }, { label: "Following", path: "following" }, diff --git a/src/views/user/media-posts.tsx b/src/views/user/media-posts.tsx new file mode 100644 index 000000000..650d89b2c --- /dev/null +++ b/src/views/user/media-posts.tsx @@ -0,0 +1,18 @@ +import { useOutletContext } from "react-router-dom"; + +import { useAdditionalRelayContext } from "../../providers/local/additional-relay-context"; +import useTimelineLoader from "../../hooks/use-timeline-loader"; +import TimelinePage from "../../components/timeline-page"; +import { MEDIA_POST_KIND } from "../../helpers/nostr/media"; + +export default function UserMediaPostsTab() { + const { pubkey } = useOutletContext() as { pubkey: string }; + const readRelays = useAdditionalRelayContext(); + + const { loader, timeline } = useTimelineLoader(pubkey + "-media-posts", readRelays, { + authors: [pubkey], + kinds: [MEDIA_POST_KIND], + }); + + return ; +}