diff --git a/.changeset/chilled-fishes-hunt.md b/.changeset/chilled-fishes-hunt.md new file mode 100644 index 000000000..1584dab8e --- /dev/null +++ b/.changeset/chilled-fishes-hunt.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Add tools menu under thread post diff --git a/package.json b/package.json index f1f147511..4a56b38e8 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@codemirror/autocomplete": "^6.18.3", "@codemirror/lang-json": "^6.0.1", "@codemirror/language": "^6.10.3", - "@codemirror/view": "^6.34.2", + "@codemirror/view": "^6.34.3", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@fedimint/core-web": "^0.0.7", @@ -114,7 +114,7 @@ "workbox-core": "7.0.0", "workbox-precaching": "7.0.0", "workbox-routing": "7.0.0", - "yet-another-react-lightbox": "^3.21.6", + "yet-another-react-lightbox": "^3.21.7", "zen-observable": "^0.10.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 526f20d8d..7cbc76278 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)(@lezer/common@1.2.3) + version: 6.18.3(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)(@lezer/common@1.2.3) '@codemirror/lang-json': specifier: ^6.0.1 version: 6.0.1 @@ -49,8 +49,8 @@ importers: specifier: ^6.10.3 version: 6.10.3 '@codemirror/view': - specifier: ^6.34.2 - version: 6.34.2 + specifier: ^6.34.3 + version: 6.34.3 '@emotion/react': specifier: ^11.13.3 version: 11.13.3(@types/react@18.3.12)(react@18.3.1) @@ -86,34 +86,34 @@ importers: version: 1.3.0 '@uiw/codemirror-theme-github': specifier: ^4.23.6 - version: 4.23.6(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2) + version: 4.23.6(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.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.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)(@lezer/common@1.2.3))(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.34.2)(codemirror@5.65.18)(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.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)(@lezer/common@1.2.3))(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.34.3)(codemirror@5.65.18)(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-20241114194041(typescript@5.6.3) + version: 0.0.0-next-20241115160057(typescript@5.6.3) applesauce-content: specifier: next - version: 0.0.0-next-20241114194041(typescript@5.6.3) + version: 0.0.0-next-20241115160057(typescript@5.6.3) applesauce-core: specifier: next - version: 0.0.0-next-20241114194041(typescript@5.6.3) + version: 0.0.0-next-20241115160057(typescript@5.6.3) applesauce-lists: specifier: next - version: 0.0.0-next-20241114194041(typescript@5.6.3) + version: 0.0.0-next-20241115160057(typescript@5.6.3) applesauce-net: specifier: next - version: 0.0.0-next-20241114194041(typescript@5.6.3) + version: 0.0.0-next-20241115160057(typescript@5.6.3) applesauce-react: specifier: next - version: 0.0.0-next-20241114194041(typescript@5.6.3) + version: 0.0.0-next-20241115160057(typescript@5.6.3) applesauce-signer: specifier: next - version: 0.0.0-next-20241114194041(typescript@5.6.3) + version: 0.0.0-next-20241115160057(typescript@5.6.3) bech32: specifier: ^2.0.0 version: 2.0.0 @@ -137,7 +137,7 @@ importers: version: 2.6.0 codemirror-json-schema: specifier: ^0.6.1 - version: 0.6.1(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)(@lezer/common@1.2.3) + version: 0.6.1(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)(@lezer/common@1.2.3) dayjs: specifier: ^1.11.13 version: 1.11.13 @@ -307,8 +307,8 @@ importers: specifier: 7.0.0 version: 7.0.0 yet-another-react-lightbox: - specifier: ^3.21.6 - version: 3.21.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^3.21.7 + version: 3.21.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) zen-observable: specifier: ^0.10.0 version: 0.10.0 @@ -1130,8 +1130,8 @@ packages: '@codemirror/theme-one-dark@6.1.2': resolution: {integrity: sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==} - '@codemirror/view@6.34.2': - resolution: {integrity: sha512-d6n0WFvL970A9Z+l9N2dO+Hk9ev4hDYQzIx+B9tCyBP0W5wPEszi1rhuyFesNSkLZzXbQE5FPH7F/z/TMJfoPA==} + '@codemirror/view@6.34.3': + resolution: {integrity: sha512-Ph5d+u8DxIeSgssXEakaakImkzBV4+slwIbcxl9oc9evexJhImeu/G8TK7+zp+IFK9KuJ0BdSn6kTBJeH2CHvA==} '@emotion/babel-plugin@11.12.0': resolution: {integrity: sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==} @@ -1516,93 +1516,93 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.26.0': - resolution: {integrity: sha512-gJNwtPDGEaOEgejbaseY6xMFu+CPltsc8/T+diUTTbOQLqD+bnrJq9ulH6WD69TqwqWmrfRAtUv30cCFZlbGTQ==} + '@rollup/rollup-android-arm-eabi@4.27.0': + resolution: {integrity: sha512-e312hTjuM89YLqlcqEs7mSvwhxN5pgXqRobUob7Jsz1wDQlpAb2WTX4jzvrx5NrL1h2SE4fGdHSNyPxbLfzyeA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.26.0': - resolution: {integrity: sha512-YJa5Gy8mEZgz5JquFruhJODMq3lTHWLm1fOy+HIANquLzfIOzE9RA5ie3JjCdVb9r46qfAQY/l947V0zfGJ0OQ==} + '@rollup/rollup-android-arm64@4.27.0': + resolution: {integrity: sha512-cBUOny8GNXP++gN00Bo5L04I2oqUEFAU0OSDb+4hqp4/R/pZL/zlGzp7lJkhtPX52Rj+PIe0S8aOqhK4hztxHQ==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.26.0': - resolution: {integrity: sha512-ErTASs8YKbqTBoPLp/kA1B1Um5YSom8QAc4rKhg7b9tyyVqDBlQxy7Bf2wW7yIlPGPg2UODDQcbkTlruPzDosw==} + '@rollup/rollup-darwin-arm64@4.27.0': + resolution: {integrity: sha512-aauK2M2ptFQQYdOqbKGYCg1LHlPbm6IxepSnHLLaMIGcd9YBiKRGl2+KtzQL/IkurP+b54EKBkvtZaWXijmzfQ==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.26.0': - resolution: {integrity: sha512-wbgkYDHcdWW+NqP2mnf2NOuEbOLzDblalrOWcPyY6+BRbVhliavon15UploG7PpBRQ2bZJnbmh8o3yLoBvDIHA==} + '@rollup/rollup-darwin-x64@4.27.0': + resolution: {integrity: sha512-VAjOnHUwpvxf3XT33sMpsLGKq24Rz1sTQhLuUicYrV9pxB4TNi0w11qAGPOyR+dQu/iZf88DmEmG0+2Gaqa1gg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.26.0': - resolution: {integrity: sha512-Y9vpjfp9CDkAG4q/uwuhZk96LP11fBz/bYdyg9oaHYhtGZp7NrbkQrj/66DYMMP2Yo/QPAsVHkV891KyO52fhg==} + '@rollup/rollup-freebsd-arm64@4.27.0': + resolution: {integrity: sha512-I2eRlZG87gl6WxP6PvSB5bfFA1btE7tWnG6QAoEU/0Gr47f6KaxRwiRfBujHlzkuMPqtpTlSOW4aOEOyMtQqfg==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.26.0': - resolution: {integrity: sha512-A/jvfCZ55EYPsqeaAt/yDAG4q5tt1ZboWMHEvKAH9Zl92DWvMIbnZe/f/eOXze65aJaaKbL+YeM0Hz4kLQvdwg==} + '@rollup/rollup-freebsd-x64@4.27.0': + resolution: {integrity: sha512-G05JNYFdjikD/2hJTf1gHdD5KjI2TotjiDn17amHtB5JgwrRF1EA9hJ3TRGIvT3zGXilNWWlR71R/2TT1pXRDg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.26.0': - resolution: {integrity: sha512-paHF1bMXKDuizaMODm2bBTjRiHxESWiIyIdMugKeLnjuS1TCS54MF5+Y5Dx8Ui/1RBPVRE09i5OUlaLnv8OGnA==} + '@rollup/rollup-linux-arm-gnueabihf@4.27.0': + resolution: {integrity: sha512-FMXxMZ7qnMULwgdmGSFVlOduAhFyqDPoK1A2Q8HBkzGYX9SMFU3ITKfLdIiCzTaaj/pt1OiEbpF2szUw6Kh++Q==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.26.0': - resolution: {integrity: sha512-cwxiHZU1GAs+TMxvgPfUDtVZjdBdTsQwVnNlzRXC5QzIJ6nhfB4I1ahKoe9yPmoaA/Vhf7m9dB1chGPpDRdGXg==} + '@rollup/rollup-linux-arm-musleabihf@4.27.0': + resolution: {integrity: sha512-0315TiPsJfOY+jAwEeqxcy9yVcAy/jg99GrMcd/L7CRESzi1vhyLPbnkDnz7giaEttSRf/d3llJYfoC+44Nl3A==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.26.0': - resolution: {integrity: sha512-4daeEUQutGRCW/9zEo8JtdAgtJ1q2g5oHaoQaZbMSKaIWKDQwQ3Yx0/3jJNmpzrsScIPtx/V+1AfibLisb3AMQ==} + '@rollup/rollup-linux-arm64-gnu@4.27.0': + resolution: {integrity: sha512-4zCKY5E9djPyHzvoCWIouFsuAvg+dk+rNia8lz1bjKpzKz02QvK4JPHyjcDT8CFR2J/aA98WccCirdDOy+VDWQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.26.0': - resolution: {integrity: sha512-eGkX7zzkNxvvS05ROzJ/cO/AKqNvR/7t1jA3VZDi2vRniLKwAWxUr85fH3NsvtxU5vnUUKFHKh8flIBdlo2b3Q==} + '@rollup/rollup-linux-arm64-musl@4.27.0': + resolution: {integrity: sha512-6St9rrPSLbYBbbJAClpU4gmnO7cdZCMMzx2MT0UCIIIevoLAmsCDOAG6t3J/RgN4CPUpdaGr/UnPqQTHZ4oDwA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.26.0': - resolution: {integrity: sha512-Odp/lgHbW/mAqw/pU21goo5ruWsytP7/HCC/liOt0zcGG0llYWKrd10k9Fj0pdj3prQ63N5yQLCLiE7HTX+MYw==} + '@rollup/rollup-linux-powerpc64le-gnu@4.27.0': + resolution: {integrity: sha512-dIBfp8NDrgvwUJxyqFv7501coIba+7xxBJy1gQEF0RGkIKa3Tq0Mh3sF9hmstDLtaMt7gL2aXsCNG9SCKyVVZg==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.26.0': - resolution: {integrity: sha512-MBR2ZhCTzUgVD0OJdTzNeF4+zsVogIR1U/FsyuFerwcqjZGvg2nYe24SAHp8O5sN8ZkRVbHwlYeHqcSQ8tcYew==} + '@rollup/rollup-linux-riscv64-gnu@4.27.0': + resolution: {integrity: sha512-Pu7xLHRy+5UjFCKR/vWsbFmiBYUC9993v99YoKWhAgK4VsdNuWHPs17NuCJEtVsZpYCNVPbRyBpQw58Ma8BmeA==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.26.0': - resolution: {integrity: sha512-YYcg8MkbN17fMbRMZuxwmxWqsmQufh3ZJFxFGoHjrE7bv0X+T6l3glcdzd7IKLiwhT+PZOJCblpnNlz1/C3kGQ==} + '@rollup/rollup-linux-s390x-gnu@4.27.0': + resolution: {integrity: sha512-2Q9qQnk/eWdvXzzHl22y7tpDHREppFUh7N6cCs70HZEbQSgB7wd/2S/B05SSiyAiIn5BL+fYiASLds5bz0IQFw==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.26.0': - resolution: {integrity: sha512-ZuwpfjCwjPkAOxpjAEjabg6LRSfL7cAJb6gSQGZYjGhadlzKKywDkCUnJ+KEfrNY1jH5EEoSIKLCb572jSiglA==} + '@rollup/rollup-linux-x64-gnu@4.27.0': + resolution: {integrity: sha512-CNnqMZ4Yz0Ga0A75qux7DNChq0P9oAWn2S7yjZPRC+AaEF8Ysw5K/1lzT25/a3reJ4V2abcShIVG+tfZHb1UrQ==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.26.0': - resolution: {integrity: sha512-+HJD2lFS86qkeF8kNu0kALtifMpPCZU80HvwztIKnYwym3KnA1os6nsX4BGSTLtS2QVAGG1P3guRgsYyMA0Yhg==} + '@rollup/rollup-linux-x64-musl@4.27.0': + resolution: {integrity: sha512-dS1+eCbbao54XB+wLW6uuwRkChq4L0UfKhd3wvt6s+EN1rTIi24ee5Lk3HfRGq9J2jsRm12/AGKLA0kd82Sp/g==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.26.0': - resolution: {integrity: sha512-WUQzVFWPSw2uJzX4j6YEbMAiLbs0BUysgysh8s817doAYhR5ybqTI1wtKARQKo6cGop3pHnrUJPFCsXdoFaimQ==} + '@rollup/rollup-win32-arm64-msvc@4.27.0': + resolution: {integrity: sha512-VrYQHY5+Y71OU/uOSRE9lLhph16bbuWGrMwGwZDPxCUXUW5NgLA+K+q0kv7rafHRlnrsZSVcMOkZskzTNnR3ZQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.26.0': - resolution: {integrity: sha512-D4CxkazFKBfN1akAIY6ieyOqzoOoBV1OICxgUblWxff/pSjCA2khXlASUx7mK6W1oP4McqhgcCsu6QaLj3WMWg==} + '@rollup/rollup-win32-ia32-msvc@4.27.0': + resolution: {integrity: sha512-LCqk4Xi3e4GzLqaq+QDM7gP5DtJ/RgWMzV3U2brwp/vEz9RTA5YBgIDP69xYfrTXexes6xPsOIquy79+kLifiA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.26.0': - resolution: {integrity: sha512-2x8MO1rm4PGEP0xWbubJW5RtbNLk3puzAMaLQd3B3JHVw4KcHlmXcO+Wewx9zCoo7EUFiMlu/aZbCJ7VjMzAag==} + '@rollup/rollup-win32-x64-msvc@4.27.0': + resolution: {integrity: sha512-dj2ZolfViR3chLWwSHID2mBzLLwYvXFldIplR6BSkdACXqAsrcmItKTff4h7enYB3Ugoh0v41WbxijE9HJb1Hw==} cpu: [x64] os: [win32] @@ -1878,26 +1878,26 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - applesauce-channel@0.0.0-next-20241114194041: - resolution: {integrity: sha512-8ItnMP36x33EdgKPJ6EDn0I2ETCW5EfbrvNpQUfh8wP+ppBVQFuhaV3UmLVRRbv+Mq4RL1Jo60HLqul60O0kYw==} + applesauce-channel@0.0.0-next-20241115160057: + resolution: {integrity: sha512-0/F0Uw+n/j51n3NIx/q1W94jkycfDffuKRFFIHdaFDC3dH2v/UnQX1LC8lOrVPoNfx6DqGK0sZZ3R6fk4OnKEQ==} - applesauce-content@0.0.0-next-20241114194041: - resolution: {integrity: sha512-0nOMZN8Jdcge4lxeuWxLIfMHfbfwdUFKEJRIxo4nb9nbms5Tuhjz9TQhvlQ/PN+0f0ioIy0nFjw7xTyJV/6sMg==} + applesauce-content@0.0.0-next-20241115160057: + resolution: {integrity: sha512-fJZFbiln+drZxEp82xJbyR3GBTysbswdtiliDN+vVSt66pbVC7QXF+7yp8CskrZm7+5BnuP59zT4Q18cipcjYw==} - applesauce-core@0.0.0-next-20241114194041: - resolution: {integrity: sha512-vPeqWHLr0DklswpmCDEMKaZ4yVwaM+8lxX7Yix8cCZvZzaXv/yxg3AlxbUcwjIVuVscuQp/zO1+soB27Coh4fQ==} + applesauce-core@0.0.0-next-20241115160057: + resolution: {integrity: sha512-9zvY/NXeJfgYk4cMaELoKVckBQnEDfobhwvxBzCkrQfh6K87mMPDbAemaaW8zp9Ggm1ejbGWpDqnBEnj+d6zvw==} - applesauce-lists@0.0.0-next-20241114194041: - resolution: {integrity: sha512-OGNQxwJ7rdunWkNaUxKkOmm0ioIAaOVEVUpKi6KWHKob4Z+I8B2onWMz/ROtNnsUafitIGK6Vp5pl3EJpzGsuw==} + applesauce-lists@0.0.0-next-20241115160057: + resolution: {integrity: sha512-2nuPegvbDyOuJB8szf/MSi80/yQhxVGcgoQ9MciNhDj7LgxdK/HABo/oaPmtBqgUEYkixO8Pe9wYnci//ooKIQ==} - applesauce-net@0.0.0-next-20241114194041: - resolution: {integrity: sha512-WtaXP59JGzCE2TJlJQ25AudcgI5rp6jI5Y7cxtYey+vxdcu931MMvod9Uo6ppgvP/U5voJusWrxEXxUWKbUIZw==} + applesauce-net@0.0.0-next-20241115160057: + resolution: {integrity: sha512-FvYHh2u7cYpIixUTN5sG18zTHj5PKWR/tcik9PCIfRPgte25zcYr1bTXYPitJnzwl5DLA85acYPjSuJlTc9vtg==} - applesauce-react@0.0.0-next-20241114194041: - resolution: {integrity: sha512-ARJjt60kjXPZk8Jeoa0xOgu5c7j66kmzqdBs+eFW7246oVxzUHyy2JpwewPNASDCjHNhaOnUVmspU2gBTF4svA==} + applesauce-react@0.0.0-next-20241115160057: + resolution: {integrity: sha512-OtBBHVdOTVOIzfzRQVgZz7kQsBfph4LPoSJ53Pj46JzEgiXyHoQDxdJ3j1h9apQsHH6hGNnTtfrH5W/U0EAwog==} - applesauce-signer@0.0.0-next-20241114194041: - resolution: {integrity: sha512-cxZVB3dcTwMq4XzOCOZheMlKB0My//x278fR/JCfaYiL9dghMCZCWwU4vUOXgyMQ4cW3csD+8RXNo0ICAG8Fpw==} + applesauce-signer@0.0.0-next-20241115160057: + resolution: {integrity: sha512-Iw9v4ylqzxyISrylZawZM+y+tWhvHRBXKmYpxKwuSkBtX9mWEUnItSKcC9M1g2ncYvima2JrOvgPr3oGEZIaKA==} argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -2361,8 +2361,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.58: - resolution: {integrity: sha512-al2l4r+24ZFL7WzyPTlyD0fC33LLzvxqLCwurtBibVPghRGO9hSTl+tis8t1kD7biPiH/en4U0I7o/nQbYeoVA==} + electron-to-chromium@1.5.60: + resolution: {integrity: sha512-HcraRUkTKJ+8yA3b10i9qvhUlPBRDlKjn1XGek1zDGVfAKcvi8TsUnImGqLiEm9j6ZulxXIWWIo9BmbkbCTGgA==} emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -2387,8 +2387,8 @@ packages: error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} - es-abstract@1.23.4: - resolution: {integrity: sha512-HR1gxH5OaiN7XH7uiWH0RLw0RcFySiSoW1ctxmD1ahTw3uGBtkmm/ng0tDU1OtYx5OK6EOL5Y6O21cDflG3Jcg==} + es-abstract@1.23.5: + resolution: {integrity: sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==} engines: {node: '>= 0.4'} es-define-property@1.0.0: @@ -3738,8 +3738,8 @@ packages: engines: {node: '>=10.0.0'} hasBin: true - rollup@4.26.0: - resolution: {integrity: sha512-ilcl12hnWonG8f+NxU6BlgysVA0gvY2l8N0R84S1HcINbW20bvwuCngJkkInV6LXhwRpucsW5k1ovDwEdBVrNg==} + rollup@4.27.0: + resolution: {integrity: sha512-nrOD/RrnAMssruS7bPa7MYpEuH6tUpOa43NLtxQiLKem0An8HZyXun5Ndig6JzbkJoIbaKkt85V67VCaQ59GyA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -4318,8 +4318,8 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} - yet-another-react-lightbox@3.21.6: - resolution: {integrity: sha512-uKcRmmezsj1Fbj38B6hFOGwbAu94fPr8d5H6I0+1FmcToX56freEGXXXtdA1oRo6036ug+UgrKZzzvsw/MIM/w==} + yet-another-react-lightbox@3.21.7: + resolution: {integrity: sha512-dcdokNuCIl92f0Vl+uzeKULnQhztIGpoZFUMvtVNUPmtwsQWpqWufeieDPeg9JtFyVCcbj4vYw3V00DS0QNoWA==} engines: {node: '>=14'} peerDependencies: react: '>=16.8.0' @@ -5395,18 +5395,18 @@ snapshots: human-id: 1.0.2 prettier: 2.8.8 - '@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)(@lezer/common@1.2.3)': + '@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)(@lezer/common@1.2.3)': dependencies: '@codemirror/language': 6.10.3 '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.2 + '@codemirror/view': 6.34.3 '@lezer/common': 1.2.3 '@codemirror/commands@6.7.1': dependencies: '@codemirror/language': 6.10.3 '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.2 + '@codemirror/view': 6.34.3 '@lezer/common': 1.2.3 '@codemirror/lang-json@6.0.1': @@ -5417,7 +5417,7 @@ snapshots: '@codemirror/language@6.10.3': dependencies: '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.2 + '@codemirror/view': 6.34.3 '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 @@ -5426,13 +5426,13 @@ snapshots: '@codemirror/lint@6.8.2': dependencies: '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.2 + '@codemirror/view': 6.34.3 crelt: 1.0.6 '@codemirror/search@6.5.6': dependencies: '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.2 + '@codemirror/view': 6.34.3 crelt: 1.0.6 '@codemirror/state@6.4.1': {} @@ -5441,10 +5441,10 @@ snapshots: dependencies: '@codemirror/language': 6.10.3 '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.2 + '@codemirror/view': 6.34.3 '@lezer/highlight': 1.2.1 - '@codemirror/view@6.34.2': + '@codemirror/view@6.34.3': dependencies: '@codemirror/state': 6.4.1 style-mod: 4.1.2 @@ -5818,58 +5818,58 @@ snapshots: optionalDependencies: rollup: 2.79.2 - '@rollup/rollup-android-arm-eabi@4.26.0': + '@rollup/rollup-android-arm-eabi@4.27.0': optional: true - '@rollup/rollup-android-arm64@4.26.0': + '@rollup/rollup-android-arm64@4.27.0': optional: true - '@rollup/rollup-darwin-arm64@4.26.0': + '@rollup/rollup-darwin-arm64@4.27.0': optional: true - '@rollup/rollup-darwin-x64@4.26.0': + '@rollup/rollup-darwin-x64@4.27.0': optional: true - '@rollup/rollup-freebsd-arm64@4.26.0': + '@rollup/rollup-freebsd-arm64@4.27.0': optional: true - '@rollup/rollup-freebsd-x64@4.26.0': + '@rollup/rollup-freebsd-x64@4.27.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.26.0': + '@rollup/rollup-linux-arm-gnueabihf@4.27.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.26.0': + '@rollup/rollup-linux-arm-musleabihf@4.27.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.26.0': + '@rollup/rollup-linux-arm64-gnu@4.27.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.26.0': + '@rollup/rollup-linux-arm64-musl@4.27.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.26.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.27.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.26.0': + '@rollup/rollup-linux-riscv64-gnu@4.27.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.26.0': + '@rollup/rollup-linux-s390x-gnu@4.27.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.26.0': + '@rollup/rollup-linux-x64-gnu@4.27.0': optional: true - '@rollup/rollup-linux-x64-musl@4.26.0': + '@rollup/rollup-linux-x64-musl@4.27.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.26.0': + '@rollup/rollup-win32-arm64-msvc@4.27.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.26.0': + '@rollup/rollup-win32-ia32-msvc@4.27.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.26.0': + '@rollup/rollup-win32-x64-msvc@4.27.0': optional: true '@sagold/json-pointer@5.1.2': {} @@ -6073,38 +6073,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.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)(@lezer/common@1.2.3))(@codemirror/commands@6.7.1)(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)': + '@uiw/codemirror-extensions-basic-setup@4.23.6(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)(@lezer/common@1.2.3))(@codemirror/commands@6.7.1)(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)': dependencies: - '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)(@lezer/common@1.2.3) + '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)(@lezer/common@1.2.3) '@codemirror/commands': 6.7.1 '@codemirror/language': 6.10.3 '@codemirror/lint': 6.8.2 '@codemirror/search': 6.5.6 '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.2 + '@codemirror/view': 6.34.3 - '@uiw/codemirror-theme-github@4.23.6(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)': + '@uiw/codemirror-theme-github@4.23.6(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)': dependencies: - '@uiw/codemirror-themes': 4.23.6(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2) + '@uiw/codemirror-themes': 4.23.6(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3) transitivePeerDependencies: - '@codemirror/language' - '@codemirror/state' - '@codemirror/view' - '@uiw/codemirror-themes@4.23.6(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)': + '@uiw/codemirror-themes@4.23.6(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)': dependencies: '@codemirror/language': 6.10.3 '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.2 + '@codemirror/view': 6.34.3 - '@uiw/react-codemirror@4.23.6(@babel/runtime@7.26.0)(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)(@lezer/common@1.2.3))(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.34.2)(codemirror@5.65.18)(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.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)(@lezer/common@1.2.3))(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.34.3)(codemirror@5.65.18)(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/theme-one-dark': 6.1.2 - '@codemirror/view': 6.34.2 - '@uiw/codemirror-extensions-basic-setup': 4.23.6(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)(@lezer/common@1.2.3))(@codemirror/commands@6.7.1)(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2) + '@codemirror/view': 6.34.3 + '@uiw/codemirror-extensions-basic-setup': 4.23.6(@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)(@lezer/common@1.2.3))(@codemirror/commands@6.7.1)(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3) codemirror: 5.65.18 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -6173,22 +6173,22 @@ snapshots: dependencies: color-convert: 2.0.1 - applesauce-channel@0.0.0-next-20241114194041(typescript@5.6.3): + applesauce-channel@0.0.0-next-20241115160057(typescript@5.6.3): dependencies: - applesauce-core: 0.0.0-next-20241114194041(typescript@5.6.3) + applesauce-core: 0.0.0-next-20241115160057(typescript@5.6.3) nostr-tools: 2.10.3(typescript@5.6.3) rxjs: 7.8.1 transitivePeerDependencies: - supports-color - typescript - applesauce-content@0.0.0-next-20241114194041(typescript@5.6.3): + applesauce-content@0.0.0-next-20241115160057(typescript@5.6.3): 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-20241114194041(typescript@5.6.3) + applesauce-core: 0.0.0-next-20241115160057(typescript@5.6.3) mdast-util-find-and-replace: 3.0.1 nostr-tools: 2.10.3(typescript@5.6.3) remark: 15.0.1 @@ -6199,7 +6199,7 @@ snapshots: - supports-color - typescript - applesauce-core@0.0.0-next-20241114194041(typescript@5.6.3): + applesauce-core@0.0.0-next-20241115160057(typescript@5.6.3): dependencies: debug: 4.3.7 json-stringify-deterministic: 1.0.12 @@ -6211,13 +6211,13 @@ snapshots: - supports-color - typescript - applesauce-lists@0.0.0-next-20241114194041(typescript@5.6.3): + applesauce-lists@0.0.0-next-20241115160057(typescript@5.6.3): dependencies: '@noble/hashes': 1.5.0 '@noble/secp256k1': 1.7.1 '@scure/base': 1.1.9 '@types/dom-serial': 1.0.6 - applesauce-core: 0.0.0-next-20241114194041(typescript@5.6.3) + applesauce-core: 0.0.0-next-20241115160057(typescript@5.6.3) debug: 4.3.7 nostr-tools: 2.10.3(typescript@5.6.3) rxjs: 7.8.1 @@ -6225,9 +6225,9 @@ snapshots: - supports-color - typescript - applesauce-net@0.0.0-next-20241114194041(typescript@5.6.3): + applesauce-net@0.0.0-next-20241115160057(typescript@5.6.3): dependencies: - applesauce-core: 0.0.0-next-20241114194041(typescript@5.6.3) + applesauce-core: 0.0.0-next-20241115160057(typescript@5.6.3) nanoid: 5.0.8 nostr-tools: 2.10.3(typescript@5.6.3) rxjs: 7.8.1 @@ -6236,10 +6236,10 @@ snapshots: - supports-color - typescript - applesauce-react@0.0.0-next-20241114194041(typescript@5.6.3): + applesauce-react@0.0.0-next-20241115160057(typescript@5.6.3): dependencies: - applesauce-content: 0.0.0-next-20241114194041(typescript@5.6.3) - applesauce-core: 0.0.0-next-20241114194041(typescript@5.6.3) + applesauce-content: 0.0.0-next-20241115160057(typescript@5.6.3) + applesauce-core: 0.0.0-next-20241115160057(typescript@5.6.3) nostr-tools: 2.10.3(typescript@5.6.3) react: 18.3.1 rxjs: 7.8.1 @@ -6247,14 +6247,14 @@ snapshots: - supports-color - typescript - applesauce-signer@0.0.0-next-20241114194041(typescript@5.6.3): + applesauce-signer@0.0.0-next-20241115160057(typescript@5.6.3): dependencies: '@noble/hashes': 1.5.0 '@noble/secp256k1': 1.7.1 '@scure/base': 1.1.9 '@types/dom-serial': 1.0.6 - applesauce-core: 0.0.0-next-20241114194041(typescript@5.6.3) - applesauce-net: 0.0.0-next-20241114194041(typescript@5.6.3) + applesauce-core: 0.0.0-next-20241115160057(typescript@5.6.3) + applesauce-net: 0.0.0-next-20241115160057(typescript@5.6.3) debug: 4.3.7 nanoid: 5.0.8 nostr-tools: 2.10.3(typescript@5.6.3) @@ -6282,7 +6282,7 @@ snapshots: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.4 + es-abstract: 1.23.5 es-errors: 1.3.0 get-intrinsic: 1.2.4 is-array-buffer: 3.0.4 @@ -6385,7 +6385,7 @@ snapshots: browserslist@4.24.2: dependencies: caniuse-lite: 1.0.30001680 - electron-to-chromium: 1.5.58 + electron-to-chromium: 1.5.60 node-releases: 2.0.18 update-browserslist-db: 1.1.1(browserslist@4.24.2) @@ -6470,13 +6470,13 @@ snapshots: classnames@2.5.1: {} - codemirror-json-schema@0.6.1(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)(@lezer/common@1.2.3): + codemirror-json-schema@0.6.1(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)(@lezer/common@1.2.3): dependencies: '@changesets/changelog-github': 0.4.8 '@codemirror/language': 6.10.3 '@codemirror/lint': 6.8.2 '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.2 + '@codemirror/view': 6.34.3 '@lezer/common': 1.2.3 '@sagold/json-pointer': 5.1.2 '@types/json-schema': 7.0.15 @@ -6494,7 +6494,7 @@ snapshots: dependencies: '@codemirror/language': 6.10.3 '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.2 + '@codemirror/view': 6.34.3 '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 json5: 2.2.3 @@ -6779,7 +6779,7 @@ snapshots: dependencies: jake: 10.9.2 - electron-to-chromium@1.5.58: {} + electron-to-chromium@1.5.60: {} emoji-regex@10.4.0: {} @@ -6805,7 +6805,7 @@ snapshots: dependencies: stackframe: 1.3.4 - es-abstract@1.23.4: + es-abstract@1.23.5: dependencies: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 @@ -7040,7 +7040,7 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.4 + es-abstract: 1.23.5 functions-have-names: 1.2.3 functions-have-names@1.2.3: {} @@ -8480,28 +8480,28 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - rollup@4.26.0: + rollup@4.27.0: dependencies: '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.26.0 - '@rollup/rollup-android-arm64': 4.26.0 - '@rollup/rollup-darwin-arm64': 4.26.0 - '@rollup/rollup-darwin-x64': 4.26.0 - '@rollup/rollup-freebsd-arm64': 4.26.0 - '@rollup/rollup-freebsd-x64': 4.26.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.26.0 - '@rollup/rollup-linux-arm-musleabihf': 4.26.0 - '@rollup/rollup-linux-arm64-gnu': 4.26.0 - '@rollup/rollup-linux-arm64-musl': 4.26.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.26.0 - '@rollup/rollup-linux-riscv64-gnu': 4.26.0 - '@rollup/rollup-linux-s390x-gnu': 4.26.0 - '@rollup/rollup-linux-x64-gnu': 4.26.0 - '@rollup/rollup-linux-x64-musl': 4.26.0 - '@rollup/rollup-win32-arm64-msvc': 4.26.0 - '@rollup/rollup-win32-ia32-msvc': 4.26.0 - '@rollup/rollup-win32-x64-msvc': 4.26.0 + '@rollup/rollup-android-arm-eabi': 4.27.0 + '@rollup/rollup-android-arm64': 4.27.0 + '@rollup/rollup-darwin-arm64': 4.27.0 + '@rollup/rollup-darwin-x64': 4.27.0 + '@rollup/rollup-freebsd-arm64': 4.27.0 + '@rollup/rollup-freebsd-x64': 4.27.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.27.0 + '@rollup/rollup-linux-arm-musleabihf': 4.27.0 + '@rollup/rollup-linux-arm64-gnu': 4.27.0 + '@rollup/rollup-linux-arm64-musl': 4.27.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.27.0 + '@rollup/rollup-linux-riscv64-gnu': 4.27.0 + '@rollup/rollup-linux-s390x-gnu': 4.27.0 + '@rollup/rollup-linux-x64-gnu': 4.27.0 + '@rollup/rollup-linux-x64-musl': 4.27.0 + '@rollup/rollup-win32-arm64-msvc': 4.27.0 + '@rollup/rollup-win32-ia32-msvc': 4.27.0 + '@rollup/rollup-win32-x64-msvc': 4.27.0 fsevents: 2.3.3 rtl-css-js@1.16.1: @@ -8637,7 +8637,7 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.4 + es-abstract: 1.23.5 es-errors: 1.3.0 es-object-atoms: 1.0.0 get-intrinsic: 1.2.4 @@ -8652,7 +8652,7 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.4 + es-abstract: 1.23.5 es-object-atoms: 1.0.0 string.prototype.trimend@1.0.8: @@ -8958,7 +8958,7 @@ snapshots: dependencies: esbuild: 0.21.5 postcss: 8.4.49 - rollup: 4.26.0 + rollup: 4.27.0 optionalDependencies: '@types/node': 20.17.6 fsevents: 2.3.3 @@ -9150,7 +9150,7 @@ snapshots: yaml@1.10.2: {} - yet-another-react-lightbox@3.21.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + yet-another-react-lightbox@3.21.7(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) diff --git a/src/components/lightning/inline-invoice-card.tsx b/src/components/lightning/inline-invoice-card.tsx index 44be05647..792a095dc 100644 --- a/src/components/lightning/inline-invoice-card.tsx +++ b/src/components/lightning/inline-invoice-card.tsx @@ -56,7 +56,7 @@ export default function InlineInvoiceCard({ if (!invoice) return <>Loading Invoice...</>; - const isExpired = dayjs(invoice.expiry).isBefore(dayjs()); + const isExpired = dayjs.unix(invoice.expiry).isBefore(dayjs()); return ( <Flex @@ -87,7 +87,7 @@ export default function InlineInvoiceCard({ </Box> <Box> <Text color={isExpired ? "red.400" : undefined}> - {isExpired ? "Expired" : "Expires"}: {dayjs(invoice.expiry).fromNow()} + {isExpired ? "Expired" : "Expires"}: {dayjs.unix(invoice.expiry).fromNow()} </Text> </Box> <ButtonGroup variant="outline"> diff --git a/src/components/note/note-zap-button.tsx b/src/components/note/note-zap-button.tsx index 17acaace6..b78c23260 100644 --- a/src/components/note/note-zap-button.tsx +++ b/src/components/note/note-zap-button.tsx @@ -1,4 +1,5 @@ import { Button, ButtonProps, IconButton, useDisclosure } from "@chakra-ui/react"; +import { getZapSender } from "applesauce-core/helpers"; import { readablizeSats } from "../../helpers/bolt11"; import { totalZaps } from "../../helpers/nostr/zaps"; @@ -11,7 +12,6 @@ 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"; -import { getZapSender } from "applesauce-core/helpers"; export type NoteZapButtonProps = Omit<ButtonProps, "children"> & { event: NostrEvent; diff --git a/src/queries/dvm-responses.ts b/src/queries/dvm-responses.ts new file mode 100644 index 000000000..334ddaddf --- /dev/null +++ b/src/queries/dvm-responses.ts @@ -0,0 +1,20 @@ +import { Query } from "applesauce-core"; +import { NostrEvent } from "nostr-tools"; +import { scan } from "rxjs/operators"; + +export default function DVMResponsesQuery(request: NostrEvent): Query<Record<string, NostrEvent>> { + return { + key: request.id, + run: (events) => + events.stream([{ kinds: [request.kind + 1000, 7000], "#e": [request.id] }]).pipe( + scan( + (byPubkey, event) => { + if (byPubkey[event.pubkey] && byPubkey[event.pubkey].created_at > event.created_at) return byPubkey; + + return { ...byPubkey, [event.pubkey]: event }; + }, + {} as Record<string, NostrEvent>, + ), + ), + }; +} diff --git a/src/views/discovery/dvm-feed/components/feed-status.tsx b/src/views/discovery/dvm-feed/components/feed-status.tsx index a93a7f259..fa01a8e14 100644 --- a/src/views/discovery/dvm-feed/components/feed-status.tsx +++ b/src/views/discovery/dvm-feed/components/feed-status.tsx @@ -9,26 +9,29 @@ import { CardBody, CardHeader, Code, + Flex, Heading, Spinner, Text, } from "@chakra-ui/react"; import dayjs from "dayjs"; +import { NostrEvent } from "nostr-tools"; +import { getTagValue } from "applesauce-core/helpers"; +import { AddressPointer } from "nostr-tools/nip19"; -import { - ChainedDVMJob, - DVM_CONTENT_DISCOVERY_JOB_KIND, - getJobStatusType, - getResponseFromDVM, -} from "../../../../helpers/nostr/dvm"; +import { ChainedDVMJob, DVM_CONTENT_DISCOVERY_JOB_KIND, getResponseFromDVM } from "../../../../helpers/nostr/dvm"; import { DraftNostrEvent } from "../../../../types/nostr-event"; import { useReadRelays } from "../../../../hooks/use-client-relays"; import { DVMAvatarLink } from "./dvm-avatar"; import DVMLink from "./dvm-name"; -import { AddressPointer } from "nostr-tools/nip19"; import useUserMailboxes from "../../../../hooks/use-user-mailboxes"; import { usePublishEvent } from "../../../../providers/global/publish-provider"; import InlineInvoiceCard from "../../../../components/lightning/inline-invoice-card"; +import UserAvatar from "../../../../components/user/user-avatar"; +import UserLink from "../../../../components/user/user-link"; +import UserDnsIdentity from "../../../../components/user/user-dns-identity"; +import DebugEventButton from "../../../../components/debug-modal/debug-event-button"; +import NoteZapButton from "../../../../components/note/note-zap-button"; function NextPageButton({ chain, pointer }: { pointer: AddressPointer; chain: ChainedDVMJob[] }) { const publish = usePublishEvent(); @@ -68,21 +71,31 @@ function NextPageButton({ chain, pointer }: { pointer: AddressPointer; chain: Ch ); } -export default function FeedStatus({ chain, pointer }: { chain: ChainedDVMJob[]; pointer: AddressPointer }) { - const lastJob = chain[chain.length - 1]; - const response = lastJob.responses.find((r) => r.pubkey === pointer.pubkey); - if (response?.result) return <NextPageButton pointer={pointer} chain={chain} />; - +export function DVMStatusCard({ status, pointer }: { status?: NostrEvent; pointer?: AddressPointer }) { const cardProps = { w: "full", maxW: "2xl", mx: "auto", overflow: "hidden" }; const cardHeader = ( <CardHeader p="4" alignItems="center" display="flex" gap="2"> - <DVMAvatarLink pointer={pointer} w="12" /> - <DVMLink pointer={pointer} fontWeight="bold" fontSize="lg" /> + {pointer ? ( + <> + <DVMAvatarLink pointer={pointer} w="12" /> + <DVMLink pointer={pointer} fontWeight="bold" fontSize="lg" /> + </> + ) : ( + status && ( + <> + <UserAvatar pubkey={status.pubkey} size="md" /> + <Flex direction="column"> + <UserLink pubkey={status.pubkey} fontWeight="bold" fontSize="lg" /> + <UserDnsIdentity pubkey={status.pubkey} /> + </Flex> + </> + ) + )} + {status && <DebugEventButton ml="auto" event={status} size="sm" variant="ghost" />} </CardHeader> ); - const statusEvent = response?.status; - if (!statusEvent) + if (!status) return ( <Card {...cardProps}> {cardHeader} @@ -93,16 +106,16 @@ export default function FeedStatus({ chain, pointer }: { chain: ChainedDVMJob[]; </Card> ); - const statusType = getJobStatusType(lastJob, pointer.pubkey); + const statusType = getTagValue(status, "status"); switch (statusType) { case "payment-required": - const [_, msats, invoice] = statusEvent.tags.find((t) => t[0] === "amount") ?? []; + const [_, msats, invoice] = status.tags.find((t) => t[0] === "amount") ?? []; return ( <Card {...cardProps}> {cardHeader} <CardBody px="4" pb="4" pt="0" gap="2" display="flex" flexDirection="column"> - <Heading size="sm">{statusEvent.content}</Heading> + <Heading size="sm">{status.content}</Heading> {invoice && <InlineInvoiceCard paymentRequest={invoice} />} </CardBody> </Card> @@ -113,7 +126,7 @@ export default function FeedStatus({ chain, pointer }: { chain: ChainedDVMJob[]; <AlertIcon boxSize={8} /> <Box> <AlertTitle>Processing</AlertTitle> - <AlertDescription>{statusEvent.content}</AlertDescription> + <AlertDescription>{status.content}</AlertDescription> </Box> </Alert> ); @@ -123,7 +136,7 @@ export default function FeedStatus({ chain, pointer }: { chain: ChainedDVMJob[]; <AlertIcon boxSize={8} /> <Box> <AlertTitle>Error!</AlertTitle> - <AlertDescription>{statusEvent.content}</AlertDescription> + <AlertDescription>{status.content}</AlertDescription> </Box> </Alert> ); @@ -133,8 +146,16 @@ export default function FeedStatus({ chain, pointer }: { chain: ChainedDVMJob[]; <Text> Unknown status <Code>{statusType}</Code> </Text> - <Text>{statusEvent.content}</Text> + <Text>{status.content}</Text> </> ); } } + +export default function FeedStatus({ chain, pointer }: { chain: ChainedDVMJob[]; pointer: AddressPointer }) { + const lastJob = chain[chain.length - 1]; + const response = lastJob.responses.find((r) => r.pubkey === pointer.pubkey); + if (response?.result) return <NextPageButton pointer={pointer} chain={chain} />; + + return <DVMStatusCard status={response?.status} pointer={pointer} />; +} diff --git a/src/views/thread/components/details-tabs.tsx b/src/views/thread/components/details-tabs.tsx index 7204b88f8..eccd2c30c 100644 --- a/src/views/thread/components/details-tabs.tsx +++ b/src/views/thread/components/details-tabs.tsx @@ -1,4 +1,5 @@ -import { Button, Flex } from "@chakra-ui/react"; +import { ReactNode } from "react"; +import { Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"; import { kinds } from "nostr-tools"; import { getEventUID } from "nostr-idb"; import styled from "@emotion/styled"; @@ -15,11 +16,12 @@ import useTimelineLoader from "../../../hooks/use-timeline-loader"; import { getContentTagRefs } from "../../../helpers/nostr/event"; import { CORRECTION_EVENT_KIND } from "../../../helpers/nostr/corrections"; import CorrectionsTab from "./tabs/corrections"; -import useRouteStateValue from "../../../hooks/use-route-state-value"; import UnknownTab from "./tabs/unknown"; import { repliesByDate } from "../../../helpers/thread"; +import ToolsTab from "./tabs/tools"; +import useRouteSearchValue from "../../../hooks/use-route-search-value"; -const HiddenScrollbar = styled(Flex)` +const HiddenScrollbarTabList = styled(TabList)` -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ &::-webkit-scrollbar { @@ -28,7 +30,7 @@ const HiddenScrollbar = styled(Flex)` `; export default function DetailsTabs({ post }: { post: ThreadItem }) { - const { value: selected, setValue: setSelected } = useRouteStateValue("tab", "replies"); + const selected = useRouteSearchValue("tab", "replies"); const zaps = useEventZaps(getEventUID(post.event)); @@ -62,99 +64,121 @@ export default function DetailsTabs({ post }: { post: ThreadItem }) { !corrections.includes(e), ); - const renderContent = () => { - switch (selected) { - case "replies": - return ( - <Flex direction="column" gap="2" pl={{ base: 2, md: 4 }}> - {repliesByDate(post).map((child) => ( - <ThreadPost key={child.event.id} post={child} focusId={undefined} level={0} /> - ))} - </Flex> - ); - case "quotes": - return <PostQuotesTab post={post} quotes={quotes} />; - case "reactions": - return <PostReactionsTab post={post} reactions={reactions} />; - case "reposts": - return <PostRepostsTab post={post} reposts={reposts} />; - case "zaps": - return <PostZapsTab post={post} zaps={zaps} />; - case "corrections": - return <CorrectionsTab post={post} corrections={corrections} />; - case "unknown": - return <UnknownTab post={post} events={unknown} />; - } - return null; - }; + const tabs: { id: string; name: string; element: ReactNode; visible: boolean; right?: boolean }[] = [ + { + id: "replies", + name: `Replies (${post.replies.size})`, + visible: true, + element: ( + <TabPanel key="replies" display="flex" flexDirection="column" gap="2" py="2" pr="0" pl={{ base: 2, md: 4 }}> + {repliesByDate(post).map((child) => ( + <ThreadPost key={child.event.id} post={child} focusId={undefined} level={0} /> + ))} + </TabPanel> + ), + }, + { + id: "quotes", + name: `Quotes (${quotes.length})`, + visible: quotes.length > 0, + element: ( + <TabPanel key="quotes" p="0" py="2"> + <PostQuotesTab post={post} quotes={quotes} /> + </TabPanel> + ), + }, + { + id: "zaps", + name: `Zaps (${zaps.length})`, + visible: zaps.length > 0, + element: ( + <TabPanel key="zaps" p="0" py="2"> + <PostZapsTab post={post} zaps={zaps} /> + </TabPanel> + ), + }, + { + id: "reposts", + name: `Reposts (${reposts.length})`, + visible: reposts.length > 0, + element: ( + <TabPanel key="reposts" p="0" py="2"> + <PostRepostsTab post={post} reposts={reposts} /> + </TabPanel> + ), + }, + { + id: "reactions", + name: `Reactions (${reactions.length})`, + visible: reactions.length > 0, + element: ( + <TabPanel key="reactions" p="0"> + <PostReactionsTab post={post} reactions={reactions} /> + </TabPanel> + ), + }, + { + id: "corrections", + name: `Corrections (${corrections.length})`, + visible: corrections.length > 0, + element: ( + <TabPanel key="corrections" p="0"> + <CorrectionsTab post={post} corrections={corrections} /> + </TabPanel> + ), + }, + { + id: "tools", + name: "Tools", + visible: true, + right: true, + element: ( + <TabPanel key="tools" p="0"> + <ToolsTab event={post.event} /> + </TabPanel> + ), + }, + { + id: "unknown", + name: `Unknown (${unknown.length})`, + visible: unknown.length > 0, + element: ( + <TabPanel key="unknown" p="0" py="2"> + <UnknownTab post={post} events={unknown} /> + </TabPanel> + ), + }, + ]; - return ( - <> - <HiddenScrollbar gap="4" px="2" overflowX="auto"> - <Button - size="sm" - flexShrink={0} - variant={selected === "replies" ? "solid" : "outline"} - onClick={() => setSelected("replies")} - > - Replies{post.replies.size > 0 ? ` (${post.replies.size})` : ""} - </Button> - <Button - size="sm" - flexShrink={0} - variant={selected === "quotes" ? "solid" : "outline"} - onClick={() => setSelected("quotes")} - > - Quotes{quotes.length > 0 ? ` (${quotes.length})` : ""} - </Button> - <Button - size="sm" - flexShrink={0} - variant={selected === "zaps" ? "solid" : "outline"} - onClick={() => setSelected("zaps")} - > - Zaps{zaps.length > 0 ? ` (${zaps.length})` : ""} - </Button> - <Button - size="sm" - flexShrink={0} - variant={selected === "reposts" ? "solid" : "outline"} - onClick={() => setSelected("reposts")} - > - Reposts{reposts.length && reposts.length > 0 ? ` (${reposts.length})` : ""} - </Button> - <Button - size="sm" - flexShrink={0} - variant={selected === "reactions" ? "solid" : "outline"} - onClick={() => setSelected("reactions")} - mr="auto" - > - Reactions{reactions.length > 0 ? ` (${reactions.length})` : ""} - </Button> - {corrections.length > 0 && ( - <Button - size="sm" - flexShrink={0} - variant={selected === "corrections" ? "solid" : "outline"} - onClick={() => setSelected("corrections")} - > - Corrections ({corrections.length}) - </Button> - )} - {unknown.length > 0 && ( - <Button - size="sm" - flexShrink={0} - variant={selected === "unknown" ? "solid" : "outline"} - onClick={() => setSelected("unknown")} - > - Unknown Refs ({unknown.length}) - </Button> - )} - </HiddenScrollbar> + const s = tabs.find((t) => t.id === selected.value); + const index = s ? tabs.indexOf(s) : 0; - {renderContent()} - </> + return ( + <Tabs + display="flex" + flexDirection="column" + flexGrow="1" + isLazy + index={index} + onChange={(v) => { + if (tabs[v]) selected.setValue(tabs[v].id, true); + else selected.clearValue(true); + }} + h="full" + colorScheme="primary" + variant="solid-rounded" + size="sm" + > + <HiddenScrollbarTabList px="2" gap="2" whiteSpace="pre" overflowX="auto"> + {tabs + .filter((t) => t.visible) + .map((tab) => ( + <Tab key={tab.id} ml={tab.right ? "auto" : undefined}> + {tab.name} + </Tab> + ))} + </HiddenScrollbarTabList> + <TabPanels minH={{ base: "50vh", md: "0" }}>{tabs.filter((t) => t.visible).map((tab) => tab.element)}</TabPanels> + </Tabs> ); } diff --git a/src/views/thread/components/reply-form.tsx b/src/views/thread/components/reply-form.tsx index ab0c5a6bf..0798b2d20 100644 --- a/src/views/thread/components/reply-form.tsx +++ b/src/views/thread/components/reply-form.tsx @@ -30,7 +30,7 @@ import { useTextAreaUploadFileWithForm } from "../../../hooks/use-textarea-uploa export type ReplyFormProps = { item: ThreadItem; replyKind?: number; - onCancel: () => void; + onCancel?: () => void; onSubmitted?: (event: NostrEvent) => void; }; @@ -104,7 +104,7 @@ export default function ReplyForm({ item, onCancel, onSubmitted, replyKind = kin /> <UserAvatarStack label="Notify" pubkeys={notifyPubkeys} /> <ButtonGroup size="sm" ml="auto"> - <Button onClick={onCancel}>Cancel</Button> + {onCancel && <Button onClick={onCancel}>Cancel</Button>} <Button type="submit" colorScheme="primary" size="sm"> Submit </Button> diff --git a/src/views/thread/components/tabs/tools.tsx b/src/views/thread/components/tabs/tools.tsx new file mode 100644 index 000000000..f94707fd2 --- /dev/null +++ b/src/views/thread/components/tabs/tools.tsx @@ -0,0 +1,61 @@ +import { ReactNode } from "react"; +import { Button, ComponentWithAs, Flex, Heading, IconButton, IconProps } from "@chakra-ui/react"; +import { NostrEvent } from "nostr-tools"; + +import Translate01 from "../../../../components/icons/translate-01"; +import Recording02 from "../../../../components/icons/recording-02"; +import PenTool01 from "../../../../components/icons/pen-tool-01"; +import { NoteTranslationsPage } from "../../../tools/transform-note/translation"; +import useRouteSearchValue from "../../../../hooks/use-route-search-value"; +import NoteTextToSpeechPage from "../../../tools/transform-note/text-to-speech"; +import EventSummarizePage from "./tools/summary"; + +const tools: { + icon: ComponentWithAs<"svg", IconProps>; + id: string; + name: string; + render: (event: NostrEvent) => ReactNode; +}[] = [ + { id: "translate", icon: Translate01, name: "Translate", render: (event) => <NoteTranslationsPage note={event} /> }, + { id: "tts", icon: Recording02, name: "Text to speech", render: (event) => <NoteTextToSpeechPage note={event} /> }, + { id: "summarize", icon: PenTool01, name: "Summarize", render: (event) => <EventSummarizePage event={event} /> }, +]; + +export default function ToolsTab({ event }: { event: NostrEvent }) { + const selected = useRouteSearchValue("tool", ""); + const tool = tools.find((t) => t.id === selected.value); + + const IconComponent = tool?.icon; + + return ( + <Flex direction="column" gap="2" p="2" w="full"> + <Flex gap="2" alignItems="center" wrap="wrap"> + {tool && IconComponent ? ( + <IconButton + icon={<IconComponent boxSize={6} />} + aria-label="Select Tool" + onClick={() => selected.clearValue(true)} + /> + ) : ( + <> + {tools.map(({ icon: Icon, name, id }) => ( + <Button + variant="outline" + key={id} + leftIcon={<Icon boxSize={10} mb="4" />} + onClick={() => selected.setValue(id, true)} + h="36" + w="36" + flexDirection="column" + > + {name} + </Button> + ))} + </> + )} + {tool && <Heading size="md">{tool.name}</Heading>} + </Flex> + {tool?.render(event)} + </Flex> + ); +} diff --git a/src/views/thread/components/tabs/tools/summary.tsx b/src/views/thread/components/tabs/tools/summary.tsx new file mode 100644 index 000000000..eb39d65a9 --- /dev/null +++ b/src/views/thread/components/tabs/tools/summary.tsx @@ -0,0 +1,101 @@ +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { Button, Flex, Spinner, Text, Textarea, useToast } from "@chakra-ui/react"; +import { EventTemplate, NostrEvent } from "nostr-tools"; +import { MultiSubscription } from "applesauce-net/subscription"; +import { useStoreQuery } from "applesauce-react/hooks"; +import { unixNow } from "applesauce-core/helpers"; + +import { useUserInbox } from "../../../../../hooks/use-user-mailboxes"; +import useCurrentAccount from "../../../../../hooks/use-current-account"; +import { usePublishEvent } from "../../../../../providers/global/publish-provider"; +import relayPoolService from "../../../../../services/relay-pool"; +import { eventStore } from "../../../../../services/event-store"; +import DVMResponsesQuery from "../../../../../queries/dvm-responses"; +import { DVMStatusCard } from "../../../../discovery/dvm-feed/components/feed-status"; + +function PromptForm({ onSubmit }: { onSubmit: (prompt: string) => void | Promise<void> }) { + const { register, handleSubmit } = useForm({ defaultValues: { prompt: "" } }); + + const submit = handleSubmit(async (values) => { + await onSubmit(values.prompt); + }); + + return ( + <Flex gap="2" direction="column" as="form" onSubmit={submit}> + <Textarea {...register("prompt")} placeholder="Prompt an AI model to summarize note" /> + <Button ml="auto" type="submit" size="sm" colorScheme="primary"> + Summarize + </Button> + </Flex> + ); +} + +export default function EventSummarizePage({ event }: { event: NostrEvent }) { + const toast = useToast(); + const [submitted, setSubmitted] = useState(false); + const [request, setRequest] = useState<NostrEvent>(); + + const publish = usePublishEvent(); + const account = useCurrentAccount(); + const inbox = useUserInbox(account?.pubkey); + + const newRequest = async (prompt: string) => { + try { + if (!inbox) throw new Error("Missing user inbox relays"); + + const draft: EventTemplate = { + kind: 5001, + content: "", + tags: [ + ["relays", ...inbox], + ["i", event.id, "event"], + ["output", "text/plain"], + ], + created_at: unixNow(), + }; + + // add human prompt + if (prompt) draft.tags.unshift(["i", prompt, "text"]); + + const pub = await publish("Summarize Event", draft); + setRequest(pub?.event); + setSubmitted(true); + } catch (error) { + if (error instanceof Error) toast({ description: error.message, status: "error" }); + } + }; + + useEffect(() => { + if (!inbox || !request) return; + + const sub = new MultiSubscription(relayPoolService); + sub.onEvent.subscribe((e) => eventStore.add(e)); + + sub.setFilters([{ kinds: [7000, 6001], "#e": [request.id] }]); + sub.setRelays(inbox); + sub.open(); + + return () => sub.close(); + }, [request]); + + const responses = useStoreQuery(DVMResponsesQuery, request ? [request] : undefined); + + return ( + <Flex direction="column" gap="2" px="2"> + {responses ? ( + <> + {Object.entries(responses).map(([pubkey, event]) => ( + <DVMStatusCard status={event} /> + ))} + </> + ) : submitted ? ( + <Text> + <Spinner /> Waiting for responses... + </Text> + ) : ( + <PromptForm onSubmit={newRequest} /> + )} + </Flex> + ); +} diff --git a/src/views/thread/index.tsx b/src/views/thread/index.tsx index 17ea3a36a..025966c49 100644 --- a/src/views/thread/index.tsx +++ b/src/views/thread/index.tsx @@ -40,7 +40,7 @@ function CollapsedReplies({ return ( <> {reply} - <Card gap="2" overflow="hidden" px="2" display="flex" flexDirection="row" p="2"> + <Card gap="2" overflow="hidden" px="2" display="flex" flexDirection="row" p="2" flexShrink={0}> <UserAvatarLink pubkey={post.event.pubkey} size="xs" /> <UserName pubkey={post.event.pubkey} fontWeight="bold" /> {root.id !== pointer.id && <ReplyIcon />} diff --git a/src/views/tools/transform-note/translation/translation-result.tsx b/src/views/tools/transform-note/translation/translation-result.tsx index c454074a3..2092d415c 100644 --- a/src/views/tools/transform-note/translation/translation-result.tsx +++ b/src/views/tools/transform-note/translation/translation-result.tsx @@ -5,6 +5,7 @@ import UserLink from "../../../../components/user/user-link"; import { NostrEvent } from "../../../../types/nostr-event"; import TextNoteContents from "../../../../components/note/timeline-note/text-note-contents"; import { TrustProvider } from "../../../../providers/local/trust-provider"; +import DebugEventButton from "../../../../components/debug-modal/debug-event-button"; export default function TranslationResult({ result }: { result: NostrEvent }) { const content = useDisclosure(); @@ -18,6 +19,7 @@ export default function TranslationResult({ result }: { result: NostrEvent }) { <Button size="sm" onClick={content.onToggle}> {content.isOpen ? "Hide" : "Show"} Content </Button> + <DebugEventButton ml="auto" event={result} size="sm" variant="ghost" /> </Flex> {content.isOpen && ( <TrustProvider trust>