This commit is contained in:
Ren Amamiya 2023-10-10 11:51:01 +07:00
parent 043c1b1220
commit bc4c3b9803
39 changed files with 411 additions and 216 deletions

View File

@ -61,6 +61,7 @@
"html-to-text": "^9.0.5", "html-to-text": "^9.0.5",
"light-bolt11-decoder": "^3.0.0", "light-bolt11-decoder": "^3.0.0",
"lru-cache": "^10.0.1", "lru-cache": "^10.0.1",
"million": "^2.6.4",
"minidenticons": "^4.2.0", "minidenticons": "^4.2.0",
"nostr-fetch": "^0.13.0", "nostr-fetch": "^0.13.0",
"nostr-tools": "^1.16.0", "nostr-tools": "^1.16.0",

View File

@ -134,6 +134,9 @@ dependencies:
lru-cache: lru-cache:
specifier: ^10.0.1 specifier: ^10.0.1
version: 10.0.1 version: 10.0.1
million:
specifier: ^2.6.4
version: 2.6.4
minidenticons: minidenticons:
specifier: ^4.2.0 specifier: ^4.2.0
version: 4.2.0 version: 4.2.0
@ -301,13 +304,48 @@ packages:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'} engines: {node: '>=10'}
/@ampproject/remapping@2.2.1:
resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
engines: {node: '>=6.0.0'}
dependencies:
'@jridgewell/gen-mapping': 0.3.3
'@jridgewell/trace-mapping': 0.3.19
dev: false
/@babel/code-frame@7.22.13: /@babel/code-frame@7.22.13:
resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/highlight': 7.22.20 '@babel/highlight': 7.22.20
chalk: 2.4.2 chalk: 2.4.2
dev: true
/@babel/compat-data@7.22.20:
resolution: {integrity: sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==}
engines: {node: '>=6.9.0'}
dev: false
/@babel/core@7.23.0:
resolution: {integrity: sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==}
engines: {node: '>=6.9.0'}
dependencies:
'@ampproject/remapping': 2.2.1
'@babel/code-frame': 7.22.13
'@babel/generator': 7.23.0
'@babel/helper-compilation-targets': 7.22.15
'@babel/helper-module-transforms': 7.23.0(@babel/core@7.23.0)
'@babel/helpers': 7.23.1
'@babel/parser': 7.23.0
'@babel/template': 7.22.15
'@babel/traverse': 7.23.0
'@babel/types': 7.23.0
convert-source-map: 2.0.0
debug: 4.3.4
gensync: 1.0.0-beta.2
json5: 2.2.3
semver: 6.3.1
transitivePeerDependencies:
- supports-color
dev: false
/@babel/generator@7.17.7: /@babel/generator@7.17.7:
resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==}
@ -318,10 +356,30 @@ packages:
source-map: 0.5.7 source-map: 0.5.7
dev: true dev: true
/@babel/generator@7.23.0:
resolution: {integrity: sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.0
'@jridgewell/gen-mapping': 0.3.3
'@jridgewell/trace-mapping': 0.3.19
jsesc: 2.5.2
dev: false
/@babel/helper-compilation-targets@7.22.15:
resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/compat-data': 7.22.20
'@babel/helper-validator-option': 7.22.15
browserslist: 4.22.1
lru-cache: 5.1.1
semver: 6.3.1
dev: false
/@babel/helper-environment-visitor@7.22.20: /@babel/helper-environment-visitor@7.22.20:
resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dev: true
/@babel/helper-function-name@7.23.0: /@babel/helper-function-name@7.23.0:
resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
@ -329,31 +387,75 @@ packages:
dependencies: dependencies:
'@babel/template': 7.22.15 '@babel/template': 7.22.15
'@babel/types': 7.23.0 '@babel/types': 7.23.0
dev: true
/@babel/helper-hoist-variables@7.22.5: /@babel/helper-hoist-variables@7.22.5:
resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/types': 7.23.0 '@babel/types': 7.23.0
dev: true
/@babel/helper-module-imports@7.22.15:
resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.0
dev: false
/@babel/helper-module-transforms@7.23.0(@babel/core@7.23.0):
resolution: {integrity: sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
dependencies:
'@babel/core': 7.23.0
'@babel/helper-environment-visitor': 7.22.20
'@babel/helper-module-imports': 7.22.15
'@babel/helper-simple-access': 7.22.5
'@babel/helper-split-export-declaration': 7.22.6
'@babel/helper-validator-identifier': 7.22.20
dev: false
/@babel/helper-plugin-utils@7.22.5:
resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==}
engines: {node: '>=6.9.0'}
dev: false
/@babel/helper-simple-access@7.22.5:
resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.0
dev: false
/@babel/helper-split-export-declaration@7.22.6: /@babel/helper-split-export-declaration@7.22.6:
resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/types': 7.23.0 '@babel/types': 7.23.0
dev: true
/@babel/helper-string-parser@7.22.5: /@babel/helper-string-parser@7.22.5:
resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dev: true
/@babel/helper-validator-identifier@7.22.20: /@babel/helper-validator-identifier@7.22.20:
resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dev: true
/@babel/helper-validator-option@7.22.15:
resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==}
engines: {node: '>=6.9.0'}
dev: false
/@babel/helpers@7.23.1:
resolution: {integrity: sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/template': 7.22.15
'@babel/traverse': 7.23.0
'@babel/types': 7.23.0
transitivePeerDependencies:
- supports-color
dev: false
/@babel/highlight@7.22.20: /@babel/highlight@7.22.20:
resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==}
@ -362,7 +464,6 @@ packages:
'@babel/helper-validator-identifier': 7.22.20 '@babel/helper-validator-identifier': 7.22.20
chalk: 2.4.2 chalk: 2.4.2
js-tokens: 4.0.0 js-tokens: 4.0.0
dev: true
/@babel/parser@7.23.0: /@babel/parser@7.23.0:
resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==} resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==}
@ -370,7 +471,26 @@ packages:
hasBin: true hasBin: true
dependencies: dependencies:
'@babel/types': 7.17.0 '@babel/types': 7.17.0
dev: true
/@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.23.0):
resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.23.0
'@babel/helper-plugin-utils': 7.22.5
dev: false
/@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.23.0):
resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.23.0
'@babel/helper-plugin-utils': 7.22.5
dev: false
/@babel/runtime@7.23.1: /@babel/runtime@7.23.1:
resolution: {integrity: sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==} resolution: {integrity: sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==}
@ -385,7 +505,6 @@ packages:
'@babel/code-frame': 7.22.13 '@babel/code-frame': 7.22.13
'@babel/parser': 7.23.0 '@babel/parser': 7.23.0
'@babel/types': 7.23.0 '@babel/types': 7.23.0
dev: true
/@babel/traverse@7.17.3: /@babel/traverse@7.17.3:
resolution: {integrity: sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==} resolution: {integrity: sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==}
@ -405,13 +524,30 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@babel/traverse@7.23.0:
resolution: {integrity: sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/code-frame': 7.22.13
'@babel/generator': 7.23.0
'@babel/helper-environment-visitor': 7.22.20
'@babel/helper-function-name': 7.23.0
'@babel/helper-hoist-variables': 7.22.5
'@babel/helper-split-export-declaration': 7.22.6
'@babel/parser': 7.23.0
'@babel/types': 7.23.0
debug: 4.3.4
globals: 11.12.0
transitivePeerDependencies:
- supports-color
dev: false
/@babel/types@7.17.0: /@babel/types@7.17.0:
resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/helper-validator-identifier': 7.22.20 '@babel/helper-validator-identifier': 7.22.20
to-fast-properties: 2.0.0 to-fast-properties: 2.0.0
dev: true
/@babel/types@7.23.0: /@babel/types@7.23.0:
resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==} resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==}
@ -420,7 +556,6 @@ packages:
'@babel/helper-string-parser': 7.22.5 '@babel/helper-string-parser': 7.22.5
'@babel/helper-validator-identifier': 7.22.20 '@babel/helper-validator-identifier': 7.22.20
to-fast-properties: 2.0.0 to-fast-properties: 2.0.0
dev: true
/@esbuild/android-arm64@0.18.20: /@esbuild/android-arm64@0.18.20:
resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
@ -2817,7 +2952,6 @@ packages:
resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==}
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true hasBin: true
dev: true
/ajv@6.12.6: /ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
@ -2850,7 +2984,6 @@ packages:
engines: {node: '>=4'} engines: {node: '>=4'}
dependencies: dependencies:
color-convert: 1.9.3 color-convert: 1.9.3
dev: true
/ansi-styles@4.3.0: /ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
@ -3033,7 +3166,6 @@ packages:
electron-to-chromium: 1.4.546 electron-to-chromium: 1.4.546
node-releases: 2.0.13 node-releases: 2.0.13
update-browserslist-db: 1.0.13(browserslist@4.22.1) update-browserslist-db: 1.0.13(browserslist@4.22.1)
dev: true
/bufferutil@4.0.7: /bufferutil@4.0.7:
resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==} resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==}
@ -3061,7 +3193,6 @@ packages:
/caniuse-lite@1.0.30001546: /caniuse-lite@1.0.30001546:
resolution: {integrity: sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==} resolution: {integrity: sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==}
dev: true
/case-anything@2.1.13: /case-anything@2.1.13:
resolution: {integrity: sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==} resolution: {integrity: sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==}
@ -3079,7 +3210,6 @@ packages:
ansi-styles: 3.2.1 ansi-styles: 3.2.1
escape-string-regexp: 1.0.5 escape-string-regexp: 1.0.5
supports-color: 5.5.0 supports-color: 5.5.0
dev: true
/chalk@4.1.2: /chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
@ -3139,7 +3269,6 @@ packages:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies: dependencies:
color-name: 1.1.3 color-name: 1.1.3
dev: true
/color-convert@2.0.1: /color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
@ -3150,7 +3279,6 @@ packages:
/color-name@1.1.3: /color-name@1.1.3:
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
dev: true
/color-name@1.1.4: /color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
@ -3176,6 +3304,10 @@ packages:
/concat-map@0.0.1: /concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
/convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
dev: false
/crelt@1.0.6: /crelt@1.0.6:
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
dev: false dev: false
@ -3435,7 +3567,6 @@ packages:
/electron-to-chromium@1.4.546: /electron-to-chromium@1.4.546:
resolution: {integrity: sha512-cz9bBM26ZqoEmGHkdHXU3LP7OofVyEzRoMqfALQ9Au9WlB4rogAHzqj/NkNvw2JJjy4xuxS1me+pP2lbCD5Mfw==} resolution: {integrity: sha512-cz9bBM26ZqoEmGHkdHXU3LP7OofVyEzRoMqfALQ9Au9WlB4rogAHzqj/NkNvw2JJjy4xuxS1me+pP2lbCD5Mfw==}
dev: true
/emoji-regex@9.2.2: /emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
@ -3603,12 +3734,10 @@ packages:
/escalade@3.1.1: /escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'} engines: {node: '>=6'}
dev: true
/escape-string-regexp@1.0.5: /escape-string-regexp@1.0.5:
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
engines: {node: '>=0.8.0'} engines: {node: '>=0.8.0'}
dev: true
/escape-string-regexp@4.0.0: /escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
@ -3924,6 +4053,11 @@ packages:
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
dev: true dev: true
/gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
dev: false
/get-intrinsic@1.2.1: /get-intrinsic@1.2.1:
resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==}
dependencies: dependencies:
@ -3987,7 +4121,6 @@ packages:
/globals@11.12.0: /globals@11.12.0:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true
/globals@13.23.0: /globals@13.23.0:
resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==}
@ -4036,7 +4169,6 @@ packages:
/has-flag@3.0.0: /has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true
/has-flag@4.0.0: /has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
@ -4397,7 +4529,6 @@ packages:
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
engines: {node: '>=4'} engines: {node: '>=4'}
hasBin: true hasBin: true
dev: true
/json-buffer@3.0.1: /json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
@ -4411,6 +4542,12 @@ packages:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
dev: true dev: true
/json5@2.2.3:
resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
engines: {node: '>=6'}
hasBin: true
dev: false
/jsx-ast-utils@3.3.5: /jsx-ast-utils@3.3.5:
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
engines: {node: '>=4.0'} engines: {node: '>=4.0'}
@ -4559,6 +4696,12 @@ packages:
engines: {node: 14 || >=16.14} engines: {node: 14 || >=16.14}
dev: false dev: false
/lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
dependencies:
yallist: 3.1.1
dev: false
/lru-cache@6.0.0: /lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -4987,6 +5130,22 @@ packages:
braces: 3.0.2 braces: 3.0.2
picomatch: 2.3.1 picomatch: 2.3.1
/million@2.6.4:
resolution: {integrity: sha512-voUkdd/jHWrG+7NS+mX49Pat+POKdgGW78V7pYMSrTaOjUitR6ySEcAci8hn17Rsx1IMI3+5w41dkADM1J1ZEg==}
hasBin: true
dependencies:
'@babel/core': 7.23.0
'@babel/generator': 7.23.0
'@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.23.0)
'@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.23.0)
'@babel/types': 7.23.0
kleur: 4.1.5
rollup: 3.29.4
unplugin: 1.5.0
transitivePeerDependencies:
- supports-color
dev: false
/mimic-fn@2.1.0: /mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -5060,7 +5219,6 @@ packages:
/node-releases@2.0.13: /node-releases@2.0.13:
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
dev: true
/normalize-path@3.0.0: /normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
@ -5902,7 +6060,6 @@ packages:
hasBin: true hasBin: true
optionalDependencies: optionalDependencies:
fsevents: 2.3.3 fsevents: 2.3.3
dev: true
/rope-sequence@1.3.4: /rope-sequence@1.3.4:
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
@ -5957,7 +6114,6 @@ packages:
/semver@6.3.1: /semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true hasBin: true
dev: true
/semver@7.5.4: /semver@7.5.4:
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
@ -6127,7 +6283,6 @@ packages:
engines: {node: '>=4'} engines: {node: '>=4'}
dependencies: dependencies:
has-flag: 3.0.0 has-flag: 3.0.0
dev: true
/supports-color@7.2.0: /supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
@ -6230,7 +6385,6 @@ packages:
/to-fast-properties@2.0.0: /to-fast-properties@2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true
/to-regex-range@5.0.1: /to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
@ -6428,6 +6582,15 @@ packages:
unist-util-visit-parents: 5.1.3 unist-util-visit-parents: 5.1.3
dev: false dev: false
/unplugin@1.5.0:
resolution: {integrity: sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==}
dependencies:
acorn: 8.10.0
chokidar: 3.5.3
webpack-sources: 3.2.3
webpack-virtual-modules: 0.5.0
dev: false
/update-browserslist-db@1.0.13(browserslist@4.22.1): /update-browserslist-db@1.0.13(browserslist@4.22.1):
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
hasBin: true hasBin: true
@ -6437,7 +6600,6 @@ packages:
browserslist: 4.22.1 browserslist: 4.22.1
escalade: 3.1.1 escalade: 3.1.1
picocolors: 1.0.0 picocolors: 1.0.0
dev: true
/uri-js@4.4.1: /uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
@ -6599,6 +6761,15 @@ packages:
engines: {node: '>= 8'} engines: {node: '>= 8'}
dev: false dev: false
/webpack-sources@3.2.3:
resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
engines: {node: '>=10.13.0'}
dev: false
/webpack-virtual-modules@0.5.0:
resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==}
dev: false
/websocket-polyfill@0.0.3: /websocket-polyfill@0.0.3:
resolution: {integrity: sha512-pF3kR8Uaoau78MpUmFfzbIRxXj9PeQrCuPepGE6JIsfsJ/o/iXr07Q2iQNzKSSblQJ0FiGWlS64N4pVSm+O3Dg==} resolution: {integrity: sha512-pF3kR8Uaoau78MpUmFfzbIRxXj9PeQrCuPepGE6JIsfsJ/o/iXr07Q2iQNzKSSblQJ0FiGWlS64N4pVSm+O3Dg==}
dependencies: dependencies:
@ -6695,6 +6866,10 @@ packages:
engines: {node: '>=0.10.32'} engines: {node: '>=0.10.32'}
dev: false dev: false
/yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
dev: false
/yallist@4.0.0: /yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: true dev: true

