mirror of
https://github.com/luminous-devs/lume.git
synced 2024-09-19 19:46:34 +00:00
polish
This commit is contained in:
parent
8a92813211
commit
d35c64e28d
@ -16,6 +16,7 @@
|
|||||||
"@floating-ui/react": "^0.23.1",
|
"@floating-ui/react": "^0.23.1",
|
||||||
"@headlessui/react": "^1.7.15",
|
"@headlessui/react": "^1.7.15",
|
||||||
"@nostr-dev-kit/ndk": "0.6.0",
|
"@nostr-dev-kit/ndk": "0.6.0",
|
||||||
|
"@radix-ui/react-popover": "^1.0.6",
|
||||||
"@radix-ui/react-tooltip": "^1.0.6",
|
"@radix-ui/react-tooltip": "^1.0.6",
|
||||||
"@tanstack/react-query": "^4.29.19",
|
"@tanstack/react-query": "^4.29.19",
|
||||||
"@tanstack/react-virtual": "3.0.0-beta.54",
|
"@tanstack/react-virtual": "3.0.0-beta.54",
|
||||||
|
173
pnpm-lock.yaml
173
pnpm-lock.yaml
@ -10,6 +10,9 @@ dependencies:
|
|||||||
'@nostr-dev-kit/ndk':
|
'@nostr-dev-kit/ndk':
|
||||||
specifier: 0.6.0
|
specifier: 0.6.0
|
||||||
version: 0.6.0(typescript@4.9.5)
|
version: 0.6.0(typescript@4.9.5)
|
||||||
|
'@radix-ui/react-popover':
|
||||||
|
specifier: ^1.0.6
|
||||||
|
version: 1.0.6(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@radix-ui/react-tooltip':
|
'@radix-ui/react-tooltip':
|
||||||
specifier: ^1.0.6
|
specifier: ^1.0.6
|
||||||
version: 1.0.6(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.0.6(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)
|
||||||
@ -714,6 +717,43 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.14)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.22.5
|
||||||
|
'@types/react': 18.2.14
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-focus-scope@1.0.3(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.22.5
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.14
|
||||||
|
'@types/react-dom': 18.2.6
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-id@1.0.1(@types/react@18.2.14)(react@18.2.0):
|
/@radix-ui/react-id@1.0.1(@types/react@18.2.14)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==}
|
resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -729,6 +769,41 @@ packages:
|
|||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-popover@1.0.6(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-cZ4defGpkZ0qTRtlIBzJLSzL6ht7ofhhW4i1+pkemjV1IKXm0wgCRnee154qlV6r9Ttunmh2TNZhMfV2bavUyA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.22.5
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
'@radix-ui/react-dismissable-layer': 1.0.4(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
'@radix-ui/react-focus-scope': 1.0.3(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-id': 1.0.1(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
'@radix-ui/react-popper': 1.1.2(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-portal': 1.0.3(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.14
|
||||||
|
'@types/react-dom': 18.2.6
|
||||||
|
aria-hidden: 1.2.3
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
react-remove-scroll: 2.5.5(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-popper@1.1.2(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-popper@1.1.2(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==}
|
resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -2158,6 +2233,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-lrbCJwD9saUQrqUfXvl6qoM+QN3W7tLV5pAOs+OqOmopCCz/JkE05MHedJR1xfk4IAnZuJXPVuN5+7jNA2ZCiA==}
|
resolution: {integrity: sha512-lrbCJwD9saUQrqUfXvl6qoM+QN3W7tLV5pAOs+OqOmopCCz/JkE05MHedJR1xfk4IAnZuJXPVuN5+7jNA2ZCiA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/detect-node-es@1.1.0:
|
||||||
|
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/didyoumean@1.2.2:
|
/didyoumean@1.2.2:
|
||||||
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
||||||
dev: true
|
dev: true
|
||||||
@ -2827,6 +2906,11 @@ packages:
|
|||||||
has-symbols: 1.0.3
|
has-symbols: 1.0.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/get-nonce@1.0.1:
|
||||||
|
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/get-stream@6.0.1:
|
/get-stream@6.0.1:
|
||||||
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
|
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@ -3118,6 +3202,12 @@ packages:
|
|||||||
side-channel: 1.0.4
|
side-channel: 1.0.4
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/invariant@2.2.4:
|
||||||
|
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
|
||||||
|
dependencies:
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ip-regex@4.3.0:
|
/ip-regex@4.3.0:
|
||||||
resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==}
|
resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -4297,6 +4387,41 @@ packages:
|
|||||||
react-fast-compare: 3.2.2
|
react-fast-compare: 3.2.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-remove-scroll-bar@2.3.4(@types/react@18.2.14)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.14
|
||||||
|
react: 18.2.0
|
||||||
|
react-style-singleton: 2.2.1(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
tslib: 2.6.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/react-remove-scroll@2.5.5(@types/react@18.2.14)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.14
|
||||||
|
react: 18.2.0
|
||||||
|
react-remove-scroll-bar: 2.3.4(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
react-style-singleton: 2.2.1(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
tslib: 2.6.0
|
||||||
|
use-callback-ref: 1.3.0(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
use-sidecar: 1.1.2(@types/react@18.2.14)(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-router-dom@6.14.0(react-dom@18.2.0)(react@18.2.0):
|
/react-router-dom@6.14.0(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-YEwlApKwzMMMbGbhh+Q7MsloTldcwMgHxUY/1g0uA62+B1hZo2jsybCWIDCL8zvIDB1FA0pBKY9chHbZHt+2dQ==}
|
resolution: {integrity: sha512-YEwlApKwzMMMbGbhh+Q7MsloTldcwMgHxUY/1g0uA62+B1hZo2jsybCWIDCL8zvIDB1FA0pBKY9chHbZHt+2dQ==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
@ -4325,6 +4450,23 @@ packages:
|
|||||||
engines: {node: '>=0.12.0'}
|
engines: {node: '>=0.12.0'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-style-singleton@2.2.1(@types/react@18.2.14)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.14
|
||||||
|
get-nonce: 1.0.1
|
||||||
|
invariant: 2.2.4
|
||||||
|
react: 18.2.0
|
||||||
|
tslib: 2.6.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-virtuoso@4.3.11(react-dom@18.2.0)(react@18.2.0):
|
/react-virtuoso@4.3.11(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-0YrCvQ5GsIKRcN34GxrzhSJGuMNI+hGxWci5cTVuPQ8QWTEsrKfCyqm7YNBMmV3pu7onG1YVUBo86CyCXdejXg==}
|
resolution: {integrity: sha512-0YrCvQ5GsIKRcN34GxrzhSJGuMNI+hGxWci5cTVuPQ8QWTEsrKfCyqm7YNBMmV3pu7onG1YVUBo86CyCXdejXg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@ -5117,6 +5259,37 @@ packages:
|
|||||||
tlds: 1.240.0
|
tlds: 1.240.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/use-callback-ref@1.3.0(@types/react@18.2.14)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.14
|
||||||
|
react: 18.2.0
|
||||||
|
tslib: 2.6.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/use-sidecar@1.1.2(@types/react@18.2.14)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.14
|
||||||
|
detect-node-es: 1.1.0
|
||||||
|
react: 18.2.0
|
||||||
|
tslib: 2.6.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/use-sync-external-store@1.2.0(react@18.2.0):
|
/use-sync-external-store@1.2.0(react@18.2.0):
|
||||||
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
|
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
19
src/app.tsx
19
src/app.tsx
@ -13,12 +13,17 @@ import { ChannelScreen } from "@app/channel";
|
|||||||
import { ChatScreen } from "@app/chat";
|
import { ChatScreen } from "@app/chat";
|
||||||
import { ErrorScreen } from "@app/error";
|
import { ErrorScreen } from "@app/error";
|
||||||
import { Root } from "@app/root";
|
import { Root } from "@app/root";
|
||||||
|
import { AccountSettingsScreen } from "@app/settings/account";
|
||||||
|
import { GeneralSettingsScreen } from "@app/settings/general";
|
||||||
|
import { ShortcutsSettingsScreen } from "@app/settings/shortcuts";
|
||||||
|
import { UpdateSettingsScreen } from "@app/settings/update";
|
||||||
import { SpaceScreen } from "@app/space";
|
import { SpaceScreen } from "@app/space";
|
||||||
import { TrendingScreen } from "@app/trending";
|
import { TrendingScreen } from "@app/trending";
|
||||||
import { UserScreen } from "@app/user";
|
import { UserScreen } from "@app/user";
|
||||||
import { AppLayout } from "@shared/appLayout";
|
import { AppLayout } from "@shared/appLayout";
|
||||||
import { AuthLayout } from "@shared/authLayout";
|
import { AuthLayout } from "@shared/authLayout";
|
||||||
import { Protected } from "@shared/protected";
|
import { Protected } from "@shared/protected";
|
||||||
|
import { SettingsLayout } from "@shared/settingsLayout";
|
||||||
import { RouterProvider, createBrowserRouter } from "react-router-dom";
|
import { RouterProvider, createBrowserRouter } from "react-router-dom";
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
@ -72,6 +77,20 @@ const router = createBrowserRouter([
|
|||||||
{ path: "channel/:id", element: <ChannelScreen /> },
|
{ path: "channel/:id", element: <ChannelScreen /> },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/settings",
|
||||||
|
element: (
|
||||||
|
<Protected>
|
||||||
|
<SettingsLayout />
|
||||||
|
</Protected>
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
{ path: "general", element: <GeneralSettingsScreen /> },
|
||||||
|
{ path: "shortcuts", element: <ShortcutsSettingsScreen /> },
|
||||||
|
{ path: "account", element: <AccountSettingsScreen /> },
|
||||||
|
{ path: "update", element: <UpdateSettingsScreen /> },
|
||||||
|
],
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
@ -12,9 +12,7 @@ export function ChatsListItem({ data }: { data: any }) {
|
|||||||
return (
|
return (
|
||||||
<div className="inline-flex h-9 items-center gap-2.5 rounded-md px-2.5">
|
<div className="inline-flex h-9 items-center gap-2.5 rounded-md px-2.5">
|
||||||
<div className="relative h-6 w-6 shrink-0 animate-pulse rounded bg-zinc-800" />
|
<div className="relative h-6 w-6 shrink-0 animate-pulse rounded bg-zinc-800" />
|
||||||
<div>
|
<div className="h-2.5 w-2/3 animate-pulse rounded bg-zinc-800" />
|
||||||
<div className="h-2.5 w-2/3 animate-pulse truncate rounded bg-zinc-800 text-base font-medium" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -40,10 +38,10 @@ export function ChatsListItem({ data }: { data: any }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-full inline-flex items-center justify-between">
|
<div className="w-full inline-flex items-center justify-between">
|
||||||
<div className="inline-flex items-baseline gap-1">
|
<div className="inline-flex items-baseline gap-1">
|
||||||
<h5 className="max-w-[9rem] truncate font-medium text-zinc-200">
|
<h5 className="max-w-[10rem] truncate font-medium text-zinc-200">
|
||||||
{user?.nip05 ||
|
{user?.nip05 ||
|
||||||
user?.displayName ||
|
|
||||||
user?.name ||
|
user?.name ||
|
||||||
|
user?.displayName ||
|
||||||
shortenKey(data.sender_pubkey)}
|
shortenKey(data.sender_pubkey)}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
7
src/app/settings/account.tsx
Normal file
7
src/app/settings/account.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export function AccountSettingsScreen() {
|
||||||
|
return (
|
||||||
|
<div className="w-full h-full flex items-center justify-center">
|
||||||
|
<h1>Account</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
7
src/app/settings/general.tsx
Normal file
7
src/app/settings/general.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export function GeneralSettingsScreen() {
|
||||||
|
return (
|
||||||
|
<div className="w-full h-full flex items-center justify-center">
|
||||||
|
<h1>General</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
7
src/app/settings/shortcuts.tsx
Normal file
7
src/app/settings/shortcuts.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export function ShortcutsSettingsScreen() {
|
||||||
|
return (
|
||||||
|
<div className="w-full h-full flex items-center justify-center">
|
||||||
|
<h1>Shortcuts</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
7
src/app/settings/update.tsx
Normal file
7
src/app/settings/update.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export function UpdateSettingsScreen() {
|
||||||
|
return (
|
||||||
|
<div className="w-full h-full flex items-center justify-center">
|
||||||
|
<h1>Update</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,19 +1,32 @@
|
|||||||
import { getNotesByPubkey } from "@libs/storage";
|
import { NDKFilter } from "@nostr-dev-kit/ndk";
|
||||||
import { Note } from "@shared/notes/note";
|
import { Note } from "@shared/notes/note";
|
||||||
|
import { RelayContext } from "@shared/relayProvider";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { dateToUnix, getHourAgo } from "@utils/date";
|
||||||
import { LumeEvent } from "@utils/types";
|
import { LumeEvent } from "@utils/types";
|
||||||
|
import { useContext } from "react";
|
||||||
|
|
||||||
export function UserFeed({ pubkey }: { pubkey: string }) {
|
export function UserFeed({ pubkey }: { pubkey: string }) {
|
||||||
|
const ndk = useContext(RelayContext);
|
||||||
const { status, data } = useQuery(["user-feed", pubkey], async () => {
|
const { status, data } = useQuery(["user-feed", pubkey], async () => {
|
||||||
return await getNotesByPubkey(pubkey);
|
const now = new Date();
|
||||||
|
const filter: NDKFilter = {
|
||||||
|
kinds: [1],
|
||||||
|
authors: [pubkey],
|
||||||
|
since: dateToUnix(getHourAgo(48, now)),
|
||||||
|
};
|
||||||
|
const events = await ndk.fetchEvents(filter);
|
||||||
|
return [...events];
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full max-w-[400px] px-2">
|
<div className="w-full max-w-[400px] px-2 pb-10">
|
||||||
{status === "loading" ? (
|
{status === "loading" ? (
|
||||||
<p>Loading...</p>
|
<div className="px-3">
|
||||||
|
<p>Loading...</p>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
data.map((note: LumeEvent) => <Note key={note.event_id} event={note} />)
|
data.map((note: LumeEvent) => <Note key={note.id} event={note} />)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -145,7 +145,7 @@ export function UserScreen() {
|
|||||||
} font-medium inline-flex items-center gap-2 h-10 border-t`}
|
} font-medium inline-flex items-center gap-2 h-10 border-t`}
|
||||||
>
|
>
|
||||||
<ThreadsIcon className="w-4 h-4" />
|
<ThreadsIcon className="w-4 h-4" />
|
||||||
Posts
|
Activities from 48 hours ago
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</Tab>
|
</Tab>
|
||||||
|
@ -400,7 +400,21 @@ export async function createBlock(kind: number, title: string, content: any) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove block
|
||||||
export async function removeBlock(id: string) {
|
export async function removeBlock(id: string) {
|
||||||
const db = await connect();
|
const db = await connect();
|
||||||
return await db.execute(`DELETE FROM blocks WHERE id = "${id}";`);
|
return await db.execute(`DELETE FROM blocks WHERE id = "${id}";`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// logout
|
||||||
|
export async function removeAll() {
|
||||||
|
const db = await connect();
|
||||||
|
await db.execute(`UPDATE settings SET value = "0" WHERE key = "last_login";`);
|
||||||
|
await db.execute("DELETE FROM replies;");
|
||||||
|
await db.execute("DELETE FROM notes;");
|
||||||
|
await db.execute("DELETE FROM blacklist;");
|
||||||
|
await db.execute("DELETE FROM blocks;");
|
||||||
|
await db.execute("DELETE FROM chats;");
|
||||||
|
await db.execute("DELETE FROM accounts;");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -39,4 +39,6 @@ export * from "./cmd";
|
|||||||
export * from "./verticalDots";
|
export * from "./verticalDots";
|
||||||
export * from "./signal";
|
export * from "./signal";
|
||||||
export * from "./unverified";
|
export * from "./unverified";
|
||||||
|
export * from "./settings";
|
||||||
|
export * from "./logout";
|
||||||
// @endindex
|
// @endindex
|
||||||
|
24
src/shared/icons/logout.tsx
Normal file
24
src/shared/icons/logout.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { SVGProps } from "react";
|
||||||
|
|
||||||
|
export function LogoutIcon(
|
||||||
|
props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
d="M20.25 12H9m11.25 0l-4.5 4.5m4.5-4.5l-4.5-4.5m-4.5 12.75h-6.5a1 1 0 01-1-1V4.75a1 1 0 011-1h6.5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
29
src/shared/icons/settings.tsx
Normal file
29
src/shared/icons/settings.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { SVGProps } from "react";
|
||||||
|
|
||||||
|
export function SettingsIcon(
|
||||||
|
props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
d="M8.552 5.37l-1.793-.414a1 1 0 00-.932.267l-.604.604a1 1 0 00-.267.932l.414 1.793a1 1 0 01-.42 1.056l-1.755 1.17a1 1 0 00-.445.832v.78a1 1 0 00.445.832l1.755 1.17a1 1 0 01.42 1.056l-.414 1.793a1 1 0 00.267.932l.604.604a1 1 0 00.932.267l1.793-.414a1 1 0 011.056.42l1.17 1.755a1 1 0 00.832.445h.78a1 1 0 00.832-.445l1.17-1.755a1 1 0 011.056-.42l1.793.414a1 1 0 00.932-.267l.604-.604a1 1 0 00.267-.932l-.414-1.793a1 1 0 01.42-1.056l1.755-1.17a1 1 0 00.445-.832v-.78a1 1 0 00-.445-.832l-1.755-1.17a1 1 0 01-.42-1.056l.414-1.793a1 1 0 00-.267-.932l-.604-.604a1 1 0 00-.932-.267l-1.793.414a1 1 0 01-1.056-.42l-1.17-1.755a1 1 0 00-.832-.445h-.78a1 1 0 00-.832.445L9.608 4.95a1 1 0 01-1.056.42z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
d="M14.75 12a2.75 2.75 0 11-5.5 0 2.75 2.75 0 015.5 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
123
src/shared/logout.tsx
Normal file
123
src/shared/logout.tsx
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
|
import { removeAll } from "@libs/storage";
|
||||||
|
import { CancelIcon, LogoutIcon } from "@shared/icons";
|
||||||
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { relaunch } from "@tauri-apps/api/process";
|
||||||
|
import { Fragment, useState } from "react";
|
||||||
|
|
||||||
|
export function Logout() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
setIsOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const openModal = () => {
|
||||||
|
setIsOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const logout = async () => {
|
||||||
|
// reset database
|
||||||
|
await removeAll();
|
||||||
|
// reset react query
|
||||||
|
queryClient.clear();
|
||||||
|
// navigate
|
||||||
|
await relaunch();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => openModal()}
|
||||||
|
aria-label="Logout"
|
||||||
|
className="inline-flex items-center justify-center w-9 h-9 rounded-md border-t bg-zinc-800 border-zinc-700/50 transform active:translate-y-1"
|
||||||
|
>
|
||||||
|
<LogoutIcon className="w-4 h-4 text-zinc-400" />
|
||||||
|
</button>
|
||||||
|
<Transition appear show={isOpen} as={Fragment}>
|
||||||
|
<Dialog as="div" className="relative z-10" onClose={closeModal}>
|
||||||
|
<Transition.Child
|
||||||
|
as={Fragment}
|
||||||
|
enter="ease-out duration-300"
|
||||||
|
enterFrom="opacity-0"
|
||||||
|
enterTo="opacity-100"
|
||||||
|
leave="ease-in duration-200"
|
||||||
|
leaveFrom="opacity-100"
|
||||||
|
leaveTo="opacity-0"
|
||||||
|
>
|
||||||
|
<div className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md" />
|
||||||
|
</Transition.Child>
|
||||||
|
<div className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
|
||||||
|
<Transition.Child
|
||||||
|
as={Fragment}
|
||||||
|
enter="ease-out duration-300"
|
||||||
|
enterFrom="opacity-0 scale-95"
|
||||||
|
enterTo="opacity-100 scale-100"
|
||||||
|
leave="ease-in duration-200"
|
||||||
|
leaveFrom="opacity-100 scale-100"
|
||||||
|
leaveTo="opacity-0 scale-95"
|
||||||
|
>
|
||||||
|
<Dialog.Panel className="relative flex h-min w-full max-w-lg flex-col rounded-xl border-t border-zinc-800/50 bg-zinc-900">
|
||||||
|
<div className="h-min w-full shrink-0 border-b border-zinc-800 px-5 py-6">
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Dialog.Title
|
||||||
|
as="h3"
|
||||||
|
className="text-lg font-semibold leading-none text-zinc-100"
|
||||||
|
>
|
||||||
|
Are you sure!
|
||||||
|
</Dialog.Title>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={closeModal}
|
||||||
|
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-900"
|
||||||
|
>
|
||||||
|
<CancelIcon
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
className="text-zinc-300"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<Dialog.Description className="text-sm leading-tight text-zinc-400">
|
||||||
|
<p className="mb-2">
|
||||||
|
When logout, all local data will be wiped, and restart
|
||||||
|
app then you need to start onboarding process again when
|
||||||
|
you log in.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In the next version, Lume will support multi account,
|
||||||
|
then you can switch between all account s instead of
|
||||||
|
logout
|
||||||
|
</p>
|
||||||
|
</Dialog.Description>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex h-full w-full flex-col items-end justify-center overflow-y-auto px-5 py-2.5">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={closeModal}
|
||||||
|
className="inline-flex h-9 items-center justify-center rounded-md px-3 text-sm font-medium text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => logout()}
|
||||||
|
className="inline-flex h-9 items-center justify-center rounded-md bg-red-500 px-3 text-sm font-medium text-zinc-100 hover:bg-red-600"
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dialog.Panel>
|
||||||
|
</Transition.Child>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</Transition>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -1,68 +1,30 @@
|
|||||||
import { Transition } from "@headlessui/react";
|
|
||||||
import { getActiveAccount } from "@libs/storage";
|
|
||||||
import { ActiveAccount } from "@shared/accounts/active";
|
import { ActiveAccount } from "@shared/accounts/active";
|
||||||
import { VerticalDotsIcon } from "@shared/icons";
|
import { SettingsIcon } from "@shared/icons";
|
||||||
import { RelayManager } from "@shared/relayManager";
|
import { Logout } from "@shared/logout";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { Notification } from "@shared/notification";
|
||||||
import { useState } from "react";
|
import { useAccount } from "@utils/hooks/useAccount";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
export function LumeBar() {
|
export function LumeBar() {
|
||||||
const { status, data: activeAccount } = useQuery(
|
const { status, account } = useAccount();
|
||||||
["activeAccount"],
|
|
||||||
async () => {
|
|
||||||
return await getActiveAccount();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
|
|
||||||
const toggleMenu = () => {
|
|
||||||
setOpen((isOpen) => !isOpen);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-2 rounded-xl p-2 border-t border-zinc-800/50 bg-zinc-900/80 backdrop-blur-md">
|
<div className="rounded-xl p-2 border-t border-zinc-800/50 bg-zinc-900/80 backdrop-blur-md">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-2">
|
{status === "loading" ? (
|
||||||
{status === "loading" ? (
|
<div className="group relative flex h-9 w-9 shrink animate-pulse items-center justify-center rounded-md bg-zinc-900" />
|
||||||
<div className="group relative flex h-9 w-9 shrink animate-pulse items-center justify-center rounded-md bg-zinc-900" />
|
) : (
|
||||||
) : (
|
<ActiveAccount data={account} />
|
||||||
<ActiveAccount data={activeAccount} />
|
)}
|
||||||
)}
|
<Notification />
|
||||||
<RelayManager />
|
<Link
|
||||||
</div>
|
to="/settings/general"
|
||||||
<button
|
className="inline-flex items-center justify-center w-9 h-9 rounded-md border-t bg-zinc-800 border-zinc-700/50 transform active:translate-y-1"
|
||||||
type="button"
|
|
||||||
onClick={() => toggleMenu()}
|
|
||||||
className="inline-flex items-center justify-center w-5 h-5 rounded hover:bg-zinc-800"
|
|
||||||
>
|
>
|
||||||
<VerticalDotsIcon className="w-4 h-4 text-zinc-100" />
|
<SettingsIcon className="w-4 h-4 text-zinc-400" />
|
||||||
</button>
|
</Link>
|
||||||
|
<Logout />
|
||||||
</div>
|
</div>
|
||||||
<Transition
|
|
||||||
show={open}
|
|
||||||
enter="transition-transform ease-in-out duration-75"
|
|
||||||
enterFrom="translate-y-16"
|
|
||||||
enterTo="translate-y-0"
|
|
||||||
leave="transition-transform ease-in-out duration-150"
|
|
||||||
leaveFrom="translate-y-0"
|
|
||||||
leaveTo="translate-y-16"
|
|
||||||
className="flex flex-col items-start justify-start gap-1 pt-1.5 border-t border-zinc-800 transform"
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
to="/app/settings"
|
|
||||||
className="w-full py-2 px-2 rounded hover:bg-zinc-800 text-zinc-100 text-start text-sm"
|
|
||||||
>
|
|
||||||
Settings
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
to="/app/logout"
|
|
||||||
className="w-full py-2 px-2 rounded hover:bg-zinc-800 text-zinc-100 text-start text-sm"
|
|
||||||
>
|
|
||||||
Logout
|
|
||||||
</Link>
|
|
||||||
</Transition>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,10 @@ import { LumeBar } from "@shared/lumeBar";
|
|||||||
import { NavLink } from "react-router-dom";
|
import { NavLink } from "react-router-dom";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
export function Navigation({ reverse = false }: { reverse?: boolean }) {
|
export function Navigation() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="relative flex w-[232px] flex-col gap-3 border-r border-zinc-900">
|
||||||
className={`relative flex w-[232px] flex-col gap-3 ${
|
<AppHeader />
|
||||||
reverse ? "border-l" : "border-r"
|
|
||||||
} border-zinc-900`}
|
|
||||||
>
|
|
||||||
<AppHeader reverse={reverse} />
|
|
||||||
<div className="pb-20 flex flex-col gap-5 overflow-y-auto scrollbar-hide">
|
<div className="pb-20 flex flex-col gap-5 overflow-y-auto scrollbar-hide">
|
||||||
<div className="inlin-lflex h-8 px-3.5">
|
<div className="inlin-lflex h-8 px-3.5">
|
||||||
<Composer />
|
<Composer />
|
||||||
@ -117,7 +113,7 @@ export function Navigation({ reverse = false }: { reverse?: boolean }) {
|
|||||||
)}
|
)}
|
||||||
</Disclosure>
|
</Disclosure>
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute bottom-3 left-0 px-8 w-full">
|
<div className="absolute bottom-3 left-0 px-10 w-full">
|
||||||
<LumeBar />
|
<LumeBar />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
58
src/shared/notification.tsx
Normal file
58
src/shared/notification.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
|
import { BellIcon } from "@shared/icons";
|
||||||
|
import { Fragment, useState } from "react";
|
||||||
|
|
||||||
|
export function Notification() {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
setIsOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const openModal = () => {
|
||||||
|
setIsOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => openModal()}
|
||||||
|
aria-label="Notification"
|
||||||
|
className="inline-flex items-center justify-center w-9 h-9 rounded-md border-t bg-zinc-800 border-zinc-700/50 transform active:translate-y-1"
|
||||||
|
>
|
||||||
|
<BellIcon className="w-4 h-4 text-zinc-400" />
|
||||||
|
</button>
|
||||||
|
<Transition appear show={isOpen} as={Fragment}>
|
||||||
|
<Dialog as="div" className="relative z-10" onClose={closeModal}>
|
||||||
|
<Transition.Child
|
||||||
|
as={Fragment}
|
||||||
|
enter="ease-out duration-300"
|
||||||
|
enterFrom="opacity-0"
|
||||||
|
enterTo="opacity-100"
|
||||||
|
leave="ease-in duration-200"
|
||||||
|
leaveFrom="opacity-100"
|
||||||
|
leaveTo="opacity-0"
|
||||||
|
>
|
||||||
|
<div className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md" />
|
||||||
|
</Transition.Child>
|
||||||
|
<div className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
|
||||||
|
<Transition.Child
|
||||||
|
as={Fragment}
|
||||||
|
enter="ease-out duration-300"
|
||||||
|
enterFrom="opacity-0 scale-95"
|
||||||
|
enterTo="opacity-100 scale-100"
|
||||||
|
leave="ease-in duration-200"
|
||||||
|
leaveFrom="opacity-100 scale-100"
|
||||||
|
leaveTo="opacity-0 scale-95"
|
||||||
|
>
|
||||||
|
<Dialog.Panel className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-lg border-t border-zinc-800/50 bg-zinc-900">
|
||||||
|
<p>OK</p>
|
||||||
|
</Dialog.Panel>
|
||||||
|
</Transition.Child>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</Transition>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
import { SignalIcon } from "@shared/icons";
|
|
||||||
|
|
||||||
export function RelayManager() {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
aria-label="Relay manager"
|
|
||||||
className="inline-flex items-center justify-center w-9 h-9 rounded-md border-t bg-zinc-800 border-zinc-700/50 transform active:translate-y-1"
|
|
||||||
>
|
|
||||||
<SignalIcon className="w-4 h-4 text-zinc-400" />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
74
src/shared/settingsLayout.tsx
Normal file
74
src/shared/settingsLayout.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { AppHeader } from "@shared/appHeader";
|
||||||
|
import { NavLink, Outlet, ScrollRestoration } from "react-router-dom";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
|
export function SettingsLayout() {
|
||||||
|
return (
|
||||||
|
<div className="flex w-screen h-screen">
|
||||||
|
<div className="relative flex flex-row shrink-0">
|
||||||
|
<div className="relative flex w-[232px] flex-col gap-3 border-r border-zinc-900">
|
||||||
|
<AppHeader />
|
||||||
|
<div className="pb-20 flex flex-col gap-5 overflow-y-auto scrollbar-hide">
|
||||||
|
<div className="flex flex-col gap-0.5 px-1.5">
|
||||||
|
<div className="px-2.5">
|
||||||
|
<h3 className="text-[11px] font-bold uppercase tracking-widest text-zinc-600">
|
||||||
|
Settings
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<NavLink
|
||||||
|
to="/settings/general"
|
||||||
|
className={({ isActive }) =>
|
||||||
|
twMerge(
|
||||||
|
"flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200",
|
||||||
|
isActive ? "bg-zinc-900/50" : "",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="font-medium">General</span>
|
||||||
|
</NavLink>
|
||||||
|
<NavLink
|
||||||
|
to="/settings/shortcuts"
|
||||||
|
className={({ isActive }) =>
|
||||||
|
twMerge(
|
||||||
|
"flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200",
|
||||||
|
isActive ? "bg-zinc-900/50" : "",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="font-medium">Shortcuts</span>
|
||||||
|
</NavLink>
|
||||||
|
<NavLink
|
||||||
|
to="/settings/account"
|
||||||
|
className={({ isActive }) =>
|
||||||
|
twMerge(
|
||||||
|
"flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200",
|
||||||
|
isActive ? "bg-zinc-900/50" : "",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="font-medium">Account</span>
|
||||||
|
</NavLink>
|
||||||
|
<NavLink
|
||||||
|
to="/settings/update"
|
||||||
|
className={({ isActive }) =>
|
||||||
|
twMerge(
|
||||||
|
"flex h-9 items-center gap-2.5 rounded-md px-2.5 text-zinc-200",
|
||||||
|
isActive ? "bg-zinc-900/50" : "",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="font-medium">Update</span>
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full h-full">
|
||||||
|
<Outlet />
|
||||||
|
<ScrollRestoration />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user