chore: refactoring store impl
This commit is contained in:
parent
58527eae71
commit
511338850e
15 changed files with 205 additions and 66 deletions
|
@ -2,6 +2,6 @@
|
|||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 120,
|
||||
"printWidth": 160,
|
||||
"tailwindFunction": ["clsx"]
|
||||
}
|
||||
|
|
|
@ -74,11 +74,13 @@
|
|||
"remesh": "^4.2.0",
|
||||
"remesh-logger": "^4.1.0",
|
||||
"remesh-react": "^4.1.0",
|
||||
"remesh-yjs": "^4.1.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"sonner": "^1.2.4",
|
||||
"tailwind-merge": "^2.0.0",
|
||||
"type-fest": "^4.8.2",
|
||||
"valibot": "^0.21.0"
|
||||
"valibot": "^0.21.0",
|
||||
"y-webrtc": "^10.2.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^18.4.3",
|
||||
|
|
101
pnpm-lock.yaml
101
pnpm-lock.yaml
|
@ -98,6 +98,9 @@ dependencies:
|
|||
remesh-react:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0(react-dom@18.2.0)(react@18.2.0)(remesh@4.2.0)(rxjs@7.8.1)
|
||||
remesh-yjs:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0(remesh@4.2.0)(rxjs@7.8.1)
|
||||
rxjs:
|
||||
specifier: ^7.8.1
|
||||
version: 7.8.1
|
||||
|
@ -113,6 +116,9 @@ dependencies:
|
|||
valibot:
|
||||
specifier: ^0.21.0
|
||||
version: 0.21.0
|
||||
y-webrtc:
|
||||
specifier: ^10.2.6
|
||||
version: 10.2.6(yjs@13.6.10)
|
||||
|
||||
devDependencies:
|
||||
'@commitlint/cli':
|
||||
|
@ -2631,7 +2637,6 @@ packages:
|
|||
|
||||
/base64-js@1.5.1:
|
||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||
dev: true
|
||||
|
||||
/big-integer@1.6.52:
|
||||
resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
|
||||
|
@ -2717,7 +2722,6 @@ packages:
|
|||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
ieee754: 1.2.1
|
||||
dev: true
|
||||
|
||||
/builtin-modules@3.3.0:
|
||||
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
|
||||
|
@ -3505,6 +3509,10 @@ packages:
|
|||
engines: {node: '>=0.12'}
|
||||
dev: true
|
||||
|
||||
/err-code@3.0.1:
|
||||
resolution: {integrity: sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==}
|
||||
dev: false
|
||||
|
||||
/error-ex@1.3.2:
|
||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||
dependencies:
|
||||
|
@ -4259,6 +4267,10 @@ packages:
|
|||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/get-browser-rtc@1.1.0:
|
||||
resolution: {integrity: sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==}
|
||||
dev: false
|
||||
|
||||
/get-caller-file@2.0.5:
|
||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
|
@ -4657,7 +4669,6 @@ packages:
|
|||
|
||||
/ieee754@1.2.1:
|
||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||
dev: true
|
||||
|
||||
/ignore@5.3.0:
|
||||
resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==}
|
||||
|
@ -5075,6 +5086,10 @@ packages:
|
|||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||
dev: true
|
||||
|
||||
/isomorphic.js@0.2.5:
|
||||
resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==}
|
||||
dev: false
|
||||
|
||||
/iterator.prototype@1.1.2:
|
||||
resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
|
||||
dependencies:
|
||||
|
@ -5227,6 +5242,14 @@ packages:
|
|||
type-check: 0.4.0
|
||||
dev: true
|
||||
|
||||
/lib0@0.2.88:
|
||||
resolution: {integrity: sha512-KyroiEvCeZcZEMx5Ys+b4u4eEBbA1ch7XUaBhYpwa/nPMrzTjUhI4RfcytmQfYoTBPcdyx+FX6WFNIoNuJzJfQ==}
|
||||
engines: {node: '>=16'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
isomorphic.js: 0.2.5
|
||||
dev: false
|
||||
|
||||
/lie@3.3.0:
|
||||
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
|
||||
dependencies:
|
||||
|
@ -6750,6 +6773,12 @@ packages:
|
|||
resolution: {integrity: sha512-pNsHDxbGORSvuSScqNJ+3Km6QAVqk8CfsCBIEoDgpqLrkD2f3QM4I7d1ozJJ172OmIcoUcerZaNWqtLkRXTV3A==}
|
||||
dev: true
|
||||
|
||||
/randombytes@2.1.0:
|
||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/rc9@2.1.1:
|
||||
resolution: {integrity: sha512-lNeOl38Ws0eNxpO3+wD1I9rkHGQyj1NU1jlzv4go2CtEnEQEUfqnIvZG7W+bC/aXdJ27n5x/yUjb6RoT9tko+Q==}
|
||||
dependencies:
|
||||
|
@ -6973,7 +7002,6 @@ packages:
|
|||
inherits: 2.0.4
|
||||
string_decoder: 1.3.0
|
||||
util-deprecate: 1.0.2
|
||||
dev: true
|
||||
|
||||
/readdirp@3.6.0:
|
||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||
|
@ -7124,6 +7152,18 @@ packages:
|
|||
use-sync-external-store: 1.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/remesh-yjs@4.1.0(remesh@4.2.0)(rxjs@7.8.1):
|
||||
resolution: {integrity: sha512-yyV1GcANEo8aqaZTYG4swVQEkKTEWd2ZTzCC/GLhFJH7BFOegBIMTEmfWDINacKWvTtb8D4Sps/eGX8TCPBhjw==}
|
||||
peerDependencies:
|
||||
remesh: ^4.0.0
|
||||
rxjs: ^7.0.0
|
||||
dependencies:
|
||||
remesh: 4.2.0(rxjs@7.8.1)
|
||||
rxjs: 7.8.1
|
||||
tslib: 2.6.2
|
||||
yjs: 13.6.10
|
||||
dev: false
|
||||
|
||||
/remesh@4.2.0(rxjs@7.8.1):
|
||||
resolution: {integrity: sha512-t2xwtFYnEwrcWddxtEb/NF7kR+x62Er52gfk+sCa4HmaQC+J5zg41pYZz6TTl4PrDghs2et1tr1dYZpbYGAu6g==}
|
||||
engines: {node: '>=14.x'}
|
||||
|
@ -7314,7 +7354,6 @@ packages:
|
|||
|
||||
/safe-buffer@5.2.1:
|
||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||
dev: true
|
||||
|
||||
/safe-json-stringify@1.2.0:
|
||||
resolution: {integrity: sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==}
|
||||
|
@ -7470,6 +7509,20 @@ packages:
|
|||
engines: {node: '>=14'}
|
||||
dev: true
|
||||
|
||||
/simple-peer@9.11.1:
|
||||
resolution: {integrity: sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==}
|
||||
dependencies:
|
||||
buffer: 6.0.3
|
||||
debug: 4.3.4
|
||||
err-code: 3.0.1
|
||||
get-browser-rtc: 1.1.0
|
||||
queue-microtask: 1.2.3
|
||||
randombytes: 2.1.0
|
||||
readable-stream: 3.6.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/sisteransi@1.0.5:
|
||||
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
||||
dev: true
|
||||
|
@ -7703,7 +7756,6 @@ packages:
|
|||
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: true
|
||||
|
||||
/strip-ansi@6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
|
@ -8627,7 +8679,6 @@ packages:
|
|||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
dev: true
|
||||
|
||||
/wxt@0.10.3(@types/node@20.10.1)(idb-keyval@6.2.1):
|
||||
resolution: {integrity: sha512-2IDbcx/em7T7+f0IJN1D3Y4Hvsb34bRyOwz8nx/vTXaoysoOHG7SsR/BowTNkX0DPxUUjCdaJpzmxeWy0dHUNQ==}
|
||||
|
@ -8710,6 +8761,35 @@ packages:
|
|||
engines: {node: '>=4.0'}
|
||||
dev: true
|
||||
|
||||
/y-protocols@1.0.6(yjs@13.6.10):
|
||||
resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==}
|
||||
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
|
||||
peerDependencies:
|
||||
yjs: ^13.0.0
|
||||
dependencies:
|
||||
lib0: 0.2.88
|
||||
yjs: 13.6.10
|
||||
dev: false
|
||||
|
||||
/y-webrtc@10.2.6(yjs@13.6.10):
|
||||
resolution: {integrity: sha512-1kZ4YYwksFZi8+l8mTebVX9vW6Q5MnqxMkvNU700X5dBE38usurt/JgeXSIQRpK3NwUYYb9y63Jn9FMpMH6/vA==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
yjs: ^13.6.8
|
||||
dependencies:
|
||||
lib0: 0.2.88
|
||||
simple-peer: 9.11.1
|
||||
y-protocols: 1.0.6(yjs@13.6.10)
|
||||
yjs: 13.6.10
|
||||
optionalDependencies:
|
||||
ws: 8.14.2
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/y18n@5.0.8:
|
||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -8750,6 +8830,13 @@ packages:
|
|||
yargs-parser: 21.1.1
|
||||
dev: true
|
||||
|
||||
/yjs@13.6.10:
|
||||
resolution: {integrity: sha512-1JcyQek1vaMyrDm7Fqfa+pvHg/DURSbVo4VmeN7wjnTKB/lZrfIPhdCj7d8sboK6zLfRBJXegTjc9JlaDd8/Zw==}
|
||||
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
|
||||
dependencies:
|
||||
lib0: 0.2.88
|
||||
dev: false
|
||||
|
||||
/yocto-queue@0.1.0:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
|
@ -4,16 +4,24 @@ import { Remesh } from 'remesh'
|
|||
import { RemeshRoot } from 'remesh-react'
|
||||
import { RemeshLogger } from 'remesh-logger'
|
||||
import { defineContentScript, createContentScriptUi } from 'wxt/client'
|
||||
import * as Y from 'yjs'
|
||||
import { RemeshYjs, RemeshYjsExtern } from 'remesh-yjs'
|
||||
import { WebrtcProvider } from 'y-webrtc'
|
||||
import App from './App'
|
||||
import { StorageIndexDBImpl } from '@/impl/Storage'
|
||||
import { IndexDBStorageImpl, BrowserSyncStorageImpl } from '@/impl/Storage'
|
||||
|
||||
import '@/assets/styles/tailwind.css'
|
||||
|
||||
export default defineContentScript({
|
||||
cssInjectionMode: 'ui',
|
||||
matches: ['*://*.example.com/*', '*://*.google.com/*', '*://*.v2ex.com/*'],
|
||||
async main(ctx) {
|
||||
const doc = new Y.Doc()
|
||||
// eslint-disable-next-line no-new
|
||||
new WebrtcProvider(__NAME__, doc)
|
||||
|
||||
const store = Remesh.store({
|
||||
externs: [StorageIndexDBImpl],
|
||||
externs: [IndexDBStorageImpl, BrowserSyncStorageImpl, RemeshYjsExtern.impl({ doc })],
|
||||
inspectors: [RemeshLogger()]
|
||||
})
|
||||
|
||||
|
|
|
@ -2,16 +2,21 @@ import { type ReactNode, type FC, useState, type MouseEvent, useRef } from 'reac
|
|||
import { SettingsIcon, MoonIcon, SunIcon } from 'lucide-react'
|
||||
import { useClickAway } from 'react-use'
|
||||
import { browser } from 'wxt/browser'
|
||||
import { useRemeshDomain, useRemeshQuery } from 'remesh-react'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { EVENTS } from '@/constants'
|
||||
import UserInfoDomain from '@/domain/UserInfo'
|
||||
|
||||
export interface AppButtonProps {
|
||||
children?: ReactNode
|
||||
}
|
||||
|
||||
const AppButton: FC<AppButtonProps> = ({ children }) => {
|
||||
const userInfoDomain = useRemeshDomain(UserInfoDomain())
|
||||
const userInfo = useRemeshQuery(userInfoDomain.query.UserInfoQuery())
|
||||
console.log(userInfo)
|
||||
|
||||
const [open, setOpen] = useState(false)
|
||||
const [isDarkMode, setIsDarkMode] = useState(window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
|
||||
const menuRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { object, string, type Output, minBytes, maxBytes, toTrimmed, union, literal, notLength } from 'valibot'
|
||||
import { type Output, object, string, minBytes, maxBytes, toTrimmed, union, literal, notLength, number } from 'valibot'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { valibotResolver } from '@hookform/resolvers/valibot'
|
||||
|
||||
|
@ -19,24 +19,24 @@ import { Label } from '@/components/ui/Label'
|
|||
// Image is encoded as base64, and the size is increased by about 33%.
|
||||
const COMPRESS_SIZE = 8 * 1024 - 8 * 1024 * 0.33
|
||||
|
||||
const formSchema = object({
|
||||
id: string(),
|
||||
name: string([
|
||||
toTrimmed(),
|
||||
minBytes(1, 'Please enter your username.'),
|
||||
maxBytes(20, 'Your username cannot exceed 20 bytes.')
|
||||
]),
|
||||
avatar: string([notLength(0, 'Please select your avatar.'), maxBytes(8 * 1024, 'Your avatar cannot exceed 8kb.')]),
|
||||
themeMode: union([literal('system'), literal('light'), literal('dark')])
|
||||
})
|
||||
|
||||
const defaultUserInfo: UserInfo = {
|
||||
id: nanoid(),
|
||||
name: '',
|
||||
avatar: '',
|
||||
createTime: Date.now(),
|
||||
themeMode: checkSystemDarkMode() ? 'dark' : 'system'
|
||||
}
|
||||
|
||||
const formSchema = object({
|
||||
id: string(),
|
||||
createTime: number(),
|
||||
// Pure numeric strings will be converted to number
|
||||
// Issues: https://github.com/unjs/unstorage/issues/277
|
||||
name: string([toTrimmed(), minBytes(1, 'Please enter your username.'), maxBytes(20, 'Your username cannot exceed 20 bytes.')]),
|
||||
avatar: string([notLength(0, 'Please select your avatar.'), maxBytes(8 * 1024, 'Your avatar cannot exceed 8kb.')]),
|
||||
themeMode: union([literal('system'), literal('light'), literal('dark')], 'Please select extension theme mode.')
|
||||
})
|
||||
|
||||
const ProfileForm = () => {
|
||||
const send = useRemeshSend()
|
||||
const userInfoDomain = useRemeshDomain(UserInfoDomain())
|
||||
|
@ -73,13 +73,7 @@ const ProfileForm = () => {
|
|||
render={({ field }) => (
|
||||
<FormItem className="absolute left-1/2 top-0 grid -translate-x-1/2 -translate-y-1/2 justify-items-center">
|
||||
<FormControl>
|
||||
<AvatarSelect
|
||||
compressSize={COMPRESS_SIZE}
|
||||
onError={handleError}
|
||||
onWarning={handleWarning}
|
||||
className="shadow-lg"
|
||||
{...field}
|
||||
></AvatarSelect>
|
||||
<AvatarSelect compressSize={COMPRESS_SIZE} onError={handleError} onWarning={handleWarning} className="shadow-lg" {...field}></AvatarSelect>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
@ -121,9 +115,7 @@ const ProfileForm = () => {
|
|||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
The theme mode of the extension. If you choose the system, will follow the system theme.
|
||||
</FormDescription>
|
||||
<FormDescription>The theme mode of the extension. If you choose the system, will follow the system theme.</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
|
|
|
@ -4,11 +4,11 @@ import { Remesh } from 'remesh'
|
|||
import { RemeshRoot } from 'remesh-react'
|
||||
import { RemeshLogger } from 'remesh-logger'
|
||||
import App from './App'
|
||||
import { StorageBrowserSyncImpl } from '@/impl/Storage'
|
||||
import { BrowserSyncStorageImpl } from '@/impl/Storage'
|
||||
import '@/assets/styles/tailwind.css'
|
||||
|
||||
const store = Remesh.store({
|
||||
externs: [StorageBrowserSyncImpl],
|
||||
externs: [BrowserSyncStorageImpl],
|
||||
inspectors: [RemeshLogger()]
|
||||
})
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@ import { Remesh } from 'remesh'
|
|||
import { ListModule } from 'remesh/modules/list'
|
||||
import { nanoid } from 'nanoid'
|
||||
import { from, map, tap, merge } from 'rxjs'
|
||||
import Storage from './externs/Storage'
|
||||
import { IndexDBStorageExtern } from './externs/Storage'
|
||||
|
||||
const MessageListDomain = Remesh.domain({
|
||||
name: 'MessageListDomain',
|
||||
impl: (domain) => {
|
||||
const storage = domain.getExtern(Storage)
|
||||
const storage = domain.getExtern(IndexDBStorageExtern)
|
||||
const storageKey = `MESSAGE_LIST` as const
|
||||
|
||||
const MessageListModule = ListModule<Message>(domain, {
|
||||
|
@ -92,9 +92,7 @@ const MessageListDomain = Remesh.domain({
|
|||
domain.effect({
|
||||
name: 'FormStateToStorageEffect',
|
||||
impl: ({ fromEvent }) => {
|
||||
const changeList$ = fromEvent(ChangeListEvent).pipe(
|
||||
tap(async (messages) => await storage.set<Message[]>(storageKey, messages))
|
||||
)
|
||||
const changeList$ = fromEvent(ChangeListEvent).pipe(tap(async (messages) => await storage.set<Message[]>(storageKey, messages)))
|
||||
return merge(changeList$).pipe(map(() => null))
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import { Remesh } from 'remesh'
|
||||
import { forkJoin, from, map, merge, tap } from 'rxjs'
|
||||
import Storage from './externs/Storage'
|
||||
import { isEmpty } from '@/utils'
|
||||
import { BrowserSyncStorageExtern } from './externs/Storage'
|
||||
import { isNullish } from '@/utils'
|
||||
|
||||
const UserInfoDomain = Remesh.domain({
|
||||
name: 'UserInfoDomain',
|
||||
impl: (domain) => {
|
||||
const storage = domain.getExtern(Storage)
|
||||
const storage = domain.getExtern(BrowserSyncStorageExtern)
|
||||
const storageKeys = {
|
||||
USER_INFO_ID: 'USER_INFO_ID',
|
||||
USER_INFO_NAME: 'USER_INFO_NAME',
|
||||
USER_INFO_AVATAR: 'USER_INFO_AVATAR',
|
||||
USER_INFO_CREATE_TIME: 'USER_INFO_CREATE_TIME',
|
||||
USER_INFO_THEME_MODE: 'USER_INFO_THEME_MODE'
|
||||
} as const
|
||||
|
||||
|
@ -29,12 +30,12 @@ const UserInfoDomain = Remesh.domain({
|
|||
const SetUserInfoCommand = domain.command({
|
||||
name: 'UserInfo.SetUserInfoCommand',
|
||||
impl: (_, userInfo: UserInfo | null) => {
|
||||
return [UserInfoState().new(userInfo), ChangeUserInfoEvent()]
|
||||
return [UserInfoState().new(userInfo), UpdateUserInfoEvent()]
|
||||
}
|
||||
})
|
||||
|
||||
const ChangeUserInfoEvent = domain.event({
|
||||
name: 'UserInfo.ChangeUserInfoEvent',
|
||||
const UpdateUserInfoEvent = domain.event({
|
||||
name: 'UserInfo.UpdateUserInfoEvent',
|
||||
impl: ({ get }) => {
|
||||
return get(UserInfoQuery())
|
||||
}
|
||||
|
@ -47,14 +48,16 @@ const UserInfoDomain = Remesh.domain({
|
|||
id: from(storage.get<UserInfo['id']>(storageKeys.USER_INFO_ID)),
|
||||
name: from(storage.get<UserInfo['name']>(storageKeys.USER_INFO_NAME)),
|
||||
avatar: from(storage.get<UserInfo['avatar']>(storageKeys.USER_INFO_AVATAR)),
|
||||
createTime: from(storage.get<UserInfo['createTime']>(storageKeys.USER_INFO_CREATE_TIME)),
|
||||
themeMode: from(storage.get<UserInfo['themeMode']>(storageKeys.USER_INFO_THEME_MODE))
|
||||
}).pipe(
|
||||
map((userInfo) => {
|
||||
if (
|
||||
!isEmpty(userInfo.id) &&
|
||||
!isEmpty(userInfo.name) &&
|
||||
!isEmpty(userInfo.avatar) &&
|
||||
!isEmpty(userInfo.themeMode)
|
||||
!isNullish(userInfo.id) &&
|
||||
!isNullish(userInfo.name) &&
|
||||
!isNullish(userInfo.avatar) &&
|
||||
!isNullish(userInfo.createTime) &&
|
||||
!isNullish(userInfo.themeMode)
|
||||
) {
|
||||
return SetUserInfoCommand(userInfo as UserInfo)
|
||||
} else {
|
||||
|
@ -68,12 +71,13 @@ const UserInfoDomain = Remesh.domain({
|
|||
domain.effect({
|
||||
name: 'FormStateToStorageEffect',
|
||||
impl: ({ fromEvent }) => {
|
||||
const changeUserInfo$ = fromEvent(ChangeUserInfoEvent).pipe(
|
||||
const changeUserInfo$ = fromEvent(UpdateUserInfoEvent).pipe(
|
||||
tap(async (userInfo) => {
|
||||
return await Promise.all([
|
||||
storage.set<UserInfo['id'] | null>(storageKeys.USER_INFO_ID, userInfo?.id ?? null),
|
||||
storage.set<UserInfo['name'] | null>(storageKeys.USER_INFO_NAME, userInfo?.name ?? null),
|
||||
storage.set<UserInfo['avatar'] | null>(storageKeys.USER_INFO_AVATAR, userInfo?.avatar ?? null),
|
||||
storage.set<UserInfo['createTime'] | null>(storageKeys.USER_INFO_CREATE_TIME, userInfo?.createTime ?? null),
|
||||
storage.set<UserInfo['themeMode'] | null>(storageKeys.USER_INFO_THEME_MODE, userInfo?.themeMode ?? null)
|
||||
])
|
||||
})
|
||||
|
@ -91,7 +95,7 @@ const UserInfoDomain = Remesh.domain({
|
|||
SetUserInfoCommand
|
||||
},
|
||||
event: {
|
||||
ChangeUserInfoEvent
|
||||
UpdateUserInfoEvent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
import { Remesh } from 'remesh'
|
||||
import { type Promisable } from 'type-fest'
|
||||
|
||||
export type StorageValue = null | string | number | boolean | object
|
||||
export type WatchEvent = 'update' | 'remove'
|
||||
export type WatchCallback = (event: WatchEvent, key: string) => any
|
||||
export type Unwatch = () => Promisable<void>
|
||||
|
||||
export interface Storage {
|
||||
name: string
|
||||
get: <T extends StorageValue>(key: string) => Promise<T | null>
|
||||
set: <T extends StorageValue>(key: string, value: T) => Promise<void>
|
||||
remove: (key: string) => Promise<void>
|
||||
clear: () => Promise<void>
|
||||
watch: (callback: WatchCallback) => Promise<Unwatch>
|
||||
unwatch: Unwatch
|
||||
}
|
||||
|
||||
const StorageExtern = Remesh.extern<Storage>({
|
||||
export const IndexDBStorageExtern = Remesh.extern<Storage>({
|
||||
default: {
|
||||
name: 'STORAGE',
|
||||
get: async () => {
|
||||
|
@ -18,10 +25,41 @@ const StorageExtern = Remesh.extern<Storage>({
|
|||
set: async () => {
|
||||
throw new Error('"set" not implemented')
|
||||
},
|
||||
remove: async () => {
|
||||
throw new Error('"remove" not implemented')
|
||||
},
|
||||
clear: async () => {
|
||||
throw new Error('"clear" not implemented')
|
||||
},
|
||||
watch: () => {
|
||||
throw new Error('"watch" not implemented')
|
||||
},
|
||||
unwatch: () => {
|
||||
throw new Error('"unwatch" not implemented')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default StorageExtern
|
||||
export const BrowserSyncStorageExtern = Remesh.extern<Storage>({
|
||||
default: {
|
||||
name: 'STORAGE',
|
||||
get: async () => {
|
||||
throw new Error('"get" not implemented')
|
||||
},
|
||||
set: async () => {
|
||||
throw new Error('"set" not implemented')
|
||||
},
|
||||
remove: async () => {
|
||||
throw new Error('"remove" not implemented')
|
||||
},
|
||||
clear: async () => {
|
||||
throw new Error('"clear" not implemented')
|
||||
},
|
||||
watch: () => {
|
||||
throw new Error('"watch" not implemented')
|
||||
},
|
||||
unwatch: () => {
|
||||
throw new Error('"unwatch" not implemented')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import indexedDbDriver from 'unstorage/drivers/indexedb'
|
||||
import { webExtensionDriver, createStorage } from 'wxt/storage'
|
||||
import StorageExtern from '@/domain/externs/Storage'
|
||||
import { IndexDBStorageExtern, BrowserSyncStorageExtern } from '@/domain/externs/Storage'
|
||||
import { STORAGE_NAME } from '@/constants'
|
||||
|
||||
const indexDBStorage = createStorage({
|
||||
|
@ -11,16 +11,22 @@ const browserSyncStorage = createStorage({
|
|||
driver: webExtensionDriver({ storageArea: 'sync' })
|
||||
})
|
||||
|
||||
export const StorageIndexDBImpl = StorageExtern.impl({
|
||||
export const IndexDBStorageImpl = IndexDBStorageExtern.impl({
|
||||
name: STORAGE_NAME,
|
||||
get: indexDBStorage.getItem,
|
||||
set: indexDBStorage.setItem,
|
||||
clear: indexDBStorage.clear
|
||||
remove: indexDBStorage.removeItem,
|
||||
clear: indexDBStorage.clear,
|
||||
watch: indexDBStorage.watch,
|
||||
unwatch: indexDBStorage.unwatch
|
||||
})
|
||||
|
||||
export const StorageBrowserSyncImpl = StorageExtern.impl({
|
||||
export const BrowserSyncStorageImpl = BrowserSyncStorageExtern.impl({
|
||||
name: STORAGE_NAME,
|
||||
get: browserSyncStorage.getItem,
|
||||
set: browserSyncStorage.setItem,
|
||||
clear: browserSyncStorage.clear
|
||||
remove: browserSyncStorage.removeItem,
|
||||
clear: browserSyncStorage.clear,
|
||||
watch: browserSyncStorage.watch,
|
||||
unwatch: browserSyncStorage.unwatch
|
||||
})
|
||||
|
|
1
src/types/global.d.ts
vendored
1
src/types/global.d.ts
vendored
|
@ -17,5 +17,6 @@ declare interface UserInfo {
|
|||
id: string
|
||||
name: string
|
||||
avatar: string
|
||||
createTime: number
|
||||
themeMode: 'system' | 'light' | 'dark'
|
||||
}
|
||||
|
|
|
@ -5,5 +5,5 @@ export { default as createElement } from './createElement'
|
|||
export { default as getSiteInfo } from './getSiteInfo'
|
||||
export { default as chunk } from './chunk'
|
||||
export { default as compressImage } from './compressImage'
|
||||
export { default as isEmpty } from './isEmpty'
|
||||
export { default as isNullish } from './isNullish'
|
||||
export { default as checkSystemDarkMode } from './checkSystemDarkMode'
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
const isEmpty = (value: any) => {
|
||||
return value === undefined || value === null
|
||||
}
|
||||
|
||||
export default isEmpty
|
3
src/utils/isNullish.ts
Normal file
3
src/utils/isNullish.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
const isNullish = (value: any) => value === undefined || value === null
|
||||
|
||||
export default isNullish
|
Loading…
Reference in a new issue