View File

@ -9,6 +9,12 @@
html { html {
font-size: 14px; font-size: 14px;
/* Smoothing */
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
font-smoothing: antialiased;
-webkit-font-smoothing: antialiased;
text-shadow: rgba(0, 0, 0, .01) 0 0 1px;
} }
a { a {

View File

@ -79,7 +79,7 @@ export function RelayScreen() {
<a <a
href={`mailto:${resolvedRelay.contact}`} href={`mailto:${resolvedRelay.contact}`}
target="_blank" target="_blank"
className="underline after:content-['_↗'] hover:text-blue-500" className="underline after:content-['_↗'] hover:text-blue-600"
rel="noreferrer" rel="noreferrer"
> >
mailto:{resolvedRelay.contact} mailto:{resolvedRelay.contact}
@ -92,7 +92,7 @@ export function RelayScreen() {
href={resolvedRelay.software} href={resolvedRelay.software}
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
className="underline after:content-['_↗'] hover:text-blue-500" className="underline after:content-['_↗'] hover:text-blue-600"
> >
{getSoftwareName(resolvedRelay.software) + {getSoftwareName(resolvedRelay.software) +
' - ' + ' - ' +

View File

@ -1,5 +1,5 @@
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect } from 'react';
import { VList } from 'virtua'; import { VList, WVList } from 'virtua';
import { ToggleWidgetList } from '@app/space/components/toggle'; import { ToggleWidgetList } from '@app/space/components/toggle';
import { WidgetList } from '@app/space/components/widgetList'; import { WidgetList } from '@app/space/components/widgetList';
@ -85,17 +85,15 @@ export function SpaceScreen() {
}, [fetchWidgets]); }, [fetchWidgets]);
return ( return (
<div className="h-full w-full"> <VList className="h-screen w-full scrollbar-none" horizontal>
<VList className="h-full w-full scrollbar-none" horizontal> {!widgets ? (
{!widgets ? ( <div className="flex h-full w-[420px] flex-col items-center justify-center">
<div className="flex h-full w-full flex-col items-center justify-center"> <LoaderIcon className="h-5 w-5 animate-spin text-neutral-900 dark:text-neutral-100" />
<LoaderIcon className="h-5 w-5 animate-spin text-neutral-900 dark:text-neutral-100" /> </div>
</div> ) : (
) : ( widgets.map((widget) => renderItem(widget))
widgets.map((widget) => renderItem(widget)) )}
)} <ToggleWidgetList />
<ToggleWidgetList /> </VList>
</VList>
</div>
); );
} }

