mirror of
https://github.com/lumehq/lume.git
synced 2025-03-18 05:41:53 +01:00
wip
This commit is contained in:
parent
3b46e71525
commit
35650a40f2
14
package.json
14
package.json
@ -47,13 +47,13 @@
|
||||
"@tauri-apps/plugin-updater": "2.0.0-alpha.1",
|
||||
"@tauri-apps/plugin-upload": "2.0.0-alpha.1",
|
||||
"@tauri-apps/plugin-window": "2.0.0-alpha.1",
|
||||
"@tiptap/extension-image": "^2.1.11",
|
||||
"@tiptap/extension-mention": "^2.1.11",
|
||||
"@tiptap/extension-placeholder": "^2.1.11",
|
||||
"@tiptap/pm": "^2.1.11",
|
||||
"@tiptap/react": "^2.1.11",
|
||||
"@tiptap/starter-kit": "^2.1.11",
|
||||
"@tiptap/suggestion": "^2.1.11",
|
||||
"@tiptap/extension-image": "^2.1.12",
|
||||
"@tiptap/extension-mention": "^2.1.12",
|
||||
"@tiptap/extension-placeholder": "^2.1.12",
|
||||
"@tiptap/pm": "^2.1.12",
|
||||
"@tiptap/react": "^2.1.12",
|
||||
"@tiptap/starter-kit": "^2.1.12",
|
||||
"@tiptap/suggestion": "^2.1.12",
|
||||
"dayjs": "^1.11.10",
|
||||
"destr": "^2.0.1",
|
||||
"html-to-text": "^9.0.5",
|
||||
|
380
pnpm-lock.yaml
generated
380
pnpm-lock.yaml
generated
@ -93,26 +93,26 @@ dependencies:
|
||||
specifier: 2.0.0-alpha.1
|
||||
version: 2.0.0-alpha.1
|
||||
'@tiptap/extension-image':
|
||||
specifier: ^2.1.11
|
||||
version: 2.1.11(@tiptap/core@2.1.11)
|
||||
specifier: ^2.1.12
|
||||
version: 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-mention':
|
||||
specifier: ^2.1.11
|
||||
version: 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)(@tiptap/suggestion@2.1.11)
|
||||
specifier: ^2.1.12
|
||||
version: 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)(@tiptap/suggestion@2.1.12)
|
||||
'@tiptap/extension-placeholder':
|
||||
specifier: ^2.1.11
|
||||
version: 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
||||
specifier: ^2.1.12
|
||||
version: 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm':
|
||||
specifier: ^2.1.11
|
||||
version: 2.1.11
|
||||
specifier: ^2.1.12
|
||||
version: 2.1.12
|
||||
'@tiptap/react':
|
||||
specifier: ^2.1.11
|
||||
version: 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)(react-dom@18.2.0)(react@18.2.0)
|
||||
specifier: ^2.1.12
|
||||
version: 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@tiptap/starter-kit':
|
||||
specifier: ^2.1.11
|
||||
version: 2.1.11(@tiptap/pm@2.1.11)
|
||||
specifier: ^2.1.12
|
||||
version: 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/suggestion':
|
||||
specifier: ^2.1.11
|
||||
version: 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
||||
specifier: ^2.1.12
|
||||
version: 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
|
||||
dayjs:
|
||||
specifier: ^1.11.10
|
||||
version: 1.11.10
|
||||
@ -313,24 +313,24 @@ packages:
|
||||
'@babel/highlight': 7.22.20
|
||||
chalk: 2.4.2
|
||||
|
||||
/@babel/compat-data@7.22.20:
|
||||
resolution: {integrity: sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==}
|
||||
/@babel/compat-data@7.23.2:
|
||||
resolution: {integrity: sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: false
|
||||
|
||||
/@babel/core@7.23.0:
|
||||
resolution: {integrity: sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==}
|
||||
/@babel/core@7.23.2:
|
||||
resolution: {integrity: sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==}
|
||||
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/helper-module-transforms': 7.23.0(@babel/core@7.23.2)
|
||||
'@babel/helpers': 7.23.2
|
||||
'@babel/parser': 7.23.0
|
||||
'@babel/template': 7.22.15
|
||||
'@babel/traverse': 7.23.0
|
||||
'@babel/traverse': 7.23.2
|
||||
'@babel/types': 7.23.0
|
||||
convert-source-map: 2.0.0
|
||||
debug: 4.3.4
|
||||
@ -364,7 +364,7 @@ packages:
|
||||
resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/compat-data': 7.22.20
|
||||
'@babel/compat-data': 7.23.2
|
||||
'@babel/helper-validator-option': 7.22.15
|
||||
browserslist: 4.22.1
|
||||
lru-cache: 5.1.1
|
||||
@ -395,13 +395,13 @@ packages:
|
||||
'@babel/types': 7.23.0
|
||||
dev: false
|
||||
|
||||
/@babel/helper-module-transforms@7.23.0(@babel/core@7.23.0):
|
||||
/@babel/helper-module-transforms@7.23.0(@babel/core@7.23.2):
|
||||
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/core': 7.23.2
|
||||
'@babel/helper-environment-visitor': 7.22.20
|
||||
'@babel/helper-module-imports': 7.22.15
|
||||
'@babel/helper-simple-access': 7.22.5
|
||||
@ -440,12 +440,12 @@ packages:
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: false
|
||||
|
||||
/@babel/helpers@7.23.1:
|
||||
resolution: {integrity: sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==}
|
||||
/@babel/helpers@7.23.2:
|
||||
resolution: {integrity: sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/template': 7.22.15
|
||||
'@babel/traverse': 7.23.0
|
||||
'@babel/traverse': 7.23.2
|
||||
'@babel/types': 7.23.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@ -466,28 +466,28 @@ packages:
|
||||
dependencies:
|
||||
'@babel/types': 7.17.0
|
||||
|
||||
/@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.23.0):
|
||||
/@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.23.2):
|
||||
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/core': 7.23.2
|
||||
'@babel/helper-plugin-utils': 7.22.5
|
||||
dev: false
|
||||
|
||||
/@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.23.0):
|
||||
/@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.23.2):
|
||||
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/core': 7.23.2
|
||||
'@babel/helper-plugin-utils': 7.22.5
|
||||
dev: false
|
||||
|
||||
/@babel/runtime@7.23.1:
|
||||
resolution: {integrity: sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==}
|
||||
/@babel/runtime@7.23.2:
|
||||
resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
regenerator-runtime: 0.14.0
|
||||
@ -518,8 +518,8 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@babel/traverse@7.23.0:
|
||||
resolution: {integrity: sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==}
|
||||
/@babel/traverse@7.23.2:
|
||||
resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.22.13
|
||||
@ -984,7 +984,7 @@ packages:
|
||||
/@radix-ui/primitive@1.0.1:
|
||||
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-alert-dialog@1.0.5(@types/react-dom@18.2.13)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0):
|
||||
@ -1000,7 +1000,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1026,7 +1026,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@types/react': 18.2.28
|
||||
'@types/react-dom': 18.2.13
|
||||
@ -1047,7 +1047,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1071,7 +1071,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1099,7 +1099,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0)
|
||||
@ -1119,7 +1119,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
@ -1133,7 +1133,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
@ -1151,7 +1151,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1181,7 +1181,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
@ -1199,7 +1199,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0)
|
||||
@ -1224,7 +1224,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1247,7 +1247,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
@ -1265,7 +1265,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1288,7 +1288,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1313,7 +1313,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
@ -1332,7 +1332,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1370,7 +1370,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1405,7 +1405,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@floating-ui/react-dom': 2.0.2(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1435,7 +1435,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@types/react': 18.2.28
|
||||
'@types/react-dom': 18.2.13
|
||||
@ -1456,7 +1456,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@types/react': 18.2.28
|
||||
@ -1478,7 +1478,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.28)(react@18.2.0)
|
||||
'@types/react': 18.2.28
|
||||
'@types/react-dom': 18.2.13
|
||||
@ -1499,7 +1499,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1524,7 +1524,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
@ -1543,7 +1543,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
@ -1571,7 +1571,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
@ -1585,7 +1585,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
@ -1600,7 +1600,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
@ -1615,7 +1615,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
@ -1629,7 +1629,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/rect': 1.0.1
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
@ -1644,7 +1644,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.28)(react@18.2.0)
|
||||
'@types/react': 18.2.28
|
||||
react: 18.2.0
|
||||
@ -1663,7 +1663,7 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.13)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@types/react': 18.2.28
|
||||
'@types/react-dom': 18.2.13
|
||||
@ -1674,7 +1674,7 @@ packages:
|
||||
/@radix-ui/rect@1.0.1:
|
||||
resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
dev: false
|
||||
|
||||
/@reactflow/background@11.3.3(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0):
|
||||
@ -2200,222 +2200,222 @@ packages:
|
||||
'@tauri-apps/api': 2.0.0-alpha.6
|
||||
dev: false
|
||||
|
||||
/@tiptap/core@2.1.11(@tiptap/pm@2.1.11):
|
||||
resolution: {integrity: sha512-1W2DdjpPwfphHgQ3Qm4s5wzCnEjiXm1TeZ+6/zBl89yKURXgv8Mw1JGdj/NcImQjtDcsNn97MscACK3GKbEJBA==}
|
||||
/@tiptap/core@2.1.12(@tiptap/pm@2.1.12):
|
||||
resolution: {integrity: sha512-ZGc3xrBJA9KY8kln5AYTj8y+GDrKxi7u95xIl2eccrqTY5CQeRu6HRNM1yT4mAjuSaG9jmazyjGRlQuhyxCKxQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/pm': 2.1.12
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-blockquote@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-IEVe3goA0rgp1G8Wm733BSRJiy71Vh2fmTCyZKWmc2A6GREVSy1X3fCvAo6pMENRObhjIoaBQUCE3p4iJYOxqg==}
|
||||
/@tiptap/extension-blockquote@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-Qb3YRlCfugx9pw7VgLTb+jY37OY4aBJeZnqHzx4QThSm13edNYjasokbX0nTwL1Up4NPTcY19JUeHt6fVaVVGg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-bold@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-vhdkBtvd029ufOYt2ug49Gz+RLKSczO/CCqKYBqBmpIpsifyK7M6jkgamvAQg3c/vYk0LNcKiL2dp0Jp7L+5Gw==}
|
||||
/@tiptap/extension-bold@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-AZGxIxcGU1/y6V2YEbKsq6BAibL8yQrbRm6EdcBnby41vj1WziewEKswhLGmZx5IKM2r2ldxld03KlfSIlKQZg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-bubble-menu@2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11):
|
||||
resolution: {integrity: sha512-WFJJpZvl9DP94Y5RQZB/THDxvDbrTo8tuhjT7yWlhseJ6zyhWmRXdutt39wfSZNFxitv/As+s7cO9aYLML/TVg==}
|
||||
/@tiptap/extension-bubble-menu@2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12):
|
||||
resolution: {integrity: sha512-gAGi21EQ4wvLmT7klgariAc2Hf+cIjaNU2NWze3ut6Ku9gUo5ZLqj1t9SKHmNf4d5JG63O8GxpErqpA7lHlRtw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm': 2.1.12
|
||||
tippy.js: 6.3.7
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-bullet-list@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-SOOVH2aSmdMtjWL7TTLbN72xbAFz2G5jifT4UCXb7Qx6LsyhNCyDCu0ukOW8rSosGoSdmBXxAsD9sBJ1jEOmZw==}
|
||||
/@tiptap/extension-bullet-list@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-vtD8vWtNlmAZX8LYqt2yU9w3mU9rPCiHmbp4hDXJs2kBnI0Ju/qAyXFx6iJ3C3XyuMnMbJdDI9ee0spAvFz7cQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-code-block@2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11):
|
||||
resolution: {integrity: sha512-QhmhCCWqg/5qLXpZ3sl2A0rqJqV8zMOegcxUFaqcJMOqNbsuHcRgc9C+1hWSVLbCmstB7M6sgF02QpTBOkYHxg==}
|
||||
/@tiptap/extension-code-block@2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12):
|
||||
resolution: {integrity: sha512-RXtSYCVsnk8D+K80uNZShClfZjvv1EgO42JlXLVGWQdIgaNyuOv/6I/Jdf+ZzhnpsBnHufW+6TJjwP5vJPSPHA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm': 2.1.12
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-code@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-G0UEbMFunujy/F86yHN0/dumPLbwTis9C+6IQv1XRPNsV28U0MgxBhlPcJUgyO5lwuleePDxiBVcRv2XrysgKw==}
|
||||
/@tiptap/extension-code@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-CRiRq5OTC1lFgSx6IMrECqmtb93a0ZZKujEnaRhzWliPBjLIi66va05f/P1vnV6/tHaC3yfXys6dxB5A4J8jxw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-document@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-L/iLuqxvJep33ycCFNrnUhdR0VtcZyeNnqB+ZvVHzEwLoRud+LBy44lpEdBrAFsvRm3DG14m/FGYL+TfaD0vxA==}
|
||||
/@tiptap/extension-document@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-0QNfAkCcFlB9O8cUNSwTSIQMV9TmoEhfEaLz/GvbjwEq4skXK3bU+OQX7Ih07waCDVXIGAZ7YAZogbvrn/WbOw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-dropcursor@2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11):
|
||||
resolution: {integrity: sha512-MiJepRpHlu93aInOMW8NeRCvm9VE5rL0MA9TONY/IspJFGFIqonc/01J6t33JQa3Xh/x3xAfis4nKa/UazeVJw==}
|
||||
/@tiptap/extension-dropcursor@2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12):
|
||||
resolution: {integrity: sha512-0tT/q8nL4NBCYPxr9T0Brck+RQbWuczm9nV0bnxgt0IiQXoRHutfPWdS7GA65PTuVRBS/3LOco30fbjFhkfz/A==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm': 2.1.12
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-floating-menu@2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11):
|
||||
resolution: {integrity: sha512-ExeoOQ6nT0CY0eWx6WjbG+osurXLXa7XrqIdhCAcTmzBAlGiKt8khX9qaZ+QF+BRK1r1lja2KX+5/fpLK7Dt1g==}
|
||||
/@tiptap/extension-floating-menu@2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12):
|
||||
resolution: {integrity: sha512-uo0ydCJNg6AWwLT6cMUJYVChfvw2PY9ZfvKRhh9YJlGfM02jS4RUG/bJBts6R37f+a5FsOvAVwg8EvqPlNND1A==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm': 2.1.12
|
||||
tippy.js: 6.3.7
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-gapcursor@2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11):
|
||||
resolution: {integrity: sha512-P/xjyhSOVyop5XXbNtRPgrooQrSlpYblwR67ClI9FAC7uQliuOwi5VcndmEItjWWSe85kJa2IHjOS7mLYvJe8A==}
|
||||
/@tiptap/extension-gapcursor@2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12):
|
||||
resolution: {integrity: sha512-zFYdZCqPgpwoB7whyuwpc8EYLYjUE5QYKb8vICvc+FraBUDM51ujYhFSgJC3rhs8EjI+8GcK8ShLbSMIn49YOQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm': 2.1.12
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-hard-break@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-qhiPe6FA0b6PPb/ITlgSnY0l9tEVmXZ9e7eSjvks12ORfqL/dofSCLtChHWvhZxugzo92xejG2hXLi6lyOLbkg==}
|
||||
/@tiptap/extension-hard-break@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-nqKcAYGEOafg9D+2cy1E4gHNGuL12LerVa0eS2SQOb+PT8vSel9OTKU1RyZldsWSQJ5rq/w4uIjmLnrSR2w6Yw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-heading@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-QBtl0S1aDFB+F1wvTrS5iGdNUEeXp+WuTddj+L2f5EP4KqG2x7sj7e7ENMy20g/l8tbKwzd3AZZydvClH4Ybbw==}
|
||||
/@tiptap/extension-heading@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-MoANP3POAP68Ko9YXarfDKLM/kXtscgp6m+xRagPAghRNujVY88nK1qBMZ3JdvTVN6b/ATJhp8UdrZX96TLV2w==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-history@2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11):
|
||||
resolution: {integrity: sha512-88dovV2O9icmBn0IvaArFFeS6X5ts6BxZPu5VbGML8KBL8iAu+Og7RXEPdOy5e13K0K4V21fDpO3n7KdvNOAYQ==}
|
||||
/@tiptap/extension-history@2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12):
|
||||
resolution: {integrity: sha512-6b7UFVkvPjq3LVoCTrYZAczt5sQrQUaoDWAieVClVZoFLfjga2Fwjcfgcie8IjdPt8YO2hG/sar/c07i9vM0Sg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm': 2.1.12
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-horizontal-rule@2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11):
|
||||
resolution: {integrity: sha512-uvHPa2YCKnDhtSBSZB3lk5U4H3wRKP0DNvVx4Y2F7MdQianVzcyOd1pZYO9BQs+lUB1aZots6doE69Zqz3mU2Q==}
|
||||
/@tiptap/extension-horizontal-rule@2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12):
|
||||
resolution: {integrity: sha512-RRuoK4KxrXRrZNAjJW5rpaxjiP0FJIaqpi7nFbAua2oHXgsCsG8qbW2Y0WkbIoS8AJsvLZ3fNGsQ8gpdliuq3A==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm': 2.1.12
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-image@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-dFFRvzl9F4fEcG95nyka72TeV127C1UVaMm816GHoFlVEFGV4yJ8NKgzT3UEDgFcs6OPwPlt8tuHuDeYm7EVOQ==}
|
||||
/@tiptap/extension-image@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-VCgOTeNLuoR89WoCESLverpdZpPamOd7IprQbDIeG14sUySt7RHNgf2AEfyTYJEHij12rduvAwFzerPldVAIJg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-italic@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-QmDsHtnBBit/1KtQpBPxjSPjDC1mVKtoNTgsEwMWK6YAkCKOKPj7oPEqqjaNZIRMKPPzE5XCsfBoS3jtVmo+6A==}
|
||||
/@tiptap/extension-italic@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-/XYrW4ZEWyqDvnXVKbgTXItpJOp2ycswk+fJ3vuexyolO6NSs0UuYC6X4f+FbHYL5VuWqVBv7EavGa+tB6sl3A==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-list-item@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-YhwHaPGhffsFsg/zjCu1G24//j/BTRDRZbZXmMwp77m1yEqPULcWyoWrI+gUzetQxJRD/ruAucqjLtoLLfICmQ==}
|
||||
/@tiptap/extension-list-item@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-Gk7hBFofAPmNQ8+uw8w5QSsZOMEGf7KQXJnx5B022YAUJTYYxO3jYVuzp34Drk9p+zNNIcXD4kc7ff5+nFOTrg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-mention@2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)(@tiptap/suggestion@2.1.11):
|
||||
resolution: {integrity: sha512-QMHmAkhiDQEgAdUHdKRfVna0AINcbSbQCrpgwKLIHGWcpbi1zJbAPpm+xngbl0I9ZNxaMzbP4utTAzeQ92pJkw==}
|
||||
/@tiptap/extension-mention@2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)(@tiptap/suggestion@2.1.12):
|
||||
resolution: {integrity: sha512-Nc8wFlyPp+/48IpOFPk2O3hYsF465wizcM3aihMvZM96Ahic7dvv9yVptyOfoOwgpExl2FIn1QPjRDXF60VAUg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
'@tiptap/suggestion': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/suggestion': 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm': 2.1.12
|
||||
'@tiptap/suggestion': 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-ordered-list@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-/tghfEJ5U7WFbF8xyOqRJks8KxP/lRjnroMXMglaushSMx8PYPo1dZDB/dJZw7ksy47MAaKJfKlx3gyN2CPXBQ==}
|
||||
/@tiptap/extension-ordered-list@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-tF6VGl+D2avCgn9U/2YLJ8qVmV6sPE/iEzVAFZuOSe6L0Pj7SQw4K6AO640QBob/d8VrqqJFHCb6l10amJOnXA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-paragraph@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-gXMgJ2CU3X4yh1wKnb8RdbDmhITB76pH6DX0uWprmEgvzNMN3Qw+h5uBD9lgxg1WVghbCmkG9mY9J4PPbPTLxw==}
|
||||
/@tiptap/extension-paragraph@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-hoH/uWPX+KKnNAZagudlsrr4Xu57nusGekkJWBcrb5MCDE91BS+DN2xifuhwXiTHxnwOMVFjluc0bPzQbkArsw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-placeholder@2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11):
|
||||
resolution: {integrity: sha512-laHYRFxJWj6m72Yf1v6Q5nF2nvwWpQlKUj6Yu/yluOOoVE92HpLqCAvA8RamqLtPiw5VxR3v3oCY0WNeQRvyIg==}
|
||||
/@tiptap/extension-placeholder@2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12):
|
||||
resolution: {integrity: sha512-K52o7B1zkP4vaVy3z4ZwHn+tQy6KlXtedj1skLg+796ImwH2GYS5z6MFOTfKzBO2hLncUzLco/s0C5PLCD6SDw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm': 2.1.12
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-strike@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-UnjeSVgu3bDuyjjUdWsUErRCoQKAHCzH/pAiqTEPEEdFYgZFQPBpcJICRVdlYjRmI2ZKh6d0TMUS55m7ckmwmQ==}
|
||||
/@tiptap/extension-strike@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-HlhrzIjYUT8oCH9nYzEL2QTTn8d1ECnVhKvzAe6x41xk31PjLMHTUy8aYjeQEkWZOWZ34tiTmslV1ce6R3Dt8g==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-text@2.1.11(@tiptap/core@2.1.11):
|
||||
resolution: {integrity: sha512-Iey0EXYv9079+lbHMvZtLc6XcYfKrq++msEXuFFNHxvL0i/XzndhGf+qlDhLROLgEtDiiTqzOBBwFCGlFjbDow==}
|
||||
/@tiptap/extension-text@2.1.12(@tiptap/core@2.1.12):
|
||||
resolution: {integrity: sha512-rCNUd505p/PXwU9Jgxo4ZJv4A3cIBAyAqlx/dtcY6cjztCQuXJhuQILPhjGhBTOLEEL4kW2wQtqzCmb7O8i2jg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
dev: false
|
||||
|
||||
/@tiptap/pm@2.1.11:
|
||||
resolution: {integrity: sha512-vBIAic+H8fjHfT8r2qJkAOxdx1Iiss9+qMyujAoIdPkiyjEc4+sXcM0qSYgIr6KL5icITyuK8J7x/V62VfB7Uw==}
|
||||
/@tiptap/pm@2.1.12:
|
||||
resolution: {integrity: sha512-Q3MXXQABG4CZBesSp82yV84uhJh/W0Gag6KPm2HRWPimSFELM09Z9/5WK9RItAYE0aLhe4Krnyiczn9AAa1tQQ==}
|
||||
dependencies:
|
||||
prosemirror-changeset: 2.2.1
|
||||
prosemirror-collab: 1.3.1
|
||||
@ -2437,56 +2437,56 @@ packages:
|
||||
prosemirror-view: 1.32.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/react@2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-OLU4uqMeCE/LKz/GY2P1JRykUgHJDoPROHUa1IOnVpj/1FbbBHDyurT3eomwsVzScTULbrKGwrS3ada6QAmTTA==}
|
||||
/@tiptap/react@2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-RMO4QmmpL7sPR7w8o1Wq0hrUe/ttHzsn5I/eWwqg1d3fGx5y9mOdfCoQ9XBtm49Xzdejy3QVzt4zYp9fX0X/xg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/extension-bubble-menu': 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
||||
'@tiptap/extension-floating-menu': 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/extension-bubble-menu': 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
|
||||
'@tiptap/extension-floating-menu': 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm': 2.1.12
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/starter-kit@2.1.11(@tiptap/pm@2.1.11):
|
||||
resolution: {integrity: sha512-kZXwuo9yxrs1ASxluRKjXThjdcy90d7owJxnJWD7SyEwXaXYc4h+Ar1M9rP3jieCDBuRTtCgvAOKbVbhnRJ2jg==}
|
||||
/@tiptap/starter-kit@2.1.12(@tiptap/pm@2.1.12):
|
||||
resolution: {integrity: sha512-+RoP1rWV7rSCit2+3wl2bjvSRiePRJE/7YNKbvH8Faz/+AMO23AFegHoUFynR7U0ouGgYDljGkkj35e0asbSDA==}
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/extension-blockquote': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-bold': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-bullet-list': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-code': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-code-block': 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
||||
'@tiptap/extension-document': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-dropcursor': 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
||||
'@tiptap/extension-gapcursor': 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
||||
'@tiptap/extension-hard-break': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-heading': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-history': 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
||||
'@tiptap/extension-horizontal-rule': 2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11)
|
||||
'@tiptap/extension-italic': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-list-item': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-ordered-list': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-paragraph': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-strike': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/extension-text': 2.1.11(@tiptap/core@2.1.11)
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/extension-blockquote': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-bold': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-bullet-list': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-code': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-code-block': 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
|
||||
'@tiptap/extension-document': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-dropcursor': 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
|
||||
'@tiptap/extension-gapcursor': 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
|
||||
'@tiptap/extension-hard-break': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-heading': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-history': 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
|
||||
'@tiptap/extension-horizontal-rule': 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
|
||||
'@tiptap/extension-italic': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-list-item': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-ordered-list': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-paragraph': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-strike': 2.1.12(@tiptap/core@2.1.12)
|
||||
'@tiptap/extension-text': 2.1.12(@tiptap/core@2.1.12)
|
||||
transitivePeerDependencies:
|
||||
- '@tiptap/pm'
|
||||
dev: false
|
||||
|
||||
/@tiptap/suggestion@2.1.11(@tiptap/core@2.1.11)(@tiptap/pm@2.1.11):
|
||||
resolution: {integrity: sha512-AVMB4x1X3eU7QCO1A8URQK0W7ps5dsVzveIP7+c//Z/GYe8lFSGIUnEbLJdr6bwgPkRL56m7c9+oZqVST5wfjQ==}
|
||||
/@tiptap/suggestion@2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12):
|
||||
resolution: {integrity: sha512-rhlLWwVkOodBGRMK0mAmE34l2a+BqM2Y7q1ViuQRBhs/6sZ8d83O4hARHKVwqT5stY4i1l7d7PoemV3uAGI6+g==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.1.11(@tiptap/pm@2.1.11)
|
||||
'@tiptap/pm': 2.1.11
|
||||
'@tiptap/core': 2.1.12(@tiptap/pm@2.1.12)
|
||||
'@tiptap/pm': 2.1.12
|
||||
dev: false
|
||||
|
||||
/@trivago/prettier-plugin-sort-imports@4.2.0(prettier@3.0.3):
|
||||
@ -3135,7 +3135,7 @@ packages:
|
||||
hasBin: true
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001547
|
||||
electron-to-chromium: 1.4.549
|
||||
electron-to-chromium: 1.4.551
|
||||
node-releases: 2.0.13
|
||||
update-browserslist-db: 1.0.13(browserslist@4.22.1)
|
||||
|
||||
@ -3537,8 +3537,8 @@ packages:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
dev: true
|
||||
|
||||
/electron-to-chromium@1.4.549:
|
||||
resolution: {integrity: sha512-gpXfJslSi4hYDkA0mTLEpYKRv9siAgSUgZ+UWyk+J5Cttpd1ThCVwdclzIwQSclz3hYn049+M2fgrP1WpvF8xg==}
|
||||
/electron-to-chromium@1.4.551:
|
||||
resolution: {integrity: sha512-/Ng/W/kFv7wdEHYzxdK7Cv0BHEGSkSB3M0Ssl8Ndr1eMiYeas/+Mv4cNaDqamqWx6nd2uQZfPz6g25z25M/sdw==}
|
||||
|
||||
/emoji-regex@9.2.2:
|
||||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
|
||||
@ -3735,7 +3735,7 @@ packages:
|
||||
peerDependencies:
|
||||
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.1
|
||||
'@babel/runtime': 7.23.2
|
||||
aria-query: 5.3.0
|
||||
array-includes: 3.1.7
|
||||
array.prototype.flatmap: 1.3.2
|
||||
@ -5105,10 +5105,10 @@ packages:
|
||||
resolution: {integrity: sha512-voUkdd/jHWrG+7NS+mX49Pat+POKdgGW78V7pYMSrTaOjUitR6ySEcAci8hn17Rsx1IMI3+5w41dkADM1J1ZEg==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@babel/core': 7.23.0
|
||||
'@babel/core': 7.23.2
|
||||
'@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/plugin-syntax-jsx': 7.22.5(@babel/core@7.23.2)
|
||||
'@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.23.2)
|
||||
'@babel/types': 7.23.0
|
||||
kleur: 4.1.5
|
||||
rollup: 3.29.4
|
||||
|
91
src-tauri/Cargo.lock
generated
91
src-tauri/Cargo.lock
generated
@ -170,18 +170,6 @@ dependencies = [
|
||||
"x11rb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
version = "0.5.1"
|
||||
@ -406,12 +394,6 @@ dependencies = [
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.4"
|
||||
@ -439,17 +421,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake2b_simd"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"constant_time_eq 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
@ -860,12 +831,6 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
@ -1051,9 +1016,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "curl-sys"
|
||||
version = "0.4.67+curl-8.3.0"
|
||||
version = "0.4.68+curl-8.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cc35d066510b197a0f72de863736641539957628c8a42e70e27c66849e77c34"
|
||||
checksum = "b4a0d18d88360e374b16b2273c832b5e57258ffc1d4aa4f96b108e0738d5752f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@ -2554,7 +2519,6 @@ name = "lume"
|
||||
version = "1.2.6"
|
||||
dependencies = [
|
||||
"keyring",
|
||||
"rust-argon2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx-cli",
|
||||
@ -3444,7 +3408,7 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdc0001cfea3db57a2e24bc0d818e9e20e554b5f97fabb9bc231dc240269ae06"
|
||||
dependencies = [
|
||||
"base64 0.21.4",
|
||||
"base64",
|
||||
"indexmap 1.9.3",
|
||||
"line-wrap",
|
||||
"quick-xml 0.29.0",
|
||||
@ -3724,7 +3688,7 @@ dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.1",
|
||||
"regex-syntax 0.8.0",
|
||||
"regex-syntax 0.8.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3744,7 +3708,7 @@ checksum = "465c6fc0621e4abc4187a2bda0937bfd4f722c2730b29562e19689ea796c9a4b"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.8.0",
|
||||
"regex-syntax 0.8.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3755,9 +3719,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3cbb081b9784b07cceb8824c8583f86db4814d172ab043f3c23f7dc600bf83d"
|
||||
checksum = "56d84fdd47036b038fc80dd333d10b6aab10d5d31f4a366e20014def75328d33"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
@ -3765,7 +3729,7 @@ version = "0.11.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
|
||||
dependencies = [
|
||||
"base64 0.21.4",
|
||||
"base64",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
@ -3861,18 +3825,6 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b50162d19404029c1ceca6f6980fe40d45c8b369f6f44446fa14bb39573b5bb9"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"blake2b_simd",
|
||||
"constant_time_eq 0.1.5",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
@ -3932,7 +3884,7 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
|
||||
dependencies = [
|
||||
"base64 0.21.4",
|
||||
"base64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4167,7 +4119,7 @@ version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237"
|
||||
dependencies = [
|
||||
"base64 0.21.4",
|
||||
"base64",
|
||||
"chrono",
|
||||
"hex",
|
||||
"indexmap 1.9.3",
|
||||
@ -4521,7 +4473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.4",
|
||||
"base64",
|
||||
"bitflags 2.4.0",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
@ -4564,7 +4516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.4",
|
||||
"base64",
|
||||
"bitflags 2.4.0",
|
||||
"byteorder",
|
||||
"crc",
|
||||
@ -4692,9 +4644,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.1"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||
|
||||
[[package]]
|
||||
name = "swift-rs"
|
||||
@ -4702,7 +4654,7 @@ version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bbdb58577b6301f8d17ae2561f32002a5bae056d444e0f69e611e504a276204"
|
||||
dependencies = [
|
||||
"base64 0.21.4",
|
||||
"base64",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
@ -4924,7 +4876,7 @@ version = "2.0.0-alpha.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8acf40451edf9ccd16d110cb10e9959fec6ccca286c5cc66b859878f8aa9a7b"
|
||||
dependencies = [
|
||||
"base64 0.21.4",
|
||||
"base64",
|
||||
"brotli",
|
||||
"ico",
|
||||
"json-patch",
|
||||
@ -5159,7 +5111,7 @@ name = "tauri-plugin-updater"
|
||||
version = "2.0.0-alpha.2"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#8902fe9adf256c52e7e6a14370f56d0b4780a3a2"
|
||||
dependencies = [
|
||||
"base64 0.21.4",
|
||||
"base64",
|
||||
"dirs-next",
|
||||
"futures-util",
|
||||
"http",
|
||||
@ -6340,7 +6292,7 @@ version = "0.33.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cb3bc6ed7e3d905a5a963a3e4e9ee5ede76408e50de42d68e523ee75ab1c78a"
|
||||
dependencies = [
|
||||
"base64 0.21.4",
|
||||
"base64",
|
||||
"block",
|
||||
"cocoa 0.24.1",
|
||||
"core-graphics 0.22.3",
|
||||
@ -6527,7 +6479,7 @@ dependencies = [
|
||||
"aes 0.8.3",
|
||||
"byteorder",
|
||||
"bzip2",
|
||||
"constant_time_eq 0.1.5",
|
||||
"constant_time_eq",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"flate2",
|
||||
@ -6559,12 +6511,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.8+zstd.1.5.5"
|
||||
version = "2.0.9+zstd.1.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c"
|
||||
checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
|
@ -40,7 +40,6 @@ tauri-plugin-sql = { git = "hhttps://github.com/tauri-apps/plugins-workspace", b
|
||||
sqlx-cli = { version = "0.7.0", default-features = false, features = [
|
||||
"sqlite",
|
||||
] }
|
||||
rust-argon2 = "1.0"
|
||||
webpage = { version = "1.6.0", features = ["serde"] }
|
||||
keyring = "2"
|
||||
|
||||
|
@ -99,10 +99,13 @@ fn secure_save(key: String, value: String) -> Result<(), ()> {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn secure_load(key: String) -> Result<String, ()> {
|
||||
fn secure_load(key: String) -> Result<String, String> {
|
||||
let entry = Entry::new("lume", &key).expect("Failed to create entry");
|
||||
let password = entry.get_password().unwrap();
|
||||
Ok(password)
|
||||
if let Ok(password) = entry.get_password() {
|
||||
Ok(password)
|
||||
} else {
|
||||
Err("not found".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
59
src/app.tsx
59
src/app.tsx
@ -27,23 +27,14 @@ export default function App() {
|
||||
try {
|
||||
const totalAccount = await db.checkAccount();
|
||||
|
||||
const stronghold = sessionStorage.getItem('stronghold');
|
||||
const privkey = JSON.parse(stronghold).state.privkey || null;
|
||||
|
||||
const onboarding = localStorage.getItem('onboarding');
|
||||
const step = JSON.parse(onboarding).state.step || null;
|
||||
|
||||
if (totalAccount === 0) {
|
||||
return redirect('/auth/welcome');
|
||||
} else {
|
||||
if (step) {
|
||||
return redirect(step);
|
||||
}
|
||||
// redirect to welcome screen if none user exist
|
||||
if (totalAccount === 0) return redirect('/auth/welcome');
|
||||
|
||||
if (!privkey) {
|
||||
return redirect('/auth/unlock');
|
||||
}
|
||||
}
|
||||
// restart onboarding process
|
||||
if (step) return redirect(step);
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
@ -204,13 +195,6 @@ export default function App() {
|
||||
return { Component: ImportStep2Screen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'step-3',
|
||||
async lazy() {
|
||||
const { ImportStep3Screen } = await import('@app/auth/import/step-3');
|
||||
return { Component: ImportStep3Screen };
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -232,13 +216,6 @@ export default function App() {
|
||||
return { Component: CreateStep2Screen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'step-3',
|
||||
async lazy() {
|
||||
const { CreateStep3Screen } = await import('@app/auth/create/step-3');
|
||||
return { Component: CreateStep3Screen };
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -273,34 +250,6 @@ export default function App() {
|
||||
return { Component: CompleteScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'unlock',
|
||||
async lazy() {
|
||||
const { UnlockScreen } = await import('@app/auth/unlock');
|
||||
return { Component: UnlockScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'lock',
|
||||
async lazy() {
|
||||
const { LockScreen } = await import('@app/auth/lock');
|
||||
return { Component: LockScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'migrate',
|
||||
async lazy() {
|
||||
const { MigrateScreen } = await import('@app/auth/migrate');
|
||||
return { Component: MigrateScreen };
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'reset',
|
||||
async lazy() {
|
||||
const { ResetScreen } = await import('@app/auth/reset');
|
||||
return { Component: ResetScreen };
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -1,19 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
import { useOnboarding } from '@stores/onboarding';
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
export function AuthCreateScreen() {
|
||||
const [step, tmpPrivkey] = useOnboarding((state) => [state.step, state.tempPrivkey]);
|
||||
const setPrivkey = useStronghold((state) => state.setPrivkey);
|
||||
|
||||
useEffect(() => {
|
||||
if (step) {
|
||||
setPrivkey(tmpPrivkey);
|
||||
}
|
||||
}, [tmpPrivkey]);
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Outlet />
|
||||
|
@ -11,13 +11,11 @@ import { useStorage } from '@libs/storage/provider';
|
||||
import { CopyIcon } from '@shared/icons';
|
||||
|
||||
import { useOnboarding } from '@stores/onboarding';
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
export function CreateStep1Screen() {
|
||||
const { db } = useStorage();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const setPrivkey = useStronghold((state) => state.setPrivkey);
|
||||
const setTempPrivkey = useOnboarding((state) => state.setTempPrivkey);
|
||||
const setPubkey = useOnboarding((state) => state.setPubkey);
|
||||
const setStep = useOnboarding((state) => state.setStep);
|
||||
@ -67,7 +65,6 @@ export function CreateStep1Screen() {
|
||||
setLoading(true);
|
||||
|
||||
// update state
|
||||
setPrivkey(privkey);
|
||||
setTempPrivkey(privkey); // only use if user close app and reopen it
|
||||
setPubkey(pubkey);
|
||||
|
||||
|
@ -1,122 +1,152 @@
|
||||
import { NDKKind } from '@nostr-dev-kit/ndk';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Resolver, useForm } from 'react-hook-form';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons';
|
||||
import { AvatarUploader } from '@shared/avatarUploader';
|
||||
import { BannerUploader } from '@shared/bannerUploader';
|
||||
import { LoaderIcon } from '@shared/icons';
|
||||
import { ArrowRightCircleIcon } from '@shared/icons/arrowRightCircle';
|
||||
import { Image } from '@shared/image';
|
||||
|
||||
import { useOnboarding } from '@stores/onboarding';
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
import { WidgetKinds } from '@stores/widgets';
|
||||
|
||||
type FormValues = {
|
||||
password: string;
|
||||
};
|
||||
|
||||
const resolver: Resolver<FormValues> = async (values) => {
|
||||
return {
|
||||
values: values.password ? values : {},
|
||||
errors: !values.password
|
||||
? {
|
||||
password: {
|
||||
type: 'required',
|
||||
message: 'This is required.',
|
||||
},
|
||||
}
|
||||
: {},
|
||||
};
|
||||
};
|
||||
import { useNostr } from '@utils/hooks/useNostr';
|
||||
|
||||
export function CreateStep2Screen() {
|
||||
const navigate = useNavigate();
|
||||
const setStep = useOnboarding((state) => state.setStep);
|
||||
const pubkey = useOnboarding((state) => state.pubkey);
|
||||
const privkey = useStronghold((state) => state.privkey);
|
||||
|
||||
const [passwordInput, setPasswordInput] = useState('password');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [picture, setPicture] = useState('https://void.cat/d/5VKmKyuHyxrNMf9bWSVPih');
|
||||
const [banner, setBanner] = useState('');
|
||||
|
||||
const { db } = useStorage();
|
||||
|
||||
// toggle private key
|
||||
const showPassword = () => {
|
||||
if (passwordInput === 'password') {
|
||||
setPasswordInput('text');
|
||||
} else {
|
||||
setPasswordInput('password');
|
||||
}
|
||||
};
|
||||
|
||||
const { publish } = useNostr();
|
||||
const {
|
||||
register,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { errors, isDirty, isValid },
|
||||
} = useForm<FormValues>({ resolver });
|
||||
formState: { isDirty, isValid },
|
||||
} = useForm();
|
||||
|
||||
const onSubmit = async (data: { [x: string]: string }) => {
|
||||
const onSubmit = async (data: { name: string; about: string; website: string }) => {
|
||||
setLoading(true);
|
||||
if (data.password.length > 3) {
|
||||
// save privkey to secure storage
|
||||
await db.secureSave(pubkey, privkey);
|
||||
try {
|
||||
const profile = {
|
||||
...data,
|
||||
name: data.name,
|
||||
display_name: data.name,
|
||||
bio: data.about,
|
||||
website: data.website,
|
||||
};
|
||||
|
||||
// redirect to next step
|
||||
navigate('/auth/create/step-3', { replace: true });
|
||||
} else {
|
||||
setLoading(false);
|
||||
setError('password', {
|
||||
type: 'custom',
|
||||
message: 'Password is required and must be greater than 3',
|
||||
const event = await publish({
|
||||
content: JSON.stringify(profile),
|
||||
kind: NDKKind.Metadata,
|
||||
tags: [],
|
||||
});
|
||||
|
||||
// create default widget
|
||||
await db.createWidget(WidgetKinds.other.learnNostr, 'Learn Nostr', '');
|
||||
|
||||
if (event) {
|
||||
navigate('/auth/onboarding', { replace: true });
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('error: ', e);
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// save current step, if user close app and reopen it
|
||||
setStep('/auth/create/step-2');
|
||||
setStep('/auth/create/step-3');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="mb-4 border-b border-white/10 pb-4">
|
||||
<h1 className="mb-2 text-center text-2xl font-semibold text-white">
|
||||
Set password to secure your key
|
||||
Personalize your Nostr profile
|
||||
</h1>
|
||||
<p className="text-white/70">
|
||||
Password is not related to your Nostr account. It is only used to secure your
|
||||
keys stored on your local machine and to unlock the app (like unlocking your
|
||||
phone with a passcode). When you move to other Nostr clients, you just need to
|
||||
copy your private key.
|
||||
Nostr profile is synchronous across all Nostr clients. If you create a profile
|
||||
on Lume, it will also work well with other Nostr clients. If you update your
|
||||
profile on another Nostr client, it will also sync to Lume.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-3">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="relative">
|
||||
<input
|
||||
{...register('password', { required: true })}
|
||||
type={passwordInput}
|
||||
placeholder="Enter password"
|
||||
className="relative h-12 w-full rounded-lg border-t border-white/10 bg-white/20 px-3.5 py-1 text-center tracking-widest text-white !outline-none backdrop-blur-xl placeholder:tracking-normal placeholder:text-white/70"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => showPassword()}
|
||||
className="group absolute right-2 top-1/2 -translate-y-1/2 transform rounded p-1 backdrop-blur-xl hover:bg-white/20"
|
||||
>
|
||||
{passwordInput === 'password' ? (
|
||||
<EyeOffIcon className="h-4 w-4 text-white/50 group-hover:text-white" />
|
||||
) : (
|
||||
<EyeOnIcon className="h-4 w-4 text-white/50 group-hover:text-white" />
|
||||
)}
|
||||
</button>
|
||||
<div className="w-full overflow-hidden rounded-xl bg-white/10 backdrop-blur-xl">
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="mb-0 flex flex-col">
|
||||
<input type={'hidden'} {...register('picture')} value={picture} />
|
||||
<input type={'hidden'} {...register('banner')} value={banner} />
|
||||
<div className="relative">
|
||||
<div className="relative h-36 w-full bg-white/10 backdrop-blur-xl">
|
||||
{banner ? (
|
||||
<Image
|
||||
src={banner}
|
||||
alt="user's banner"
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="h-full w-full bg-white/20" />
|
||||
)}
|
||||
<div className="absolute left-1/2 top-1/2 z-10 h-full w-full -translate-x-1/2 -translate-y-1/2 transform">
|
||||
<BannerUploader setBanner={setBanner} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-5 px-4">
|
||||
<div className="relative z-10 -mt-8 h-16 w-16">
|
||||
<Image
|
||||
src={picture}
|
||||
alt="user's avatar"
|
||||
className="h-16 w-16 rounded-lg object-cover ring-2 ring-white/20"
|
||||
/>
|
||||
<div className="absolute left-1/2 top-1/2 z-10 h-full w-full -translate-x-1/2 -translate-y-1/2 transform">
|
||||
<AvatarUploader setPicture={setPicture} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span className="text-sm text-red-400">
|
||||
{errors.password && <p>{errors.password.message}</p>}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-center">
|
||||
<div className="flex flex-col gap-4 px-4 pb-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<label htmlFor="name" className="font-medium text-white">
|
||||
Name *
|
||||
</label>
|
||||
<input
|
||||
type={'text'}
|
||||
{...register('name', {
|
||||
required: true,
|
||||
minLength: 1,
|
||||
})}
|
||||
spellCheck={false}
|
||||
className="relative h-12 w-full rounded-lg bg-white/20 px-3 py-1 text-white !outline-none backdrop-blur-xl placeholder:text-white/70"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label htmlFor="about" className="font-medium text-white">
|
||||
Bio
|
||||
</label>
|
||||
<textarea
|
||||
{...register('about')}
|
||||
spellCheck={false}
|
||||
className="relative h-20 w-full resize-none rounded-lg bg-white/20 px-3 py-2 text-white !outline-none backdrop-blur-xl placeholder:text-white/70"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label htmlFor="website" className="font-medium text-white">
|
||||
Website
|
||||
</label>
|
||||
<input
|
||||
{...register('website', {
|
||||
required: false,
|
||||
})}
|
||||
spellCheck={false}
|
||||
className="relative h-12 w-full rounded-lg bg-white/20 px-3 py-1 text-white !outline-none backdrop-blur-xl placeholder:text-white/70"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!isDirty || !isValid}
|
||||
@ -125,7 +155,7 @@ export function CreateStep2Screen() {
|
||||
{loading ? (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>Securing your account...</span>
|
||||
<span>Creating...</span>
|
||||
<LoaderIcon className="h-5 w-5 animate-spin text-white" />
|
||||
</>
|
||||
) : (
|
||||
|
@ -1,174 +0,0 @@
|
||||
import { NDKKind } from '@nostr-dev-kit/ndk';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { AvatarUploader } from '@shared/avatarUploader';
|
||||
import { BannerUploader } from '@shared/bannerUploader';
|
||||
import { LoaderIcon } from '@shared/icons';
|
||||
import { ArrowRightCircleIcon } from '@shared/icons/arrowRightCircle';
|
||||
import { Image } from '@shared/image';
|
||||
|
||||
import { useOnboarding } from '@stores/onboarding';
|
||||
import { WidgetKinds } from '@stores/widgets';
|
||||
|
||||
import { useNostr } from '@utils/hooks/useNostr';
|
||||
|
||||
export function CreateStep3Screen() {
|
||||
const navigate = useNavigate();
|
||||
const setStep = useOnboarding((state) => state.setStep);
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [picture, setPicture] = useState('https://void.cat/d/5VKmKyuHyxrNMf9bWSVPih');
|
||||
const [banner, setBanner] = useState('');
|
||||
|
||||
const { db } = useStorage();
|
||||
const { publish } = useNostr();
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { isDirty, isValid },
|
||||
} = useForm();
|
||||
|
||||
const onSubmit = async (data: { name: string; about: string; website: string }) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const profile = {
|
||||
...data,
|
||||
name: data.name,
|
||||
display_name: data.name,
|
||||
bio: data.about,
|
||||
website: data.website,
|
||||
};
|
||||
|
||||
const event = await publish({
|
||||
content: JSON.stringify(profile),
|
||||
kind: NDKKind.Metadata,
|
||||
tags: [],
|
||||
});
|
||||
|
||||
// create default widget
|
||||
await db.createWidget(WidgetKinds.other.learnNostr, 'Learn Nostr', '');
|
||||
|
||||
if (event) {
|
||||
navigate('/auth/onboarding', { replace: true });
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('error: ', e);
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// save current step, if user close app and reopen it
|
||||
setStep('/auth/create/step-3');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="mb-4 border-b border-white/10 pb-4">
|
||||
<h1 className="mb-2 text-center text-2xl font-semibold text-white">
|
||||
Personalize your Nostr profile
|
||||
</h1>
|
||||
<p className="text-white/70">
|
||||
Nostr profile is synchronous across all Nostr clients. If you create a profile
|
||||
on Lume, it will also work well with other Nostr clients. If you update your
|
||||
profile on another Nostr client, it will also sync to Lume.
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full overflow-hidden rounded-xl bg-white/10 backdrop-blur-xl">
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="mb-0 flex flex-col">
|
||||
<input type={'hidden'} {...register('picture')} value={picture} />
|
||||
<input type={'hidden'} {...register('banner')} value={banner} />
|
||||
<div className="relative">
|
||||
<div className="relative h-36 w-full bg-white/10 backdrop-blur-xl">
|
||||
{banner ? (
|
||||
<Image
|
||||
src={banner}
|
||||
alt="user's banner"
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="h-full w-full bg-white/20" />
|
||||
)}
|
||||
<div className="absolute left-1/2 top-1/2 z-10 h-full w-full -translate-x-1/2 -translate-y-1/2 transform">
|
||||
<BannerUploader setBanner={setBanner} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-5 px-4">
|
||||
<div className="relative z-10 -mt-8 h-16 w-16">
|
||||
<Image
|
||||
src={picture}
|
||||
alt="user's avatar"
|
||||
className="h-16 w-16 rounded-lg object-cover ring-2 ring-white/20"
|
||||
/>
|
||||
<div className="absolute left-1/2 top-1/2 z-10 h-full w-full -translate-x-1/2 -translate-y-1/2 transform">
|
||||
<AvatarUploader setPicture={setPicture} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 px-4 pb-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<label htmlFor="name" className="font-medium text-white">
|
||||
Name *
|
||||
</label>
|
||||
<input
|
||||
type={'text'}
|
||||
{...register('name', {
|
||||
required: true,
|
||||
minLength: 1,
|
||||
})}
|
||||
spellCheck={false}
|
||||
className="relative h-12 w-full rounded-lg bg-white/20 px-3 py-1 text-white !outline-none backdrop-blur-xl placeholder:text-white/70"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label htmlFor="about" className="font-medium text-white">
|
||||
Bio
|
||||
</label>
|
||||
<textarea
|
||||
{...register('about')}
|
||||
spellCheck={false}
|
||||
className="relative h-20 w-full resize-none rounded-lg bg-white/20 px-3 py-2 text-white !outline-none backdrop-blur-xl placeholder:text-white/70"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label htmlFor="website" className="font-medium text-white">
|
||||
Website
|
||||
</label>
|
||||
<input
|
||||
{...register('website', {
|
||||
required: false,
|
||||
})}
|
||||
spellCheck={false}
|
||||
className="relative h-12 w-full rounded-lg bg-white/20 px-3 py-1 text-white !outline-none backdrop-blur-xl placeholder:text-white/70"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!isDirty || !isValid}
|
||||
className="inline-flex h-12 w-full items-center justify-between gap-2 rounded-lg border-t border-white/10 bg-blue-500 px-6 font-medium leading-none text-white hover:bg-blue-600 focus:outline-none"
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>Creating...</span>
|
||||
<LoaderIcon className="h-5 w-5 animate-spin text-white" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>Continue</span>
|
||||
<ArrowRightCircleIcon className="h-5 w-5" />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,19 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
import { useOnboarding } from '@stores/onboarding';
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
export function AuthImportScreen() {
|
||||
const [step, tmpPrivkey] = useOnboarding((state) => [state.step, state.tempPrivkey]);
|
||||
const setPrivkey = useStronghold((state) => state.setPrivkey);
|
||||
|
||||
useEffect(() => {
|
||||
if (step) {
|
||||
setPrivkey(tmpPrivkey);
|
||||
}
|
||||
}, [tmpPrivkey]);
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Outlet />
|
||||
|
@ -9,7 +9,6 @@ import { EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons';
|
||||
import { ArrowRightCircleIcon } from '@shared/icons/arrowRightCircle';
|
||||
|
||||
import { useOnboarding } from '@stores/onboarding';
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
type FormValues = {
|
||||
privkey: string;
|
||||
@ -31,13 +30,14 @@ const resolver: Resolver<FormValues> = async (values) => {
|
||||
|
||||
export function ImportStep1Screen() {
|
||||
const navigate = useNavigate();
|
||||
const setPrivkey = useStronghold((state) => state.setPrivkey);
|
||||
const setTempPubkey = useOnboarding((state) => state.setTempPrivkey);
|
||||
const setPubkey = useOnboarding((state) => state.setPubkey);
|
||||
const setStep = useOnboarding((state) => state.setStep);
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [passwordInput, setPasswordInput] = useState('password');
|
||||
const [setStep, setPubkey, setTempPrivkey] = useOnboarding((state) => [
|
||||
state.setStep,
|
||||
state.setPubkey,
|
||||
state.setTempPrivkey,
|
||||
]);
|
||||
|
||||
const { db } = useStorage();
|
||||
const {
|
||||
@ -60,8 +60,7 @@ export function ImportStep1Screen() {
|
||||
const pubkey = getPublicKey(privkey);
|
||||
const npub = nip19.npubEncode(pubkey);
|
||||
|
||||
setPrivkey(privkey);
|
||||
setTempPubkey(privkey); // only use if user close app and reopen it
|
||||
setTempPrivkey(privkey);
|
||||
setPubkey(pubkey);
|
||||
|
||||
// add account to local database
|
||||
|
@ -1,143 +1,89 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Resolver, useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons';
|
||||
import { ArrowRightCircleIcon } from '@shared/icons/arrowRightCircle';
|
||||
import { ArrowRightCircleIcon, LoaderIcon } from '@shared/icons';
|
||||
import { User } from '@shared/user';
|
||||
|
||||
import { useOnboarding } from '@stores/onboarding';
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
import { WidgetKinds } from '@stores/widgets';
|
||||
|
||||
type FormValues = {
|
||||
password: string;
|
||||
};
|
||||
|
||||
const resolver: Resolver<FormValues> = async (values) => {
|
||||
return {
|
||||
values: values.password ? values : {},
|
||||
errors: !values.password
|
||||
? {
|
||||
password: {
|
||||
type: 'required',
|
||||
message: 'This is required.',
|
||||
},
|
||||
}
|
||||
: {},
|
||||
};
|
||||
};
|
||||
import { useNostr } from '@utils/hooks/useNostr';
|
||||
|
||||
export function ImportStep2Screen() {
|
||||
const navigate = useNavigate();
|
||||
const setStep = useOnboarding((state) => state.setStep);
|
||||
const pubkey = useOnboarding((state) => state.pubkey);
|
||||
const privkey = useStronghold((state) => state.privkey);
|
||||
|
||||
const [passwordInput, setPasswordInput] = useState('password');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const { db } = useStorage();
|
||||
const { fetchUserData } = useNostr();
|
||||
|
||||
// toggle private key
|
||||
const showPassword = () => {
|
||||
if (passwordInput === 'password') {
|
||||
setPasswordInput('text');
|
||||
} else {
|
||||
setPasswordInput('password');
|
||||
}
|
||||
};
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const {
|
||||
register,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { errors, isDirty, isValid },
|
||||
} = useForm<FormValues>({ resolver });
|
||||
const submit = async () => {
|
||||
try {
|
||||
// show loading indicator
|
||||
setLoading(true);
|
||||
|
||||
const onSubmit = async (data: { [x: string]: string }) => {
|
||||
setLoading(true);
|
||||
if (data.password.length > 3) {
|
||||
// save privkey to secure storage
|
||||
await db.secureSave(pubkey, privkey);
|
||||
// prefetch data
|
||||
const user = await fetchUserData();
|
||||
|
||||
// create default widget
|
||||
await db.createWidget(WidgetKinds.other.learnNostr, 'Learn Nostr', '');
|
||||
|
||||
// redirect to next step
|
||||
navigate('/auth/import/step-3', { replace: true });
|
||||
} else {
|
||||
if (user.status === 'ok') {
|
||||
navigate('/auth/onboarding/step-2', { replace: true });
|
||||
} else {
|
||||
setLoading(false);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('error: ', e);
|
||||
setLoading(false);
|
||||
setError('password', {
|
||||
type: 'custom',
|
||||
message: 'Password is required and must be greater than 3, please check again',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// save current step, if user close app and reopen it
|
||||
setStep('/auth/import/step-2');
|
||||
setStep('/auth/import/step-3');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="mb-4 border-b border-white/10 pb-4">
|
||||
<h1 className="mb-2 text-center text-2xl font-semibold text-white">
|
||||
Set password to secure your key
|
||||
<div className="mb-4 pb-4">
|
||||
<h1 className="text-center text-2xl font-semibold text-white">
|
||||
{loading ? 'Downloading...' : 'Your Nostr profile'}
|
||||
</h1>
|
||||
<p className="text-white/70">
|
||||
Password is not related to your Nostr account. It is only used to secure your
|
||||
keys stored on your local machine and to unlock the app (like unlocking your
|
||||
phone with a passcode). When you move to other Nostr clients, you only need to
|
||||
copy your private key.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-3">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="relative">
|
||||
<input
|
||||
{...register('password', { required: true })}
|
||||
type={passwordInput}
|
||||
placeholder="Enter password"
|
||||
className="relative h-12 w-full rounded-lg border-t border-white/10 bg-white/20 px-3.5 py-1 text-center tracking-widest text-white !outline-none backdrop-blur-xl placeholder:tracking-normal placeholder:text-white/70"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => showPassword()}
|
||||
className="group absolute right-2 top-1/2 -translate-y-1/2 transform rounded p-1 backdrop-blur-xl hover:bg-white/20"
|
||||
>
|
||||
{passwordInput === 'password' ? (
|
||||
<EyeOffIcon className="h-4 w-4 text-white/50 group-hover:text-white" />
|
||||
) : (
|
||||
<EyeOnIcon className="h-4 w-4 text-white/50 group-hover:text-white" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<span className="text-sm text-red-400">
|
||||
{errors.password && <p>{errors.password.message}</p>}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-center">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!isDirty || !isValid}
|
||||
className="inline-flex h-12 w-full items-center justify-between gap-2 rounded-lg border-t border-white/10 bg-blue-500 px-6 font-medium leading-none text-white hover:bg-blue-600 focus:outline-none"
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>Securing your account...</span>
|
||||
<LoaderIcon className="h-5 w-5 animate-spin text-white" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>Continue</span>
|
||||
<ArrowRightCircleIcon className="h-5 w-5" />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="rounded-lg border-t border-white/10 bg-white/20 px-3 py-3">
|
||||
<User pubkey={db.account.pubkey} variant="simple" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-12 w-full items-center justify-between gap-2 rounded-lg bg-blue-500 px-6 font-medium leading-none text-white hover:bg-blue-600 focus:outline-none"
|
||||
onClick={() => submit()}
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>It might take a bit, please patient...</span>
|
||||
<LoaderIcon className="h-5 w-5 animate-spin text-white" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>Continue</span>
|
||||
<ArrowRightCircleIcon className="h-5 w-5" />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
<span className="text-center text-sm text-white/50">
|
||||
By clicking 'Continue', Lume will download your old relay list and
|
||||
metadata. It may take a bit
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,90 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { ArrowRightCircleIcon, LoaderIcon } from '@shared/icons';
|
||||
import { User } from '@shared/user';
|
||||
|
||||
import { useOnboarding } from '@stores/onboarding';
|
||||
import { WidgetKinds } from '@stores/widgets';
|
||||
|
||||
import { useNostr } from '@utils/hooks/useNostr';
|
||||
|
||||
export function ImportStep3Screen() {
|
||||
const navigate = useNavigate();
|
||||
const setStep = useOnboarding((state) => state.setStep);
|
||||
|
||||
const { db } = useStorage();
|
||||
const { fetchUserData } = useNostr();
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const submit = async () => {
|
||||
try {
|
||||
// show loading indicator
|
||||
setLoading(true);
|
||||
|
||||
// prefetch data
|
||||
const user = await fetchUserData();
|
||||
|
||||
// create default widget
|
||||
await db.createWidget(WidgetKinds.other.learnNostr, 'Learn Nostr', '');
|
||||
|
||||
// redirect to next step
|
||||
if (user.status === 'ok') {
|
||||
navigate('/auth/onboarding/step-2', { replace: true });
|
||||
} else {
|
||||
setLoading(false);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('error: ', e);
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// save current step, if user close app and reopen it
|
||||
setStep('/auth/import/step-3');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="mb-4 pb-4">
|
||||
<h1 className="text-center text-2xl font-semibold text-white">
|
||||
{loading ? 'Downloading...' : 'Your Nostr profile'}
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="rounded-lg border-t border-white/10 bg-white/20 px-3 py-3">
|
||||
<User pubkey={db.account.pubkey} variant="simple" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-12 w-full items-center justify-between gap-2 rounded-lg bg-blue-500 px-6 font-medium leading-none text-white hover:bg-blue-600 focus:outline-none"
|
||||
onClick={() => submit()}
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>It might take a bit, please patient...</span>
|
||||
<LoaderIcon className="h-5 w-5 animate-spin text-white" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>Continue</span>
|
||||
<ArrowRightCircleIcon className="h-5 w-5" />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
<span className="text-center text-sm text-white/50">
|
||||
By clicking 'Continue', Lume will download your old relay list and
|
||||
metadata. It may take a bit
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
export function LockScreen() {
|
||||
return (
|
||||
<div
|
||||
className="h-full w-full bg-cover bg-center"
|
||||
style={{ backgroundImage: 'url(/wallpapers/1.png)' }}
|
||||
>
|
||||
<p>TODO</p>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { appConfigDir } from '@tauri-apps/api/path';
|
||||
import { Stronghold } from '@tauri-apps/plugin-stronghold';
|
||||
import { useState } from 'react';
|
||||
import { Resolver, useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
type FormValues = {
|
||||
password: string;
|
||||
};
|
||||
|
||||
const resolver: Resolver<FormValues> = async (values) => {
|
||||
return {
|
||||
values: values.password ? values : {},
|
||||
errors: !values.password
|
||||
? {
|
||||
password: {
|
||||
type: 'required',
|
||||
message: 'This is required.',
|
||||
},
|
||||
}
|
||||
: {},
|
||||
};
|
||||
};
|
||||
|
||||
export function MigrateScreen() {
|
||||
const queryClient = useQueryClient();
|
||||
const navigate = useNavigate();
|
||||
const setPrivkey = useStronghold((state) => state.setPrivkey);
|
||||
|
||||
const [passwordInput, setPasswordInput] = useState('password');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const { db } = useStorage();
|
||||
|
||||
// toggle private key
|
||||
const showPassword = () => {
|
||||
if (passwordInput === 'password') {
|
||||
setPasswordInput('text');
|
||||
} else {
|
||||
setPasswordInput('password');
|
||||
}
|
||||
};
|
||||
|
||||
const {
|
||||
register,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { errors, isDirty, isValid },
|
||||
} = useForm<FormValues>({ resolver });
|
||||
|
||||
const onSubmit = async (data: { [x: string]: string }) => {
|
||||
setLoading(true);
|
||||
if (data.password.length > 3) {
|
||||
// load private in secure storage
|
||||
try {
|
||||
// save privkey to secure storage
|
||||
const dir = await appConfigDir();
|
||||
const stronghold = await Stronghold.load(`${dir}/lume.stronghold`, data.password);
|
||||
|
||||
if (!db.secureDB) db.secureDB = stronghold;
|
||||
await db.secureSave(db.account.pubkey, db.account.privkey);
|
||||
|
||||
// add privkey to state
|
||||
setPrivkey(db.account.privkey);
|
||||
// remove privkey in db
|
||||
await db.removePrivkey();
|
||||
// clear cache
|
||||
await queryClient.invalidateQueries(['account']);
|
||||
// redirect to home
|
||||
navigate('/', { replace: true });
|
||||
} catch {
|
||||
setLoading(false);
|
||||
setError('password', {
|
||||
type: 'custom',
|
||||
message: 'Wrong password',
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setLoading(false);
|
||||
setError('password', {
|
||||
type: 'custom',
|
||||
message: 'Password is required and must be greater than 3',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="mb-8 text-center">
|
||||
<h1 className="text-xl font-semibold text-white">
|
||||
Upgrade security for your account
|
||||
</h1>
|
||||
</div>
|
||||
<div className="w-full rounded-xl bg-white/10 px-3 py-3 backdrop-blur-xl">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<div className="mt-1">
|
||||
<p className="text-sm text-white/50">
|
||||
You're using old Lume version which store your private key as
|
||||
plaintext in database, this is huge security risk.
|
||||
</p>
|
||||
<p className="mt-2 text-sm text-white/50">
|
||||
To secure your private key, please set a password and Lume will put your
|
||||
private key in secure storage.
|
||||
</p>
|
||||
<p className="mt-2 text-sm text-white/50">
|
||||
It is not possible to start the app without applying this step, it is
|
||||
easy and fast!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="mb-0">
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="font-medium text-white">
|
||||
Set a password to protect your key
|
||||
</span>
|
||||
<div className="relative">
|
||||
<input
|
||||
{...register('password', { required: true })}
|
||||
type={passwordInput}
|
||||
placeholder="min. 4 characters"
|
||||
className="relative w-full rounded-lg bg-white/10 py-3 pl-3.5 pr-11 text-white !outline-none placeholder:text-white/50"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => showPassword()}
|
||||
className="group absolute right-2 top-1/2 -translate-y-1/2 transform rounded p-1 hover:bg-white/10"
|
||||
>
|
||||
{passwordInput === 'password' ? (
|
||||
<EyeOffIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-white/50 group-hover:text-white"
|
||||
/>
|
||||
) : (
|
||||
<EyeOnIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-white/50 group-hover:text-white"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<span className="text-sm text-red-400">
|
||||
{errors.password && <p>{errors.password.message}</p>}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-center">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!isDirty || !isValid}
|
||||
className="mt-3 inline-flex h-11 w-full items-center justify-center rounded-md bg-blue-500 font-medium text-white hover:bg-blue-600 disabled:pointer-events-none disabled:opacity-50"
|
||||
>
|
||||
{loading ? (
|
||||
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
|
||||
) : (
|
||||
'Continue →'
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,19 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
import { useOnboarding } from '@stores/onboarding';
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
export function OnboardingScreen() {
|
||||
const [step, tmpPrivkey] = useOnboarding((state) => [state.step, state.tempPrivkey]);
|
||||
const setPrivkey = useStronghold((state) => state.setPrivkey);
|
||||
|
||||
useEffect(() => {
|
||||
if (step) {
|
||||
setPrivkey(tmpPrivkey);
|
||||
}
|
||||
}, [tmpPrivkey]);
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Outlet />
|
||||
|
@ -1,181 +0,0 @@
|
||||
import { appConfigDir } from '@tauri-apps/api/path';
|
||||
import { Stronghold } from '@tauri-apps/plugin-stronghold';
|
||||
import { getPublicKey, nip19 } from 'nostr-tools';
|
||||
import { useState } from 'react';
|
||||
import { Resolver, useForm } from 'react-hook-form';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
type FormValues = {
|
||||
password: string;
|
||||
privkey: string;
|
||||
};
|
||||
|
||||
const resolver: Resolver<FormValues> = async (values) => {
|
||||
return {
|
||||
values: values.password ? values : {},
|
||||
errors: !values.password
|
||||
? {
|
||||
password: {
|
||||
type: 'required',
|
||||
message: 'This is required.',
|
||||
},
|
||||
}
|
||||
: {},
|
||||
};
|
||||
};
|
||||
|
||||
export function ResetScreen() {
|
||||
const navigate = useNavigate();
|
||||
const setPrivkey = useStronghold((state) => state.setPrivkey);
|
||||
|
||||
const [passwordInput, setPasswordInput] = useState('password');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const { db } = useStorage();
|
||||
|
||||
// toggle private key
|
||||
const showPassword = () => {
|
||||
if (passwordInput === 'password') {
|
||||
setPasswordInput('text');
|
||||
} else {
|
||||
setPasswordInput('password');
|
||||
}
|
||||
};
|
||||
|
||||
const {
|
||||
register,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { errors, isDirty, isValid },
|
||||
} = useForm<FormValues>({ resolver });
|
||||
|
||||
const onSubmit = async (data: { [x: string]: string }) => {
|
||||
setLoading(true);
|
||||
if (data.password.length > 3) {
|
||||
try {
|
||||
let privkey = data.privkey;
|
||||
if (privkey.startsWith('nsec')) {
|
||||
privkey = nip19.decode(privkey).data as string;
|
||||
}
|
||||
|
||||
const tmpPubkey = getPublicKey(privkey);
|
||||
|
||||
if (tmpPubkey !== db.account.pubkey) {
|
||||
setLoading(false);
|
||||
setError('password', {
|
||||
type: 'custom',
|
||||
message:
|
||||
"Private key don't match current account store in database, please check again",
|
||||
});
|
||||
} else {
|
||||
// remove old stronghold
|
||||
await db.secureReset();
|
||||
|
||||
// save privkey to secure storage
|
||||
const dir = await appConfigDir();
|
||||
const stronghold = await Stronghold.load(
|
||||
`${dir}/lume.stronghold`,
|
||||
data.password
|
||||
);
|
||||
|
||||
if (!db.secureDB) db.secureDB = stronghold;
|
||||
await db.secureSave(db.account.pubkey, db.account.privkey);
|
||||
|
||||
// add privkey to state
|
||||
setPrivkey(db.account.privkey);
|
||||
// redirect to home
|
||||
navigate('/auth/unlock', { replace: true });
|
||||
}
|
||||
} catch {
|
||||
setLoading(false);
|
||||
setError('password', {
|
||||
type: 'custom',
|
||||
message: 'Invalid private key',
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setLoading(false);
|
||||
setError('password', {
|
||||
type: 'custom',
|
||||
message: 'Password is required and must be greater than 3',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="mb-6 text-center">
|
||||
<h1 className="text-2xl font-semibold text-white">Reset unlock password</h1>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="mb-0 flex flex-col gap-3">
|
||||
<div className="flex flex-col gap-1">
|
||||
<label htmlFor="privkey" className="font-medium text-white">
|
||||
Private key
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
{...register('privkey', { required: true })}
|
||||
type="text"
|
||||
placeholder="nsec1..."
|
||||
className="relative h-12 w-full rounded-lg border-t border-white/10 bg-white/20 px-3.5 py-1 text-white !outline-none backdrop-blur-xl placeholder:text-white/70"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label htmlFor="password" className="font-medium text-white">
|
||||
Set a new password to protect your key
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
{...register('password', { required: true })}
|
||||
type={passwordInput}
|
||||
placeholder="Min. 4 characters"
|
||||
className="relative h-12 w-full rounded-lg border-t border-white/10 bg-white/20 px-3.5 py-1 text-white !outline-none backdrop-blur-xl placeholder:text-white/70"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => showPassword()}
|
||||
className="group absolute right-2 top-1/2 -translate-y-1/2 transform rounded p-1 backdrop-blur-xl hover:bg-white/10"
|
||||
>
|
||||
{passwordInput === 'password' ? (
|
||||
<EyeOffIcon className="h-5 w-5 text-white/50 group-hover:text-white" />
|
||||
) : (
|
||||
<EyeOnIcon className="h-5 w-5 text-white/50 group-hover:text-white" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<span className="text-sm text-red-400">
|
||||
{errors.password && <p>{errors.password.message}</p>}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!isDirty || !isValid}
|
||||
className="inline-flex h-12 w-full items-center justify-center rounded-md bg-blue-500 font-medium text-white hover:bg-blue-600 disabled:pointer-events-none disabled:opacity-50"
|
||||
>
|
||||
{loading ? (
|
||||
<LoaderIcon className="h-4 w-4 animate-spin text-white" />
|
||||
) : (
|
||||
'Continue →'
|
||||
)}
|
||||
</button>
|
||||
<Link
|
||||
to="/auth/unlock"
|
||||
className="mt-1 inline-flex h-12 w-full items-center justify-center rounded-lg text-center text-white/70 hover:bg-white/20"
|
||||
>
|
||||
Back
|
||||
</Link>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
import { appConfigDir } from '@tauri-apps/api/path';
|
||||
import { Stronghold } from '@tauri-apps/plugin-stronghold';
|
||||
import { useState } from 'react';
|
||||
import { Resolver, useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { ArrowRightCircleIcon, EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons';
|
||||
import { User } from '@shared/user';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
type FormValues = {
|
||||
password: string;
|
||||
};
|
||||
|
||||
const resolver: Resolver<FormValues> = async (values) => {
|
||||
return {
|
||||
values: values.password ? values : {},
|
||||
errors: !values.password
|
||||
? {
|
||||
password: {
|
||||
type: 'required',
|
||||
message: 'This is required.',
|
||||
},
|
||||
}
|
||||
: {},
|
||||
};
|
||||
};
|
||||
|
||||
export function UnlockScreen() {
|
||||
const navigate = useNavigate();
|
||||
const setPrivkey = useStronghold((state) => state.setPrivkey);
|
||||
const setWalletConnectURL = useStronghold((state) => state.setWalletConnectURL);
|
||||
|
||||
const [showPassword, setShowPassword] = useState<boolean>(false);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
const { db } = useStorage();
|
||||
const {
|
||||
register,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { isDirty, isValid },
|
||||
} = useForm<FormValues>({ resolver });
|
||||
|
||||
const onSubmit = async (data: { [x: string]: string }) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const dir = await appConfigDir();
|
||||
const stronghold = await Stronghold.load(`${dir}/lume.stronghold`, data.password);
|
||||
|
||||
if (!db.secureDB) db.secureDB = stronghold;
|
||||
|
||||
const privkey = await db.secureLoad(db.account.pubkey);
|
||||
const uri = await db.secureLoad('walletConnectURL', 'nwc');
|
||||
|
||||
if (privkey) setPrivkey(privkey);
|
||||
if (uri) setWalletConnectURL(uri);
|
||||
// redirect to home
|
||||
navigate('/', { replace: true });
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
setError('password', {
|
||||
type: 'custom',
|
||||
message: e,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="mb-8 inline-flex w-full items-center justify-center">
|
||||
<User pubkey={db.account.pubkey} variant="avatar" />
|
||||
</div>
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="mx-auto mb-0 flex w-2/3 flex-col"
|
||||
>
|
||||
<div className="relative">
|
||||
<input
|
||||
{...register('password', { required: true, minLength: 4 })}
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
placeholder="Enter password"
|
||||
className="relative h-12 w-full rounded-lg bg-neutral-300 py-1 text-center tracking-widest text-neutral-900 !outline-none backdrop-blur-xl placeholder:tracking-normal placeholder:text-neutral-500 dark:bg-neutral-800 dark:text-neutral-100 dark:placeholder:text-neutral-500"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowPassword((prev) => !prev)}
|
||||
className="group absolute right-2 top-1/2 -translate-y-1/2 transform rounded-lg p-1 backdrop-blur-xl hover:bg-black/10 dark:hover:bg-white/10"
|
||||
>
|
||||
{showPassword ? (
|
||||
<EyeOffIcon className="group-hover:text-dark h-5 w-5 text-black/50 dark:text-white/50 dark:group-hover:text-white" />
|
||||
) : (
|
||||
<EyeOnIcon className="group-hover:text-dark h-5 w-5 text-black/50 dark:text-white/50 dark:group-hover:text-white" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<div className="mt-2 flex flex-col">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!isDirty || !isValid}
|
||||
className="inline-flex h-10 w-full items-center justify-between gap-2 rounded-lg bg-blue-500 px-6 text-white hover:bg-blue-600 focus:outline-none disabled:opacity-50"
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>Unlocking...</span>
|
||||
<LoaderIcon className="h-5 w-5 animate-spin text-white" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="w-5" />
|
||||
<span>Continue</span>
|
||||
<ArrowRightCircleIcon className="h-5 w-5" />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -13,13 +13,10 @@ import { useStorage } from '@libs/storage/provider';
|
||||
import { LoaderIcon } from '@shared/icons';
|
||||
import { User } from '@shared/user';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
import { useNostr } from '@utils/hooks/useNostr';
|
||||
|
||||
export function ChatScreen() {
|
||||
const listRef = useRef<VListHandle>(null);
|
||||
const userPrivkey = useStronghold((state) => state.privkey);
|
||||
|
||||
const { db } = useStorage();
|
||||
const { ndk } = useNDK();
|
||||
@ -35,7 +32,7 @@ export function ChatScreen() {
|
||||
<ChatMessage
|
||||
message={message}
|
||||
userPubkey={db.account.pubkey}
|
||||
userPrivkey={userPrivkey}
|
||||
userPrivkey={''}
|
||||
self={message.pubkey === db.account.pubkey}
|
||||
/>
|
||||
);
|
||||
@ -108,7 +105,7 @@ export function ChatScreen() {
|
||||
<ChatForm
|
||||
receiverPubkey={pubkey}
|
||||
userPubkey={db.account.pubkey}
|
||||
userPrivkey={userPrivkey}
|
||||
userPrivkey={''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -9,8 +9,6 @@ import { useDecryptMessage } from '@app/chats/hooks/useDecryptMessage';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
import { formatCreatedAt } from '@utils/createdAt';
|
||||
import { useProfile } from '@utils/hooks/useProfile';
|
||||
import { displayNpub } from '@utils/shortenKey';
|
||||
@ -19,8 +17,7 @@ export const ChatListItem = memo(function ChatListItem({ event }: { event: NDKEv
|
||||
const { db } = useStorage();
|
||||
const { status, user } = useProfile(event.pubkey);
|
||||
|
||||
const privkey = useStronghold((state) => state.privkey);
|
||||
const decryptedContent = useDecryptMessage(event, db.account.pubkey, privkey);
|
||||
const decryptedContent = useDecryptMessage(event, db.account.pubkey);
|
||||
|
||||
const createdAt = formatCreatedAt(event.created_at, true);
|
||||
const svgURI =
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { webln } from '@getalby/sdk';
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
import { message } from '@tauri-apps/plugin-dialog';
|
||||
import { WebviewWindow } from '@tauri-apps/plugin-window';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
@ -14,8 +13,6 @@ import {
|
||||
LoaderIcon,
|
||||
} from '@shared/icons';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
export function NWCAlby() {
|
||||
const { db } = useStorage();
|
||||
|
||||
@ -23,8 +20,6 @@ export function NWCAlby() {
|
||||
const [isLoading, setIsloading] = useState(false);
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
|
||||
const setWalletConnectURL = useStronghold((state) => state.setWalletConnectURL);
|
||||
|
||||
const initAlby = async () => {
|
||||
try {
|
||||
setIsloading(true);
|
||||
@ -36,6 +31,7 @@ export function NWCAlby() {
|
||||
const authURL = provider.getAuthorizationUrl({ name: 'Lume' });
|
||||
|
||||
// open auth window
|
||||
/*
|
||||
const webview = new WebviewWindow('alby', {
|
||||
title: 'Connect Alby',
|
||||
url: authURL.href,
|
||||
@ -45,11 +41,11 @@ export function NWCAlby() {
|
||||
});
|
||||
|
||||
webview.listen('tauri://close-requested', async () => {
|
||||
await db.secureSave('walletConnectURL', walletConnectURL, 'nwc');
|
||||
setWalletConnectURL(walletConnectURL);
|
||||
await db.secureSave('nwc', walletConnectURL);
|
||||
setIsConnected(true);
|
||||
setIsloading(false);
|
||||
});
|
||||
*/
|
||||
} catch (e) {
|
||||
setIsloading(false);
|
||||
await message(e.toString(), { title: 'Connect Alby', type: 'error' });
|
||||
|
@ -6,8 +6,6 @@ import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { ArrowRightCircleIcon, CancelIcon, LoaderIcon, WorldIcon } from '@shared/icons';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
type FormValues = {
|
||||
uri: string;
|
||||
};
|
||||
@ -38,8 +36,6 @@ export function NWCOther() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isLoading, setIsloading] = useState(false);
|
||||
|
||||
const setWalletConnectURL = useStronghold((state) => state.setWalletConnectURL);
|
||||
|
||||
const onSubmit = async (data: { [x: string]: string }) => {
|
||||
try {
|
||||
if (!data.uri.startsWith('nostr+walletconnect:')) {
|
||||
@ -57,8 +53,7 @@ export function NWCOther() {
|
||||
const params = new URLSearchParams(uriObj.search);
|
||||
|
||||
if (params.has('relay') && params.has('secret')) {
|
||||
await db.secureSave('walletConnectURL', data.uri, 'nwc');
|
||||
setWalletConnectURL(data.uri);
|
||||
await db.secureSave('nwc', data.uri);
|
||||
setIsloading(false);
|
||||
setIsOpen(false);
|
||||
}
|
||||
@ -95,7 +90,7 @@ export function NWCOther() {
|
||||
</button>
|
||||
</Dialog.Trigger>
|
||||
</div>
|
||||
<Dialog.Portal className="relative z-10">
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 backdrop-blur-2xl" />
|
||||
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
|
||||
<div className="relative h-min w-full max-w-xl rounded-xl bg-white/10 backdrop-blur-xl">
|
||||
|
@ -1,23 +1,14 @@
|
||||
import { NWCAlby } from '@app/nwc/components/alby';
|
||||
import { NWCOther } from '@app/nwc/components/other';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { CheckCircleIcon } from '@shared/icons';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
export function NWCScreen() {
|
||||
const { db } = useStorage();
|
||||
|
||||
const [walletConnectURL, setWalletConnectURL] = useStronghold((state) => [
|
||||
state.walletConnectURL,
|
||||
state.setWalletConnectURL,
|
||||
]);
|
||||
const walletConnectURL = 'test';
|
||||
|
||||
const remove = async () => {
|
||||
setWalletConnectURL('');
|
||||
await db.secureSave('walletConnectURL', '', 'nwc');
|
||||
// setWalletConnectURL('');
|
||||
// await db.secureSave('walletConnectURL', '', 'nwc');
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -5,15 +5,13 @@ import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { EyeOffIcon, EyeOnIcon } from '@shared/icons';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
export function AccountSettingsScreen() {
|
||||
const { db } = useStorage();
|
||||
|
||||
const [privType, setPrivType] = useState('password');
|
||||
const [nsecType, setNsecType] = useState('password');
|
||||
|
||||
const privkey = useStronghold((state) => state.privkey);
|
||||
const privkey = 'todo';
|
||||
const nsec = useMemo(() => nip19.nsecEncode(privkey), [privkey]);
|
||||
|
||||
const showPrivkey = () => {
|
||||
|
@ -57,7 +57,6 @@ export const NDKInstance = () => {
|
||||
const dexieAdapter = new NDKCacheAdapterDexie({ dbName: 'lume_ndkcache' });
|
||||
const instance = new NDK({
|
||||
explicitRelayUrls,
|
||||
// @ts-expect-error, wtf?
|
||||
cacheAdapter: dexieAdapter,
|
||||
});
|
||||
|
||||
|
@ -19,11 +19,13 @@ export class LumeStorage {
|
||||
}
|
||||
|
||||
public async secureSave(value: string, key?: string) {
|
||||
await invoke('secure_save', { key: this.account.pubkey ?? key, value });
|
||||
return await invoke('secure_save', { key: this.account.pubkey ?? key, value });
|
||||
}
|
||||
|
||||
public async secureLoad(key?: string) {
|
||||
const value = invoke('secure_load', { key: this.account.pubkey ?? key });
|
||||
const value: string = await invoke('secure_load', {
|
||||
key: this.account.pubkey ?? key,
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { appConfigDir } from '@tauri-apps/api/path';
|
||||
import { message } from '@tauri-apps/plugin-dialog';
|
||||
import { platform } from '@tauri-apps/plugin-os';
|
||||
import Database from '@tauri-apps/plugin-sql';
|
||||
@ -20,10 +21,13 @@ const StorageProvider = ({ children }: PropsWithChildren<object>) => {
|
||||
try {
|
||||
const sqlite = await Database.load('sqlite:lume.db');
|
||||
const platformName = await platform();
|
||||
const lumeStorage = new LumeStorage(sqlite, platformName);
|
||||
const dir = await appConfigDir();
|
||||
|
||||
const lumeStorage = new LumeStorage(sqlite, platformName);
|
||||
if (!lumeStorage.account) await lumeStorage.getActiveAccount();
|
||||
|
||||
setDB(lumeStorage);
|
||||
console.info(dir);
|
||||
} catch (e) {
|
||||
await message(`Cannot initialize database: ${e}`, {
|
||||
title: 'Lume',
|
||||
|
@ -5,19 +5,14 @@ import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { LogoutIcon } from '@shared/icons';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
export function Logout() {
|
||||
const { db } = useStorage();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const resetStronghold = useStronghold((state) => state.reset);
|
||||
|
||||
const logout = async () => {
|
||||
// remove account
|
||||
db.accountLogout();
|
||||
// clear privkey in session storage
|
||||
resetStronghold();
|
||||
// redirect to welcome screen
|
||||
navigate('/auth/welcome');
|
||||
};
|
||||
|
@ -8,8 +8,6 @@ import CurrencyInput from 'react-currency-input-field';
|
||||
|
||||
import { CancelIcon, ZapIcon } from '@shared/icons';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
import { useEvent } from '@utils/hooks/useEvent';
|
||||
import { useNostr } from '@utils/hooks/useNostr';
|
||||
import { useProfile } from '@utils/hooks/useProfile';
|
||||
@ -21,6 +19,7 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
|
||||
const { user } = useProfile(pubkey);
|
||||
const { data: event } = useEvent(id);
|
||||
|
||||
const [walletConnectURL, setWalletConnectURL] = useState<string>(null);
|
||||
const [amount, setAmount] = useState<string>('21');
|
||||
const [zapMessage, setZapMessage] = useState<string>('');
|
||||
const [invoice, setInvoice] = useState<null | string>(null);
|
||||
@ -28,7 +27,6 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
|
||||
const [isCompleted, setIsCompleted] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const walletConnectURL = useStronghold((state) => state.walletConnectURL);
|
||||
const nwc = useRef(null);
|
||||
|
||||
const createZapRequest = async () => {
|
||||
@ -80,6 +78,12 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function getWalletConnectURL() {
|
||||
// const uri: string = await invoke('secure_load', { key: 'nwc' });
|
||||
setWalletConnectURL('todo');
|
||||
}
|
||||
getWalletConnectURL();
|
||||
|
||||
return () => {
|
||||
setAmount('21');
|
||||
setZapMessage('');
|
||||
|
@ -3,7 +3,7 @@ import { useEffect, useState } from 'react';
|
||||
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
import { useWidgets } from '@stores/widgets';
|
||||
|
||||
import { useNostr } from '@utils/hooks/useNostr';
|
||||
|
||||
@ -11,11 +11,11 @@ export function EventLoader({ firstTime }: { firstTime: boolean }) {
|
||||
const { db } = useStorage();
|
||||
const { getAllEventsSinceLastLogin } = useNostr();
|
||||
|
||||
const setIsFetched = useStronghold((state) => state.setIsFetched);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const [progress, setProgress] = useState(0);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const setIsFetched = useWidgets((state) => state.setIsFetched);
|
||||
|
||||
useEffect(() => {
|
||||
async function getEvents() {
|
||||
const events = await getAllEventsSinceLastLogin();
|
||||
|
@ -18,7 +18,7 @@ import { NoteSkeleton } from '@shared/notes/skeleton';
|
||||
import { TitleBar } from '@shared/titleBar';
|
||||
import { EventLoader, WidgetWrapper } from '@shared/widgets';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
import { useWidgets } from '@stores/widgets';
|
||||
|
||||
import { useNostr } from '@utils/hooks/useNostr';
|
||||
import { toRawEvent } from '@utils/rawEvent';
|
||||
@ -36,7 +36,7 @@ export function LocalNetworkWidget() {
|
||||
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
||||
});
|
||||
|
||||
const isFetched = useStronghold((state) => state.isFetched);
|
||||
const isFetched = useWidgets((state) => state.isFetched);
|
||||
const dbEvents = useMemo(
|
||||
() => (data ? data.pages.flatMap((d: { data: DBEvent[] }) => d.data) : []),
|
||||
[data]
|
||||
|
@ -1,22 +0,0 @@
|
||||
import { create } from 'zustand';
|
||||
import { createJSONStorage, persist } from 'zustand/middleware';
|
||||
|
||||
interface BrowseState {
|
||||
data: Array<{ title: string; data: string[] }>;
|
||||
setData: ({ title, data }: { title: string; data: string[] }) => void;
|
||||
}
|
||||
|
||||
export const useBrowse = create<BrowseState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
data: [],
|
||||
setData: (data) => {
|
||||
set((state) => ({ data: [...state.data, data] }));
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'browseUsers',
|
||||
storage: createJSONStorage(() => localStorage),
|
||||
}
|
||||
)
|
||||
);
|
@ -1,42 +0,0 @@
|
||||
import { create } from 'zustand';
|
||||
import { createJSONStorage, persist } from 'zustand/middleware';
|
||||
|
||||
interface StrongholdState {
|
||||
privkey: null | string;
|
||||
walletConnectURL: null | string;
|
||||
isFetched: null | boolean;
|
||||
setPrivkey: (privkey: string) => void;
|
||||
setWalletConnectURL: (uri: string) => void;
|
||||
clearPrivkey: () => void;
|
||||
setIsFetched: () => void;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
export const useStronghold = create<StrongholdState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
privkey: null,
|
||||
walletConnectURL: null,
|
||||
isFetched: false,
|
||||
setPrivkey: (privkey: string) => {
|
||||
set({ privkey: privkey });
|
||||
},
|
||||
setWalletConnectURL: (uri: string) => {
|
||||
set({ walletConnectURL: uri });
|
||||
},
|
||||
clearPrivkey: () => {
|
||||
set({ privkey: null });
|
||||
},
|
||||
setIsFetched: () => {
|
||||
set({ isFetched: true });
|
||||
},
|
||||
reset: () => {
|
||||
set({ privkey: null, walletConnectURL: null, isFetched: false });
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'stronghold',
|
||||
storage: createJSONStorage(() => sessionStorage),
|
||||
}
|
||||
)
|
||||
);
|
@ -7,10 +7,12 @@ import { Widget, WidgetGroup } from '@utils/types';
|
||||
|
||||
interface WidgetState {
|
||||
widgets: null | Array<Widget>;
|
||||
isFetched: boolean;
|
||||
fetchWidgets: (db: LumeStorage) => void;
|
||||
setWidget: (db: LumeStorage, { kind, title, content }: Widget) => void;
|
||||
removeWidget: (db: LumeStorage, id: string) => void;
|
||||
reorderWidget: (id: string, position: number) => void;
|
||||
setIsFetched: () => void;
|
||||
}
|
||||
|
||||
export const WidgetKinds = {
|
||||
@ -120,6 +122,7 @@ export const useWidgets = create<WidgetState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
widgets: null,
|
||||
isFetched: false,
|
||||
fetchWidgets: async (db: LumeStorage) => {
|
||||
const dbWidgets = await db.getWidgets();
|
||||
console.log('db widgets: ', dbWidgets);
|
||||
@ -142,7 +145,7 @@ export const useWidgets = create<WidgetState>()(
|
||||
await db.removeWidget(id);
|
||||
set((state) => ({ widgets: state.widgets.filter((widget) => widget.id !== id) }));
|
||||
},
|
||||
reorderWidget: (id: string, position: number) =>
|
||||
reorderWidget: (id: string, position: number) => {
|
||||
set((state) => {
|
||||
const widgets = [...state.widgets];
|
||||
const widget = widgets.find((widget) => widget.id === id);
|
||||
@ -153,7 +156,11 @@ export const useWidgets = create<WidgetState>()(
|
||||
widgets.splice(position, 0, widget);
|
||||
|
||||
return { widgets };
|
||||
}),
|
||||
});
|
||||
},
|
||||
setIsFetched: () => {
|
||||
set({ isFetched: true });
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'widgets',
|
||||
|
@ -16,8 +16,6 @@ import { useMemo } from 'react';
|
||||
import { useNDK } from '@libs/ndk/provider';
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { useStronghold } from '@stores/stronghold';
|
||||
|
||||
import { nHoursAgo } from '@utils/date';
|
||||
import { getMultipleRandom } from '@utils/transform';
|
||||
import { NDKEventWithReplies, NostrBuildResponse } from '@utils/types';
|
||||
@ -26,7 +24,6 @@ export function useNostr() {
|
||||
const { db } = useStorage();
|
||||
const { ndk, relayUrls, fetcher } = useNDK();
|
||||
|
||||
const privkey = useStronghold((state) => state.privkey);
|
||||
const subManager = useMemo(
|
||||
() =>
|
||||
new LRUCache<string, NDKSubscription, void>({
|
||||
@ -41,6 +38,7 @@ export function useNostr() {
|
||||
callback: (event: NDKEvent) => void,
|
||||
groupable?: boolean
|
||||
) => {
|
||||
console.info(ndk);
|
||||
if (!ndk) throw new Error('NDK instance not found');
|
||||
|
||||
const subEvent = ndk.subscribe(filter, {
|
||||
@ -347,7 +345,7 @@ export function useNostr() {
|
||||
kind: NDKKind | number;
|
||||
tags: string[][];
|
||||
}): Promise<NDKEvent> => {
|
||||
if (!privkey) throw new Error('Private key not found');
|
||||
const privkey: string = await db.secureLoad();
|
||||
|
||||
const event = new NDKEvent(ndk);
|
||||
const signer = new NDKPrivateKeySigner(privkey);
|
||||
@ -365,7 +363,7 @@ export function useNostr() {
|
||||
};
|
||||
|
||||
const createZap = async (event: NDKEvent, amount: number, message?: string) => {
|
||||
if (!privkey) throw new Error('Private key not found');
|
||||
const privkey: string = await db.secureLoad();
|
||||
|
||||
if (!ndk.signer) {
|
||||
const signer = new NDKPrivateKeySigner(privkey);
|
||||
|
Loading…
x
Reference in New Issue
Block a user