View File

@ -62,7 +62,7 @@ export function ActiveAccount() {
alt={db.account.npub} alt={db.account.npub}
className="aspect-square h-full w-full rounded-md" className="aspect-square h-full w-full rounded-md"
/> />
<span className="absolute bottom-0 right-0 block h-2 w-2 rounded-full bg-green-400 ring-2 ring-neutral-50 dark:ring-neutral-950" /> <span className="absolute bottom-0 right-0 block h-2 w-2 rounded-full bg-emerald-500 ring-2 ring-neutral-100 dark:ring-neutral-900" />
</Link> </Link>
<div className="inline-flex items-center justify-center rounded-md"> <div className="inline-flex items-center justify-center rounded-md">
<HorizontalDotsIcon className="h-4 w-4" /> <HorizontalDotsIcon className="h-4 w-4" />

View File

@ -11,11 +11,16 @@ export function FocusIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElemen
{...props} {...props}
> >
<path <path
stroke="currentColor" fill="currentColor"
strokeLinecap="round" d="M9 13a3 3 0 013 3v3a3 3 0 01-3 3H5a3 3 0 01-3-3v-3a3 3 0 013-3h4z"
strokeLinejoin="round" ></path>
strokeWidth="1.5" <path
d="M8.25 3.75h-3.5a1 1 0 00-1 1v3.5m12-4.5h3.5a1 1 0 011 1v3.5m0 7.5v3.5a1 1 0 01-1 1h-3.5m-7.5 0h-3.5a1 1 0 01-1-1v-3.5" fill="currentColor"
d="M20 6a1 1 0 00-1-1H6a1 1 0 00-1 1v4a1 1 0 11-2 0V6a3 3 0 013-3h13a3 3 0 013 3v7a3 3 0 01-3 3h-4a1 1 0 110-2h4a1 1 0 001-1V6z"
></path>
<path
fill="currentColor"
d="M17 7a1 1 0 011 1v3a1 1 0 11-2 0v-.586l-1.293 1.293a1 1 0 01-1.414-1.414L14.586 9H14a1 1 0 110-2h3z"
></path> ></path>
</svg> </svg>
); );

View File

@ -12,17 +12,13 @@ export function HorizontalDotsIcon(
viewBox="0 0 24 24" viewBox="0 0 24 24"
{...props} {...props}
> >
<path
fill="currentColor"
d="M12 13a1 1 0 100-2 1 1 0 000 2zM20.25 13a1 1 0 100-2 1 1 0 000 2zM3.75 13a1 1 0 100-2 1 1 0 000 2z"
/>
<path <path
stroke="currentColor" stroke="currentColor"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
strokeWidth="1.5" strokeWidth="2"
d="M12 13a1 1 0 100-2 1 1 0 000 2zM20.25 13a1 1 0 100-2 1 1 0 000 2zM3.75 13a1 1 0 100-2 1 1 0 000 2z" d="M12 13a1 1 0 100-2 1 1 0 000 2zM20 13a1 1 0 100-2 1 1 0 000 2zM4 13a1 1 0 100-2 1 1 0 000 2z"
/> ></path>
</svg> </svg>
); );
} }

View File

@ -12,24 +12,12 @@ export function ReactionIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGEle
> >
<path <path
fill="currentColor" fill="currentColor"
fillRule="evenodd" d="M10.499 9.5c0 .828-.56 1.5-1.25 1.5s-1.25-.672-1.25-1.5.56-1.5 1.25-1.5 1.25.672 1.25 1.5zM15.999 9.5c0 .828-.56 1.5-1.25 1.5s-1.25-.672-1.25-1.5.56-1.5 1.25-1.5 1.25.672 1.25 1.5z"
d="M19 1a.75.75 0 01.75.75v2.5h2.5a.75.75 0 110 1.5h-2.5v2.5a.75.75 0 11-1.5 0v-2.5h-2.5a.75.75 0 110-1.5h2.5v-2.5A.75.75 0 0119 1z"
clipRule="evenodd"
></path>
<path
fill="currentColor"
d="M10.5 9.5c0 .828-.56 1.5-1.25 1.5S8 10.328 8 9.5 8.56 8 9.25 8s1.25.672 1.25 1.5zM16 9.5c0 .828-.56 1.5-1.25 1.5s-1.25-.672-1.25-1.5.56-1.5 1.25-1.5S16 8.672 16 9.5z"
></path> ></path>
<path <path
fill="currentColor" fill="currentColor"
fillRule="evenodd" fillRule="evenodd"
d="M8.642 14.298a.75.75 0 011.06 0 3.25 3.25 0 004.597 0 .75.75 0 011.06 1.06 4.75 4.75 0 01-6.717 0 .75.75 0 010-1.06z" d="M18.999 1a1 1 0 011 1v2h2a1 1 0 110 2h-2v2a1 1 0 11-2 0V6h-2a1 1 0 010-2h2V2a1 1 0 011-1zm-7.006 1.945a1 1 0 01-.884 1.104 8.001 8.001 0 108.842 8.841 1 1 0 011.988.22C21.386 18.11 17.148 22 12 22 6.477 22 2 17.523 2 12c0-5.147 3.888-9.385 8.889-9.939a1 1 0 011.104.884zm-3.53 11.176a1 1 0 011.415 0 3 3 0 004.242 0 1 1 0 011.415 1.415 5 5 0 01-7.072 0 1 1 0 010-1.415z"
clipRule="evenodd"
></path>
<path
fill="currentColor"
fillRule="evenodd"
d="M12 3.5a8.5 8.5 0 108.5 8.5.75.75 0 011.5 0c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2a.75.75 0 010 1.5z"
clipRule="evenodd" clipRule="evenodd"
></path> ></path>
</svg> </svg>

View File

@ -2,14 +2,28 @@ import { SVGProps } from 'react';
export function ReplyIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) { export function ReplyIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
return ( return (
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}> <svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
fill="none"
viewBox="0 0 24 24"
{...props}
>
<path <path
d="M12 21.25C17.1086 21.25 21.25 17.1086 21.25 12C21.25 6.89137 17.1086 2.75 12 2.75C6.89137 2.75 2.75 6.89137 2.75 12C2.75 13.529 3.12096 14.9713 3.77778 16.2418L2.75 21.25L7.88889 20.2885C9.12732 20.9039 10.5232 21.25 12 21.25Z"
stroke="currentColor" stroke="currentColor"
strokeWidth={1.5}
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> strokeWidth="2"
d="M12 21a9 9 0 10-9-9c0 1.354.3 2.639.835 3.791.102.219.133.465.076.7l-.778 3.191a1 1 0 001.191 1.213l3.33-.752c.224-.05.458-.02.667.073A8.969 8.969 0 0012 21z"
></path>
<path
fill="currentColor"
stroke="currentColor"
strokeLinecap="square"
strokeWidth="0.75"
d="M6.625 12a.875.875 0 101.75 0 .875.875 0 00-1.75 0zm4.5 0a.875.875 0 101.75 0 .875.875 0 00-1.75 0zm4.5 0a.875.875 0 101.75 0 .875.875 0 00-1.75 0z"
></path>
</svg> </svg>
); );
} }

View File

@ -11,10 +11,8 @@ export function RepostIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGEleme
{...props} {...props}
> >
<path <path
stroke="currentColor" fill="currentColor"
strokeLinejoin="round" d="M17.957 2.293a1 1 0 10-1.414 1.414L17.836 5H6a3 3 0 00-3 3v3a1 1 0 102 0V8a1 1 0 011-1h11.836l-1.293 1.293a1 1 0 001.414 1.414l2.47-2.47a1.75 1.75 0 000-2.474l-2.47-2.47zM20 12a1 1 0 011 1v3a3 3 0 01-3 3H6.164l1.293 1.293a1 1 0 11-1.414 1.414l-2.47-2.47a1.75 1.75 0 010-2.474l2.47-2.47a1 1 0 011.414 1.414L6.164 17H18a1 1 0 001-1v-3a1 1 0 011-1z"
strokeWidth="1.5"
d="M12 21.25c4.28 0 7.75-3.75 7.75-8.25 0-5.167-4.613-8.829-6.471-10.094-.426-.29-.988-.165-1.285.257L9.582 6.59a1.002 1.002 0 01-1.525.131c-.39-.387-1.026-.391-1.376.033C5.06 8.718 4.25 11.16 4.25 13c0 4.5 3.47 8.25 7.75 8.25zm0 0c1.657 0 3-1.533 3-3.424 0-2.084-1.663-3.601-2.513-4.24a.802.802 0 00-.974 0c-.85.639-2.513 2.156-2.513 4.24 0 1.89 1.343 3.424 3 3.424z"
></path> ></path>
</svg> </svg>
); );

View File

@ -12,7 +12,7 @@ export function ThreadIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGEleme
> >
<path <path
fill="currentColor" fill="currentColor"
d="M12 19.25V20a.75.75 0 00.75-.75H12zm8.5-9a.75.75 0 001.5 0h-1.5zm-.75 3.5a.75.75 0 00-1.5 0h1.5zm-1.5 6.5a.75.75 0 001.5 0h-1.5zm-2.5-4a.75.75 0 000 1.5v-1.5zm6.5 1.5a.75.75 0 000-1.5v1.5zm-18.75.5V5.75H2v12.5h1.5zm8.5.25H3.75V20H12v-1.5zm8.5-12.75v4.5H22v-4.5h-1.5zM3.75 5.5H12V4H3.75v1.5zm8.25 0h8.25V4H12v1.5zm.75 13.75V4.75h-1.5v14.5h1.5zm5.5-5.5V17h1.5v-3.25h-1.5zm0 3.25v3.25h1.5V17h-1.5zm-2.5.75H19v-1.5h-3.25v1.5zm3.25 0h3.25v-1.5H19v1.5zm3-12A1.75 1.75 0 0020.25 4v1.5a.25.25 0 01.25.25H22zm-18.5 0a.25.25 0 01.25-.25V4A1.75 1.75 0 002 5.75h1.5zM2 18.25c0 .966.784 1.75 1.75 1.75v-1.5a.25.25 0 01-.25-.25H2z" d="M12 19v1a1 1 0 001-1h-1zm8-9a1 1 0 102 0h-2zm0 4a1 1 0 10-2 0h2zm-2 6a1 1 0 102 0h-2zm-2-4a1 1 0 100 2v-2zm6 2a1 1 0 100-2v2zM4 17V7H2v10h2zm8 1H5v2h7v-2zm8-11v3h2V7h-2zM5 6h7V4H5v2zm7 0h7V4h-7v2zm1 13V5h-2v14h2zm5-5v3h2v-3h-2zm0 3v3h2v-3h-2zm-2 1h3v-2h-3v2zm3 0h3v-2h-3v2zm3-11a3 3 0 00-3-3v2a1 1 0 011 1h2zM4 7a1 1 0 011-1V4a3 3 0 00-3 3h2zM2 17a3 3 0 003 3v-2a1 1 0 01-1-1H2z"
></path> ></path>
</svg> </svg>
); );

View File

@ -3,20 +3,20 @@ import { SVGProps } from 'react';
export function ZapIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) { export function ZapIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) {
return ( return (
<svg <svg
width={24}
height={24}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
fill="none"
viewBox="0 0 24 24"
{...props} {...props}
> >
<path <path
d="M3.75 12.75L8.75 2.75H18L15.25 8.25H21.25L6.75 21.25L8.89706 12.75H3.75Z"
stroke="currentColor" stroke="currentColor"
strokeWidth={1.5}
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> strokeWidth="2"
d="M4.116 12.276l4.5-9A.5.5 0 019.063 3h8.058a.5.5 0 01.429.757l-2.091 3.486a.5.5 0 00.428.757h4.804a.5.5 0 01.332.873L7.381 21.023c-.38.34-.965-.042-.808-.527l2.219-6.842A.5.5 0 008.316 13H4.563a.5.5 0 01-.447-.724z"
></path>
</svg> </svg>
); );
} }

View File

@ -28,33 +28,16 @@ export function NoteActions({
return ( return (
<Tooltip.Provider> <Tooltip.Provider>
<div className="-ml-1 mt-3 inline-flex w-full items-center"> <div className="-ml-1 mt-4 inline-flex w-full items-center">
<div className="inline-flex items-center gap-2"> <div className="inline-flex items-center gap-8">
<NoteReply id={id} pubkey={pubkey} root={root} /> <NoteReply id={id} pubkey={pubkey} root={root} />
<NoteReaction id={id} pubkey={pubkey} /> <NoteReaction id={id} pubkey={pubkey} />
<NoteRepost id={id} pubkey={pubkey} /> <NoteRepost id={id} pubkey={pubkey} />
<NoteZap id={id} pubkey={pubkey} /> <NoteZap id={id} pubkey={pubkey} />
</div> </div>
{extraButtons && ( {extraButtons && (
<> <div className="ml-auto">
<div className="mx-2 block h-4 w-px bg-white/10 backdrop-blur-xl" /> <div className="inline-flex items-center gap-3">
<div className="inline-flex items-center gap-2">
<Tooltip.Root delayDuration={150}>
<Tooltip.Trigger asChild>
<Link
to={`/notes/text/${id}`}
className="group inline-flex h-7 w-7 items-center justify-center"
>
<FocusIcon className="h-5 w-5 text-white/80 group-hover:text-blue-400" />
</Link>
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content className="-left-10 select-none rounded-md bg-black px-3.5 py-1.5 text-sm leading-none text-white will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
Focus
<Tooltip.Arrow className="fill-black" />
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
<Tooltip.Root delayDuration={150}> <Tooltip.Root delayDuration={150}>
<Tooltip.Trigger asChild> <Tooltip.Trigger asChild>
<button <button
@ -66,22 +49,22 @@ export function NoteActions({
content: id, content: id,
}) })
} }
className="group inline-flex h-7 w-7 items-center justify-center" className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
> >
<ThreadIcon className="h-5 w-5 text-white/80 group-hover:text-blue-400" /> <ThreadIcon className="h-5 w-5 group-hover:text-blue-500" />
</button> </button>
</Tooltip.Trigger> </Tooltip.Trigger>
<Tooltip.Portal> <Tooltip.Portal>
<Tooltip.Content className="-left-10 select-none rounded-md bg-black px-3.5 py-1.5 text-sm leading-none text-white will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade"> <Tooltip.Content className="-left-10 inline-flex h-7 select-none items-center justify-center rounded-md bg-neutral-200 px-3.5 text-sm text-neutral-900 will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade dark:bg-neutral-800 dark:text-neutral-100">
Open thread Open thread
<Tooltip.Arrow className="fill-black" /> <Tooltip.Arrow className="fill-neutral-200 dark:fill-neutral-800" />
</Tooltip.Content> </Tooltip.Content>
</Tooltip.Portal> </Tooltip.Portal>
</Tooltip.Root> </Tooltip.Root>
<MoreActions id={id} pubkey={pubkey} />
</div> </div>
</> </div>
)} )}
<MoreActions id={id} pubkey={pubkey} />
</div> </div>
</Tooltip.Provider> </Tooltip.Provider>
); );

View File

@ -30,26 +30,35 @@ export function MoreActions({ id, pubkey }: { id: string; pubkey: string }) {
<DropdownMenu.Trigger asChild> <DropdownMenu.Trigger asChild>
<button <button
type="button" type="button"
className="group ml-auto inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300" className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
> >
<HorizontalDotsIcon className="h-5 w-5 group-hover:text-blue-500" /> <HorizontalDotsIcon className="h-5 w-5 group-hover:text-blue-500" />
</button> </button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
</Tooltip.Trigger> </Tooltip.Trigger>
<Tooltip.Portal> <Tooltip.Portal>
<Tooltip.Content className="-left-10 select-none rounded-md bg-black px-3.5 py-1.5 text-sm leading-none text-white will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade"> <Tooltip.Content className="-left-10 inline-flex h-7 select-none items-center justify-center rounded-md bg-neutral-200 px-3.5 text-sm text-neutral-900 will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade dark:bg-neutral-800 dark:text-neutral-100">
More More
<Tooltip.Arrow className="fill-black" /> <Tooltip.Arrow className="fill-neutral-200 dark:fill-neutral-800" />
</Tooltip.Content> </Tooltip.Content>
</Tooltip.Portal> </Tooltip.Portal>
</Tooltip.Root> </Tooltip.Root>
<DropdownMenu.Portal> <DropdownMenu.Portal>
<DropdownMenu.Content className="flex w-[200px] flex-col overflow-hidden rounded-xl border border-white/10 bg-white/20 p-2 backdrop-blur-3xl focus:outline-none"> <DropdownMenu.Content className="flex w-[200px] flex-col overflow-hidden rounded-xl border border-neutral-300 bg-neutral-200 focus:outline-none dark:border-neutral-700 dark:bg-neutral-800">
<DropdownMenu.Item asChild> <DropdownMenu.Item asChild>
<button <button
type="button" type="button"
onClick={() => copyLink()} onClick={() => copyLink()}
className="inline-flex h-10 items-center rounded-md px-2 text-sm font-medium text-white hover:bg-white/10 focus:outline-none" className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-300 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-700"
>
Focus
</button>
</DropdownMenu.Item>
<DropdownMenu.Item asChild>
<button
type="button"
onClick={() => copyLink()}
className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-300 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-700"
> >
Copy shareable link Copy shareable link
</button> </button>
@ -58,7 +67,7 @@ export function MoreActions({ id, pubkey }: { id: string; pubkey: string }) {
<button <button
type="button" type="button"
onClick={() => copyID()} onClick={() => copyID()}
className="inline-flex h-10 items-center rounded-md px-2 text-sm font-medium text-white hover:bg-white/10 focus:outline-none" className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-300 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-700"
> >
Copy ID Copy ID
</button> </button>
@ -66,7 +75,7 @@ export function MoreActions({ id, pubkey }: { id: string; pubkey: string }) {
<DropdownMenu.Item asChild> <DropdownMenu.Item asChild>
<Link <Link
to={`/users/${pubkey}`} to={`/users/${pubkey}`}
className="inline-flex h-10 items-center rounded-md px-2 text-sm font-medium text-white hover:bg-white/10 focus:outline-none" className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-300 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-700"
> >
View profile View profile
</Link> </Link>

View File

@ -65,15 +65,15 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300" className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
> >
{reaction ? ( {reaction ? (
<img src={getReactionImage(reaction)} alt={reaction} className="h-6 w-6" /> <img src={getReactionImage(reaction)} alt={reaction} className="h-5 w-5" />
) : ( ) : (
<ReactionIcon className="h-5 w-5 group-hover:text-red-400" /> <ReactionIcon className="h-5 w-5 group-hover:text-blue-500" />
)} )}
</button> </button>
</Popover.Trigger> </Popover.Trigger>
<Popover.Portal> <Popover.Portal>
<Popover.Content <Popover.Content
className="select-none rounded-md bg-black px-1 py-1 text-sm will-change-[transform,opacity] data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=top]:animate-slideDownAndFade" className="select-none rounded-md bg-neutral-200 px-1 py-1 text-sm will-change-[transform,opacity] data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=top]:animate-slideDownAndFade dark:bg-neutral-800"
sideOffset={0} sideOffset={0}
side="top" side="top"
> >
@ -122,7 +122,7 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
<img src="/clown_face.png" alt="Clown Face" className="h-6 w-6" /> <img src="/clown_face.png" alt="Clown Face" className="h-6 w-6" />
</button> </button>
</div> </div>
<Popover.Arrow className="fill-black" /> <Popover.Arrow className="fill-neutral-200 dark:fill-neutral-800" />
</Popover.Content> </Popover.Content>
</Popover.Portal> </Popover.Portal>
</Popover.Root> </Popover.Root>

View File

@ -23,13 +23,13 @@ export function NoteReply({
onClick={() => setReply(id, pubkey, root)} onClick={() => setReply(id, pubkey, root)}
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300" className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
> >
<ReplyIcon className="h-5 w-5 group-hover:text-green-500" /> <ReplyIcon className="h-5 w-5 group-hover:text-blue-500" />
</button> </button>
</Tooltip.Trigger> </Tooltip.Trigger>
<Tooltip.Portal> <Tooltip.Portal>
<Tooltip.Content className="-left-10 select-none rounded-md bg-black px-3.5 py-1.5 text-sm leading-none text-white will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade"> <Tooltip.Content className="-left-10 inline-flex h-7 select-none items-center justify-center rounded-md bg-neutral-200 px-3.5 text-sm text-neutral-900 will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade dark:bg-neutral-800 dark:text-neutral-100">
Quick reply Quick reply
<Tooltip.Arrow className="fill-black" /> <Tooltip.Arrow className="fill-neutral-200 dark:fill-neutral-800" />
</Tooltip.Content> </Tooltip.Content>
</Tooltip.Portal> </Tooltip.Portal>
</Tooltip.Root> </Tooltip.Root>

View File

@ -48,7 +48,7 @@ export function NoteRepost({ id, pubkey }: { id: string; pubkey: string }) {
> >
<RepostIcon <RepostIcon
className={twMerge( className={twMerge(
'h-5 w-5 group-hover:text-blue-500', 'h-5 w-5 group-hover:text-blue-600',
isRepost ? 'text-blue-500' : '' isRepost ? 'text-blue-500' : ''
)} )}
/> />
@ -56,9 +56,9 @@ export function NoteRepost({ id, pubkey }: { id: string; pubkey: string }) {
</AlertDialog.Trigger> </AlertDialog.Trigger>
</Tooltip.Trigger> </Tooltip.Trigger>
<Tooltip.Portal> <Tooltip.Portal>
<Tooltip.Content className="-left-10 select-none rounded-md bg-black px-3.5 py-1.5 text-sm leading-none text-white will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade"> <Tooltip.Content className="-left-10 inline-flex h-7 select-none items-center justify-center rounded-md bg-neutral-200 px-3.5 text-sm text-neutral-900 will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade dark:bg-neutral-800 dark:text-neutral-100">
Repost Repost
<Tooltip.Arrow className="fill-black" /> <Tooltip.Arrow className="fill-neutral-200 dark:fill-neutral-800" />
</Tooltip.Content> </Tooltip.Content>
</Tooltip.Portal> </Tooltip.Portal>
</Tooltip.Root> </Tooltip.Root>

View File

@ -95,7 +95,7 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
type="button" type="button"
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300" className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
> >
<ZapIcon className="h-5 w-5 group-hover:text-orange-400" /> <ZapIcon className="h-5 w-5 group-hover:text-blue-500" />
</button> </button>
</Dialog.Trigger> </Dialog.Trigger>
<Dialog.Portal> <Dialog.Portal>

View File

@ -56,7 +56,7 @@ export function ChildNote({ id, root }: { id: string; root?: string }) {
Lume <span className="text-green-500">(System)</span> Lume <span className="text-green-500">(System)</span>
</h5> </h5>
</div> </div>
<div className="-mt-5 flex items-start gap-3"> <div className="-mt-3 flex items-start gap-3">
<div className="w-10 shrink-0" /> <div className="w-10 shrink-0" />
<div> <div>
<div className="relative z-20 mt-1 flex-1 select-text"> <div className="relative z-20 mt-1 flex-1 select-text">
@ -81,7 +81,7 @@ export function ChildNote({ id, root }: { id: string; root?: string }) {
<div className="absolute bottom-0 left-[18px] h-[calc(100%-3.6rem)] w-0.5 bg-gradient-to-t from-black/20 to-black/10 dark:from-white/20 dark:to-white/10" /> <div className="absolute bottom-0 left-[18px] h-[calc(100%-3.6rem)] w-0.5 bg-gradient-to-t from-black/20 to-black/10 dark:from-white/20 dark:to-white/10" />
<div className="mb-6 flex flex-col"> <div className="mb-6 flex flex-col">
<User pubkey={data.pubkey} time={data.created_at} /> <User pubkey={data.pubkey} time={data.created_at} />
<div className="-mt-4 flex items-start gap-3"> <div className="-mt-3 flex items-start gap-3">
<div className="w-10 shrink-0" /> <div className="w-10 shrink-0" />
<div className="relative z-20 flex-1"> <div className="relative z-20 flex-1">
{renderKind(data)} {renderKind(data)}

View File

@ -1,5 +1,5 @@
import { NDKEvent } from '@nostr-dev-kit/ndk'; import { NDKEvent } from '@nostr-dev-kit/ndk';
import { useMemo } from 'react'; import { memo, useMemo } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Image } from '@shared/image'; import { Image } from '@shared/image';
@ -54,3 +54,5 @@ export function ArticleNote(props: { event?: NDKEvent }) {
</Link> </Link>
); );
} }
export const MemoizedArticleNote = memo(ArticleNote);

View File

@ -5,6 +5,7 @@ import {
DefaultVideoLayout, DefaultVideoLayout,
defaultLayoutIcons, defaultLayoutIcons,
} from '@vidstack/react/player/layouts/default'; } from '@vidstack/react/player/layouts/default';
import { memo } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Image } from '@shared/image'; import { Image } from '@shared/image';
@ -34,13 +35,19 @@ export function FileNote(props: { event?: NDKEvent }) {
key={url} key={url}
src={url} src={url}
poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`} poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
load="visible" load="idle"
aspectRatio="16/9" aspectRatio="16/9"
muted={true} muted={true}
crossorigin="" crossorigin=""
className="player" className="player"
> >
<MediaProvider /> <MediaProvider>
<Poster
className="vds-poster"
src={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
alt="poster"
/>
</MediaProvider>
<DefaultAudioLayout <DefaultAudioLayout
icons={defaultLayoutIcons} icons={defaultLayoutIcons}
smallLayoutWhen="(width < 500) or (height < 380)" smallLayoutWhen="(width < 500) or (height < 380)"
@ -61,10 +68,12 @@ export function FileNote(props: { event?: NDKEvent }) {
<Link <Link
to={url} to={url}
target="_blank" target="_blank"
className="break-all font-normal text-blue-500 hover:text-blue-500" className="break-all font-normal text-blue-500 hover:text-blue-600"
> >
{url} {url}
</Link> </Link>
</div> </div>
); );
} }
export const MemoizedFileNote = memo(FileNote);

View File

@ -1,7 +1,7 @@
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk'; import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { nip19 } from 'nostr-tools'; import { nip19 } from 'nostr-tools';
import { useCallback } from 'react'; import { memo, useCallback } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
@ -71,7 +71,7 @@ export function Repost({
<User pubkey={event.pubkey} time={event.created_at} variant="repost" /> <User pubkey={event.pubkey} time={event.created_at} variant="repost" />
<div className="relative flex flex-col"> <div className="relative flex flex-col">
<User pubkey={embedEvent.pubkey} time={embedEvent.created_at} /> <User pubkey={embedEvent.pubkey} time={embedEvent.created_at} />
<div className="-mt-4 flex items-start gap-3"> <div className="-mt-3 flex items-start gap-3">
<div className="w-10 shrink-0" /> <div className="w-10 shrink-0" />
<div className="relative z-20 flex-1"> <div className="relative z-20 flex-1">
{renderKind(embedEvent)} {renderKind(embedEvent)}
@ -116,7 +116,7 @@ export function Repost({
Lume <span className="text-green-500">(System)</span> Lume <span className="text-green-500">(System)</span>
</h5> </h5>
</div> </div>
<div className="-mt-4 flex items-start gap-3"> <div className="-mt-3 flex items-start gap-3">
<div className="w-11 shrink-0" /> <div className="w-11 shrink-0" />
<div> <div>
<div className="relative z-20 mt-1 flex-1 select-text"> <div className="relative z-20 mt-1 flex-1 select-text">
@ -148,7 +148,7 @@ export function Repost({
<User pubkey={event.pubkey} time={event.created_at} variant="repost" /> <User pubkey={event.pubkey} time={event.created_at} variant="repost" />
<div className="relative flex flex-col"> <div className="relative flex flex-col">
<User pubkey={data.pubkey} time={data.created_at} /> <User pubkey={data.pubkey} time={data.created_at} />
<div className="-mt-4 flex items-start gap-3"> <div className="-mt-3 flex items-start gap-3">
<div className="w-10 shrink-0" /> <div className="w-10 shrink-0" />
<div className="relative z-20 flex-1"> <div className="relative z-20 flex-1">
{renderKind(data)} {renderKind(data)}
@ -160,3 +160,5 @@ export function Repost({
</div> </div>
); );
} }
export const MemoizedRepost = memo(Repost);

View File

@ -1,3 +1,4 @@
import { memo } from 'react';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import remarkGfm from 'remark-gfm'; import remarkGfm from 'remark-gfm';
@ -82,3 +83,5 @@ export function TextNote(props: { content?: string }) {
</div> </div>
); );
} }
export const MemoizedTextNote = memo(TextNote);

View File

@ -2,7 +2,7 @@ import { NDKEvent } from '@nostr-dev-kit/ndk';
export function UnknownNote(props: { event?: NDKEvent }) { export function UnknownNote(props: { event?: NDKEvent }) {
return ( return (
<div className="mt-2 flex w-full flex-col gap-2"> <div className="flex w-full flex-col gap-2">
<div className="inline-flex flex-col rounded-md bg-neutral-200 px-2 py-2 dark:bg-neutral-800"> <div className="inline-flex flex-col rounded-md bg-neutral-200 px-2 py-2 dark:bg-neutral-800">
<span className="text-sm font-medium text-neutral-500 dark:text-neutral-400"> <span className="text-sm font-medium text-neutral-500 dark:text-neutral-400">
Kind: {props.event.kind} Kind: {props.event.kind}
@ -11,7 +11,7 @@ export function UnknownNote(props: { event?: NDKEvent }) {
Unsupport kind on newsfeed Unsupport kind on newsfeed
</p> </p>
</div> </div>
<div className="select-text whitespace-pre-line break-all text-neutral-800 dark:text-neutral-200"> <div className="select-text whitespace-pre-line break-words text-neutral-800 dark:text-neutral-200">
<p>{props.event.content.toString()}</p> <p>{props.event.content.toString()}</p>
</div> </div>
</div> </div>

View File

@ -1,3 +1,3 @@
export function Boost({ boost }: { boost: string }) { export function Boost({ boost }: { boost: string }) {
return <span className="break-words text-blue-400 hover:text-blue-500">{boost}</span>; return <span className="break-words text-blue-400 hover:text-blue-600">{boost}</span>;
} }

View File

@ -24,7 +24,7 @@ export function Hashtag({ tag }: { tag: string }) {
content: tag.replace('#', ''), content: tag.replace('#', ''),
}) })
} }
className="break-all text-blue-500 hover:text-blue-500" className="cursor-default break-all text-blue-500 hover:text-blue-600"
> >
{tag} {tag}
</span> </span>

View File

@ -1,9 +1,10 @@
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { memo } from 'react';
export function Invoice({ invoice }: { invoice: string }) { export const Invoice = memo(function Invoice({ invoice }: { invoice: string }) {
return ( return (
<div className="mt-2 flex items-center rounded-lg bg-neutral-200 p-2 dark:bg-neutral-800"> <span className="mt-2 flex items-center rounded-lg bg-neutral-200 p-2 dark:bg-neutral-800">
<QRCodeSVG value={invoice} includeMargin={true} className="rounded-lg" /> <QRCodeSVG value={invoice} includeMargin={true} className="rounded-lg" />
</div> </span>
); );
} });

View File

@ -30,7 +30,7 @@ export const MentionUser = memo(function MentionUser({ pubkey }: { pubkey: strin
content: pubkey, content: pubkey,
}) })
} }
className="break-words text-blue-500 hover:text-blue-500" className="break-words text-blue-500 hover:text-blue-600"
> >
{'@' + {'@' +
(user?.name || (user?.name ||

View File

@ -11,30 +11,25 @@ export function ImagePreview({ urls, truncate }: { urls: string[]; truncate?: bo
}; };
return ( return (
<div className="mt-3 overflow-hidden"> <div className="flex flex-col gap-2">
<div className="flex flex-col gap-2"> {urls.map((url) => (
{urls.map((url) => ( <div key={url} className="group relative min-w-0 shrink-0 grow-0 basis-full">
<div key={url} className="group relative min-w-0 shrink-0 grow-0 basis-full"> <img
<img src={url}
src={url} alt="image"
alt="image" className={`${
className={`${ truncate ? 'h-auto max-h-[300px]' : 'h-auto'
truncate ? 'h-auto max-h-[300px]' : 'h-auto' } w-full rounded-lg border border-white/10 object-cover`}
} w-full rounded-lg border border-white/10 object-cover`} />
loading="lazy" <button
decoding="async" type="button"
style={{ contentVisibility: 'auto' }} onClick={() => downloadImage(url)}
/> className="absolute right-2 top-2 hidden h-8 w-8 items-center justify-center rounded-md bg-black/50 backdrop-blur-md group-hover:inline-flex hover:bg-black/40"
<button >
type="button" <DownloadIcon className="h-5 w-5 text-white" />
onClick={() => downloadImage(url)} </button>
className="absolute right-2 top-2 hidden h-8 w-8 items-center justify-center rounded-md bg-black/50 backdrop-blur-md hover:bg-black/40 group-hover:inline-flex" </div>
> ))}
<DownloadIcon className="h-5 w-5 text-white" />
</button>
</div>
))}
</div>
</div> </div>
); );
} }

View File

@ -7,7 +7,7 @@ export function LinkPreview({ urls }: { urls: string[] }) {
const domain = new URL(urls[0]); const domain = new URL(urls[0]);
return ( return (
<div className="mt-3 overflow-hidden rounded-lg bg-white/10 backdrop-blur-xl"> <div className="rounded-lg bg-neutral-200 dark:bg-neutral-800">
{status === 'loading' ? ( {status === 'loading' ? (
<div className="flex flex-col"> <div className="flex flex-col">
<div className="h-44 w-full animate-pulse bg-white/10 backdrop-blur-xl" /> <div className="h-44 w-full animate-pulse bg-white/10 backdrop-blur-xl" />

View File

@ -4,21 +4,29 @@ import {
DefaultVideoLayout, DefaultVideoLayout,
defaultLayoutIcons, defaultLayoutIcons,
} from '@vidstack/react/player/layouts/default'; } from '@vidstack/react/player/layouts/default';
import { memo } from 'react';
export function VideoPreview({ urls }: { urls: string[] }) { export const VideoPreview = memo(function VideoPreview({ urls }: { urls: string[] }) {
return ( return (
<div className="relative mt-3 flex w-full flex-col gap-2"> <div className="flex flex-col gap-2">
{urls.map((url) => ( {urls.map((url) => (
<MediaPlayer <MediaPlayer
key={url} key={url}
src={url} src={url}
load="visible" poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
load="idle"
aspectRatio="16/9" aspectRatio="16/9"
crossorigin="" crossorigin=""
muted={true} muted={true}
className="player" className="player"
> >
<MediaProvider /> <MediaProvider>
<Poster
className="vds-poster"
src={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
alt="poster"
/>
</MediaProvider>
<DefaultAudioLayout <DefaultAudioLayout
icons={defaultLayoutIcons} icons={defaultLayoutIcons}
smallLayoutWhen="(width < 500) or (height < 380)" smallLayoutWhen="(width < 500) or (height < 380)"
@ -33,4 +41,4 @@ export function VideoPreview({ urls }: { urls: string[] }) {
))} ))}
</div> </div>
); );
} });

View File

@ -31,7 +31,7 @@ export function NoteWrapper({
<div className="relative">{reply && <ChildNote id={reply} root={root} />}</div> <div className="relative">{reply && <ChildNote id={reply} root={root} />}</div>
<div className="relative flex flex-col"> <div className="relative flex flex-col">
<User pubkey={event.pubkey} time={event.created_at} /> <User pubkey={event.pubkey} time={event.created_at} />
<div className="-mt-4 flex items-start gap-3"> <div className="-mt-3 flex items-start gap-3">
<div className="w-10 shrink-0" /> <div className="w-10 shrink-0" />
<div className="relative z-20 flex-1"> <div className="relative z-20 flex-1">
{cloneElement( {cloneElement(

View File

@ -229,7 +229,7 @@ export const User = memo(function User({
return ( return (
<div className="flex gap-3"> <div className="flex gap-3">
<div className="inline-flex h-10 w-10 items-center justify-center"> <div className="inline-flex h-10 w-10 items-center justify-center">
<RepostIcon className="h-6 w-6 text-blue-500" /> <RepostIcon className="h-5 w-5 text-blue-500" />
</div> </div>
<div className="inline-flex items-center gap-2"> <div className="inline-flex items-center gap-2">
<Avatar.Root className="shrink-0"> <Avatar.Root className="shrink-0">
@ -308,7 +308,7 @@ export const User = memo(function User({
loading="lazy" loading="lazy"
decoding="async" decoding="async"
style={{ contentVisibility: 'auto' }} style={{ contentVisibility: 'auto' }}
className="h-10 w-10 rounded-lg border border-white/5 object-cover" className="h-10 w-10 rounded-lg object-cover"
/> />
<Avatar.Fallback delayMs={300}> <Avatar.Fallback delayMs={300}>
<img <img
@ -320,14 +320,15 @@ export const User = memo(function User({
</Avatar.Root> </Avatar.Root>
</HoverCard.Trigger> </HoverCard.Trigger>
<div className="flex flex-1 items-center gap-2"> <div className="flex flex-1 items-center gap-2">
<h5 className="max-w-[15rem] truncate font-semibold text-neutral-900 dark:text-neutral-100"> <div className="max-w-[15rem] truncate font-semibold text-neutral-950 dark:text-neutral-50">
{user?.name || {user?.name ||
user?.display_name || user?.display_name ||
user?.displayName || user?.displayName ||
displayNpub(pubkey, 16)} displayNpub(pubkey, 16)}
</h5> </div>
<span className="text-neutral-500 dark:text-neutral-300">·</span> <div className="ml-auto text-neutral-500 dark:text-neutral-400">
<span className="text-neutral-500 dark:text-neutral-300">{createdAt}</span> {createdAt}
</div>
</div> </div>
</div> </div>
<HoverCard.Portal> <HoverCard.Portal>

View File

@ -7,11 +7,11 @@ import { useStorage } from '@libs/storage/provider';
import { ArrowRightCircleIcon, LoaderIcon } from '@shared/icons'; import { ArrowRightCircleIcon, LoaderIcon } from '@shared/icons';
import { import {
ArticleNote, MemoizedArticleNote,
FileNote, MemoizedFileNote,
MemoizedRepost,
MemoizedTextNote,
NoteWrapper, NoteWrapper,
Repost,
TextNote,
UnknownNote, UnknownNote,
} from '@shared/notes'; } from '@shared/notes';
import { TitleBar } from '@shared/titleBar'; import { TitleBar } from '@shared/titleBar';
@ -48,21 +48,21 @@ export function LocalFollowsWidget({ params }: { params: Widget }) {
root={dbEvent.root_id} root={dbEvent.root_id}
reply={dbEvent.reply_id} reply={dbEvent.reply_id}
> >
<TextNote /> <MemoizedTextNote />
</NoteWrapper> </NoteWrapper>
); );
case NDKKind.Repost: case NDKKind.Repost:
return <Repost key={dbEvent.id} event={event} />; return <MemoizedRepost key={dbEvent.id} event={event} />;
case 1063: case 1063:
return ( return (
<NoteWrapper key={dbEvent.id} event={event}> <NoteWrapper key={dbEvent.id} event={event}>
<FileNote /> <MemoizedFileNote />
</NoteWrapper> </NoteWrapper>
); );
case NDKKind.Article: case NDKKind.Article:
return ( return (
<NoteWrapper key={dbEvent.id} event={event}> <NoteWrapper key={dbEvent.id} event={event}>
<ArticleNote /> <MemoizedArticleNote />
</NoteWrapper> </NoteWrapper>
); );
default: default:

View File

@ -7,11 +7,11 @@ import { useStorage } from '@libs/storage/provider';
import { ArrowRightCircleIcon, LoaderIcon } from '@shared/icons'; import { ArrowRightCircleIcon, LoaderIcon } from '@shared/icons';
import { import {
ArticleNote, MemoizedArticleNote,
FileNote, MemoizedFileNote,
MemoizedRepost,
MemoizedTextNote,
NoteWrapper, NoteWrapper,
Repost,
TextNote,
UnknownNote, UnknownNote,
} from '@shared/notes'; } from '@shared/notes';
import { NoteSkeleton } from '@shared/notes/skeleton'; import { NoteSkeleton } from '@shared/notes/skeleton';
@ -55,21 +55,21 @@ export function LocalNetworkWidget() {
root={dbEvent.root_id} root={dbEvent.root_id}
reply={dbEvent.reply_id} reply={dbEvent.reply_id}
> >
<TextNote /> <MemoizedTextNote />
</NoteWrapper> </NoteWrapper>
); );
case NDKKind.Repost: case NDKKind.Repost:
return <Repost key={dbEvent.id} event={event} />; return <MemoizedRepost key={dbEvent.id} event={event} />;
case 1063: case 1063:
return ( return (
<NoteWrapper key={dbEvent.id} event={event}> <NoteWrapper key={dbEvent.id} event={event}>
<FileNote /> <MemoizedFileNote />
</NoteWrapper> </NoteWrapper>
); );
case NDKKind.Article: case NDKKind.Article:
return ( return (
<NoteWrapper key={dbEvent.id} event={event}> <NoteWrapper key={dbEvent.id} event={event}>
<ArticleNote /> <MemoizedArticleNote />
</NoteWrapper> </NoteWrapper>
); );
default: default:

View File

@ -4,12 +4,12 @@ import { useCallback } from 'react';
import { useStorage } from '@libs/storage/provider'; import { useStorage } from '@libs/storage/provider';
import { import {
ArticleNote, MemoizedArticleNote,
FileNote, MemoizedFileNote,
MemoizedTextNote,
NoteActions, NoteActions,
NoteReplyForm, NoteReplyForm,
NoteStats, NoteStats,
TextNote,
UnknownNote, UnknownNote,
} from '@shared/notes'; } from '@shared/notes';
import { RepliesList } from '@shared/notes/replies/list'; import { RepliesList } from '@shared/notes/replies/list';
@ -29,11 +29,11 @@ export function LocalThreadWidget({ params }: { params: Widget }) {
(event: NDKEvent) => { (event: NDKEvent) => {
switch (event.kind) { switch (event.kind) {
case NDKKind.Text: case NDKKind.Text:
return <TextNote content={event.content} />; return <MemoizedTextNote content={event.content} />;
case NDKKind.Article: case NDKKind.Article:
return <ArticleNote event={event} />; return <MemoizedArticleNote event={event} />;
case 1063: case 1063:
return <FileNote event={event} />; return <MemoizedFileNote event={event} />;
default: default:
return <UnknownNote event={event} />; return <UnknownNote event={event} />;
} }

View File

@ -13,15 +13,15 @@ export function WidgetWrapper({
return ( return (
<Resizable <Resizable
size={{ width: width, height: '100vh' }} size={{ width: width, height: '100%' }}
onResizeStart={(e) => e.preventDefault()} onResizeStart={(e) => e.preventDefault()}
onResizeStop={(_e, _direction, _ref, d) => { onResizeStop={(_e, _direction, _ref, d) => {
setWidth((prevWidth) => prevWidth + d.width); setWidth((prevWidth) => prevWidth + d.width);
}} }}
minWidth={420} minWidth={420}
minHeight={'100vh'} maxWidth={600}
className={twMerge( className={twMerge(
'h-full border-r border-neutral-100 pb-10 dark:border-neutral-900', 'flex flex-col border-r border-neutral-100 dark:border-neutral-900',
className className
)} )}
enable={{ right: true }} enable={{ right: true }}

View File

@ -1,9 +1,10 @@
import react from '@vitejs/plugin-react-swc'; import react from '@vitejs/plugin-react-swc';
import million from 'million/compiler';
import { defineConfig } from 'vite'; import { defineConfig } from 'vite';
import viteTsconfigPaths from 'vite-tsconfig-paths'; import viteTsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig({ export default defineConfig({
plugins: [react(), viteTsconfigPaths()], plugins: [million.vite({ auto: true }), react(), viteTsconfigPaths()],
envPrefix: ['VITE_', 'TAURI_'], envPrefix: ['VITE_', 'TAURI_'],
build: { build: {
target: process.env.TAURI_PLATFORM === 'windows' ? 'chrome105' : 'safari13', target: process.env.TAURI_PLATFORM === 'windows' ? 'chrome105' : 'safari13',