fix(setup): setup page display timing is incorrect
This commit is contained in:
parent
cc3424d4d8
commit
f6277bcc83
7 changed files with 362 additions and 90 deletions
|
@ -9,6 +9,8 @@ import { stringToHex } from '@/utils'
|
||||||
import { Toaster } from '@/components/ui/Sonner'
|
import { Toaster } from '@/components/ui/Sonner'
|
||||||
import UserInfoDomain from '@/domain/UserInfo'
|
import UserInfoDomain from '@/domain/UserInfo'
|
||||||
import Setup from '@/app/content/views/Setup'
|
import Setup from '@/app/content/views/Setup'
|
||||||
|
import MessageListDomain from '@/domain/MessageList'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
const hostRoomId = stringToHex(document.location.host)
|
const hostRoomId = stringToHex(document.location.host)
|
||||||
|
|
||||||
|
@ -16,15 +18,31 @@ export default function App() {
|
||||||
const send = useRemeshSend()
|
const send = useRemeshSend()
|
||||||
const roomDomain = useRemeshDomain(RoomDomain())
|
const roomDomain = useRemeshDomain(RoomDomain())
|
||||||
const userInfoDomain = useRemeshDomain(UserInfoDomain())
|
const userInfoDomain = useRemeshDomain(UserInfoDomain())
|
||||||
send(roomDomain.command.JoinRoomCommand(hostRoomId))
|
const messageListDomain = useRemeshDomain(MessageListDomain())
|
||||||
const isLogin = useRemeshQuery(userInfoDomain.query.IsLoginQuery())
|
const joinRoomFinished = useRemeshQuery(roomDomain.query.IsFinishedQuery())
|
||||||
|
const userInfoFinished = useRemeshQuery(userInfoDomain.query.IsFinishedQuery())
|
||||||
|
|
||||||
|
const userInfo = useRemeshQuery(userInfoDomain.query.UserInfoQuery())
|
||||||
|
|
||||||
|
const notUserInfo = userInfoFinished && !userInfo
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (userInfoFinished) {
|
||||||
|
if (userInfo) {
|
||||||
|
!joinRoomFinished && send(roomDomain.command.JoinRoomCommand(hostRoomId))
|
||||||
|
} else {
|
||||||
|
send(messageListDomain.command.ClearListCommand())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [userInfoFinished, userInfo, joinRoomFinished])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AppContainer>
|
<AppContainer>
|
||||||
<Header />
|
<Header />
|
||||||
<Main />
|
<Main />
|
||||||
<Footer />
|
<Footer />
|
||||||
{!isLogin && <Setup />}
|
{notUserInfo && <Setup />}
|
||||||
</AppContainer>
|
</AppContainer>
|
||||||
<AppButton></AppButton>
|
<AppButton></AppButton>
|
||||||
<Toaster richColors offset="104px" position="top-center"></Toaster>
|
<Toaster richColors offset="104px" position="top-center"></Toaster>
|
||||||
|
|
|
@ -18,7 +18,7 @@ export default defineContentScript({
|
||||||
async main(ctx) {
|
async main(ctx) {
|
||||||
const store = Remesh.store({
|
const store = Remesh.store({
|
||||||
externs: [IndexDBStorageImpl, BrowserSyncStorageImpl, PeerRoomImpl],
|
externs: [IndexDBStorageImpl, BrowserSyncStorageImpl, PeerRoomImpl],
|
||||||
inspectors: [RemeshLogger()]
|
inspectors: __DEV__ ? [RemeshLogger()] : []
|
||||||
})
|
})
|
||||||
|
|
||||||
const ui = await createShadowRootUi(ctx, {
|
const ui = await createShadowRootUi(ctx, {
|
||||||
|
|
|
@ -76,17 +76,18 @@ const Setup: FC = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
send(messageListDomain.command.ClearListCommand())
|
|
||||||
const timer = new Timer(
|
const timer = new Timer(
|
||||||
async () => {
|
async () => {
|
||||||
const userInfo = await refreshUserInfo()
|
await createMessage(await refreshUserInfo())
|
||||||
await createMessage(userInfo)
|
|
||||||
},
|
},
|
||||||
{ delay: 2000, immediate: true, limit: mockTextList.length }
|
{ delay: 2000, immediate: true, limit: mockTextList.length }
|
||||||
)
|
)
|
||||||
|
|
||||||
timer.start()
|
timer.start()
|
||||||
return () => timer.stop()
|
return () => {
|
||||||
|
timer.stop()
|
||||||
|
send(messageListDomain.command.ClearListCommand())
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
return (
|
return (
|
||||||
<div className="absolute inset-0 z-50 flex rounded-xl bg-black/10 shadow-2xl backdrop-blur-sm">
|
<div className="absolute inset-0 z-50 flex rounded-xl bg-black/10 shadow-2xl backdrop-blur-sm">
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { Remesh } from 'remesh'
|
import { Remesh } from 'remesh'
|
||||||
import { map, merge, tap } from 'rxjs'
|
import { map, merge, switchMap, tap, defer, of, EMPTY, mergeMap } from 'rxjs'
|
||||||
import { type MessageUser } from './MessageList'
|
import { type MessageUser } from './MessageList'
|
||||||
import { PeerRoomExtern } from '@/domain/externs/PeerRoom'
|
import { PeerRoomExtern } from '@/domain/externs/PeerRoom'
|
||||||
import MessageListDomain from '@/domain/MessageList'
|
import MessageListDomain from '@/domain/MessageList'
|
||||||
import UserInfoDomain from '@/domain/UserInfo'
|
import UserInfoDomain from '@/domain/UserInfo'
|
||||||
import { callbackToObservable, desert } from '@/utils'
|
import { callbackToObservable, desert } from '@/utils'
|
||||||
import { nanoid } from 'nanoid'
|
import { nanoid } from 'nanoid'
|
||||||
|
import StatusModule from './modules/Status'
|
||||||
|
|
||||||
export enum MessageType {
|
export enum MessageType {
|
||||||
Like = 'like',
|
Like = 'like',
|
||||||
|
@ -40,6 +41,10 @@ const RoomDomain = Remesh.domain({
|
||||||
|
|
||||||
const MessageListQuery = messageListDomain.query.ListQuery
|
const MessageListQuery = messageListDomain.query.ListQuery
|
||||||
|
|
||||||
|
const RoomStatusState = StatusModule(domain, {
|
||||||
|
name: 'Room.RoomStatusModule'
|
||||||
|
})
|
||||||
|
|
||||||
const PeerListState = domain.state<string[]>({
|
const PeerListState = domain.state<string[]>({
|
||||||
name: 'Room.PeerListState',
|
name: 'Room.PeerListState',
|
||||||
default: [peerRoom.selfId]
|
default: [peerRoom.selfId]
|
||||||
|
@ -56,15 +61,15 @@ const RoomDomain = Remesh.domain({
|
||||||
name: 'RoomJoinRoomCommand',
|
name: 'RoomJoinRoomCommand',
|
||||||
impl: (_, roomId: string) => {
|
impl: (_, roomId: string) => {
|
||||||
peerRoom.joinRoom(roomId)
|
peerRoom.joinRoom(roomId)
|
||||||
return [JoinRoomEvent(peerRoom.selfId)]
|
return [JoinRoomEvent(roomId), RoomStatusState.command.SetFinishedCommand()]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const LeaveRoomCommand = domain.command({
|
const LeaveRoomCommand = domain.command({
|
||||||
name: 'RoomLeaveRoomCommand',
|
name: 'RoomLeaveRoomCommand',
|
||||||
impl: (_) => {
|
impl: (_, roomId: string) => {
|
||||||
peerRoom.leaveRoom()
|
peerRoom.leaveRoom()
|
||||||
return [LeaveRoomEvent(peerRoom.selfId)]
|
return [LeaveRoomEvent(roomId), RoomStatusState.command.SetInitialCommand()]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -156,6 +161,18 @@ const RoomDomain = Remesh.domain({
|
||||||
name: 'RoomLeaveRoomEvent'
|
name: 'RoomLeaveRoomEvent'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const OnMessageEvent = domain.event<RoomMessage>({
|
||||||
|
name: 'RoomOnMessageEvent'
|
||||||
|
})
|
||||||
|
|
||||||
|
const OnJoinRoomEvent = domain.event<string>({
|
||||||
|
name: 'RoomOnJoinRoomEvent'
|
||||||
|
})
|
||||||
|
|
||||||
|
const OnLeaveRoomEvent = domain.event<string>({
|
||||||
|
name: 'RoomOnLeaveRoomEvent'
|
||||||
|
})
|
||||||
|
|
||||||
const UpdatePeerListCommand = domain.command({
|
const UpdatePeerListCommand = domain.command({
|
||||||
name: 'RoomUpdatePeerListCommand',
|
name: 'RoomUpdatePeerListCommand',
|
||||||
impl: ({ get }, action: { type: 'create' | 'delete'; peerId: string }) => {
|
impl: ({ get }, action: { type: 'create' | 'delete'; peerId: string }) => {
|
||||||
|
@ -208,106 +225,111 @@ const RoomDomain = Remesh.domain({
|
||||||
|
|
||||||
domain.effect({
|
domain.effect({
|
||||||
name: 'RoomOnMessageEffect',
|
name: 'RoomOnMessageEffect',
|
||||||
impl: ({ get }) => {
|
impl: ({ fromEvent, get }) => {
|
||||||
const onMessage$ = callbackToObservable<RoomMessage>(peerRoom.onMessage.bind(peerRoom))
|
const onMessage$ = fromEvent(JoinRoomEvent).pipe(
|
||||||
return onMessage$.pipe(
|
switchMap(() => callbackToObservable<RoomMessage>(peerRoom.onMessage.bind(peerRoom))),
|
||||||
map((message) => {
|
mergeMap((message) => {
|
||||||
switch (message.type) {
|
console.log('onMessage', message)
|
||||||
case 'text':
|
|
||||||
return messageListDomain.command.CreateItemCommand({
|
const messageEvent$ = of(OnMessageEvent(message))
|
||||||
...message,
|
|
||||||
date: Date.now(),
|
const commandEvent$ = (() => {
|
||||||
likeUsers: [],
|
switch (message.type) {
|
||||||
hateUsers: []
|
case 'text':
|
||||||
})
|
return of(
|
||||||
case 'like': {
|
messageListDomain.command.CreateItemCommand({
|
||||||
if (!get(messageListDomain.query.HasItemQuery(message.id))) {
|
...message,
|
||||||
return null
|
date: Date.now(),
|
||||||
}
|
likeUsers: [],
|
||||||
const _message = get(messageListDomain.query.ItemQuery(message.id))
|
hateUsers: []
|
||||||
return messageListDomain.command.UpdateItemCommand({
|
})
|
||||||
..._message,
|
|
||||||
likeUsers: desert(
|
|
||||||
_message.likeUsers,
|
|
||||||
{
|
|
||||||
userId: message.userId,
|
|
||||||
username: message.username,
|
|
||||||
userAvatar: message.userAvatar
|
|
||||||
},
|
|
||||||
'userId'
|
|
||||||
)
|
)
|
||||||
})
|
case 'like':
|
||||||
}
|
case 'hate': {
|
||||||
case 'hate': {
|
if (!get(messageListDomain.query.HasItemQuery(message.id))) {
|
||||||
if (!get(messageListDomain.query.HasItemQuery(message.id))) {
|
return EMPTY
|
||||||
return null
|
}
|
||||||
}
|
const _message = get(messageListDomain.query.ItemQuery(message.id))
|
||||||
const _message = get(messageListDomain.query.ItemQuery(message.id))
|
const users = message.type === 'like' ? 'likeUsers' : 'hateUsers'
|
||||||
return messageListDomain.command.UpdateItemCommand({
|
return of(
|
||||||
..._message,
|
messageListDomain.command.UpdateItemCommand({
|
||||||
hateUsers: desert(
|
..._message,
|
||||||
_message.hateUsers,
|
[users]: desert(
|
||||||
{
|
_message[users],
|
||||||
userId: message.userId,
|
{
|
||||||
username: message.username,
|
userId: message.userId,
|
||||||
userAvatar: message.userAvatar
|
username: message.username,
|
||||||
},
|
userAvatar: message.userAvatar
|
||||||
'userId'
|
},
|
||||||
|
'userId'
|
||||||
|
)
|
||||||
|
})
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
|
default:
|
||||||
|
console.warn('未知消息类型', message)
|
||||||
|
return EMPTY
|
||||||
}
|
}
|
||||||
default:
|
})()
|
||||||
console.warn('unknown message type', message)
|
return merge(messageEvent$, commandEvent$)
|
||||||
return null
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
return onMessage$
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
domain.effect({
|
domain.effect({
|
||||||
name: 'RoomOnJoinRoomEffect',
|
name: 'RoomOnJoinRoomEffect',
|
||||||
impl: () => {
|
impl: ({ fromEvent }) => {
|
||||||
const onJoinRoom$ = callbackToObservable<string>(peerRoom.onJoinRoom.bind(peerRoom))
|
const onJoinRoom$ = fromEvent(JoinRoomEvent).pipe(
|
||||||
return onJoinRoom$.pipe(
|
switchMap(() => callbackToObservable<string>(peerRoom.onJoinRoom.bind(peerRoom))),
|
||||||
map((peerId) => {
|
map((peerId) => {
|
||||||
console.log('onJoinRoom', peerId)
|
console.log('onJoinRoom', peerId)
|
||||||
return [UpdatePeerListCommand({ type: 'create', peerId }), JoinRoomEvent(peerId)]
|
return [UpdatePeerListCommand({ type: 'create', peerId }), OnJoinRoomEvent(peerId)]
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
return onJoinRoom$
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
domain.effect({
|
domain.effect({
|
||||||
name: 'RoomOnLeaveRoomEffect',
|
name: 'RoomOnLeaveRoomEffect',
|
||||||
impl: () => {
|
impl: ({ fromEvent }) => {
|
||||||
const onLeaveRoom$ = callbackToObservable<string>(peerRoom.onLeaveRoom.bind(peerRoom))
|
const onLeaveRoom$ = fromEvent(JoinRoomEvent).pipe(
|
||||||
return onLeaveRoom$.pipe(
|
switchMap(() => callbackToObservable<string>(peerRoom.onLeaveRoom.bind(peerRoom))),
|
||||||
map((peerId) => {
|
map((peerId) => {
|
||||||
console.log('onLeaveRoom', peerId)
|
console.log('onLeaveRoom', peerId)
|
||||||
return [UpdatePeerListCommand({ type: 'delete', peerId }), LeaveRoomEvent(peerId)]
|
return [UpdatePeerListCommand({ type: 'delete', peerId }), OnLeaveRoomEvent(peerId)]
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
return onLeaveRoom$
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
query: {
|
query: {
|
||||||
PeerListQuery,
|
PeerListQuery,
|
||||||
MessageListQuery
|
MessageListQuery,
|
||||||
|
...RoomStatusState.query
|
||||||
},
|
},
|
||||||
event: {
|
event: {
|
||||||
SendTextMessageEvent,
|
SendTextMessageEvent,
|
||||||
SendLikeMessageEvent,
|
SendLikeMessageEvent,
|
||||||
SendHateMessageEvent,
|
SendHateMessageEvent,
|
||||||
JoinRoomEvent,
|
JoinRoomEvent,
|
||||||
LeaveRoomEvent
|
LeaveRoomEvent,
|
||||||
|
OnMessageEvent,
|
||||||
|
OnJoinRoomEvent,
|
||||||
|
OnLeaveRoomEvent,
|
||||||
|
...RoomStatusState.event
|
||||||
},
|
},
|
||||||
command: {
|
command: {
|
||||||
JoinRoomCommand,
|
JoinRoomCommand,
|
||||||
LeaveRoomCommand,
|
LeaveRoomCommand,
|
||||||
SendTextMessageCommand,
|
SendTextMessageCommand,
|
||||||
SendLikeMessageCommand,
|
SendLikeMessageCommand,
|
||||||
SendHateMessageCommand
|
SendHateMessageCommand,
|
||||||
|
...RoomStatusState.command
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Remesh } from 'remesh'
|
import { Remesh } from 'remesh'
|
||||||
import { BrowserSyncStorageExtern } from '@/domain/externs/Storage'
|
import { BrowserSyncStorageExtern } from '@/domain/externs/Storage'
|
||||||
import StorageEffect from '@/domain/modules/StorageEffect'
|
import StorageEffect from '@/domain/modules/StorageEffect'
|
||||||
|
import StatusModule from './modules/Status'
|
||||||
|
|
||||||
export interface UserInfo {
|
export interface UserInfo {
|
||||||
id: string
|
id: string
|
||||||
|
@ -26,6 +27,10 @@ const UserInfoDomain = Remesh.domain({
|
||||||
default: null
|
default: null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const UserInfoStatusModule = StatusModule(domain, {
|
||||||
|
name: 'UserInfo.StatusModule'
|
||||||
|
})
|
||||||
|
|
||||||
const UserInfoQuery = domain.query({
|
const UserInfoQuery = domain.query({
|
||||||
name: 'UserInfo.UserInfoQuery',
|
name: 'UserInfo.UserInfoQuery',
|
||||||
impl: ({ get }) => {
|
impl: ({ get }) => {
|
||||||
|
@ -33,17 +38,17 @@ const UserInfoDomain = Remesh.domain({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const IsLoginQuery = domain.query({
|
|
||||||
name: 'UserInfo.IsLoginQuery',
|
|
||||||
impl: ({ get }) => {
|
|
||||||
return !!get(UserInfoState())?.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const UpdateUserInfoCommand = domain.command({
|
const UpdateUserInfoCommand = domain.command({
|
||||||
name: 'UserInfo.UpdateUserInfoCommand',
|
name: 'UserInfo.UpdateUserInfoCommand',
|
||||||
impl: (_, userInfo: UserInfo | null) => {
|
impl: (_, userInfo: UserInfo | null) => {
|
||||||
return [UserInfoState().new(userInfo), UpdateUserInfoEvent(), SyncToStorageEvent()]
|
return [
|
||||||
|
UserInfoState().new(userInfo),
|
||||||
|
UpdateUserInfoEvent(),
|
||||||
|
SyncToStorageEvent(),
|
||||||
|
userInfo
|
||||||
|
? UserInfoStatusModule.command.SetFinishedCommand()
|
||||||
|
: UserInfoStatusModule.command.SetInitialCommand()
|
||||||
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -74,21 +79,25 @@ const UserInfoDomain = Remesh.domain({
|
||||||
|
|
||||||
storageEffect
|
storageEffect
|
||||||
.set(SyncToStorageEvent)
|
.set(SyncToStorageEvent)
|
||||||
.get<UserInfo>((value) => SyncToStateCommand(value))
|
.get<UserInfo>((value) => {
|
||||||
.watch<UserInfo>((value) => SyncToStateCommand(value!))
|
return [SyncToStateCommand(value), UserInfoStatusModule.command.SetFinishedCommand()]
|
||||||
|
})
|
||||||
|
.watch<UserInfo>((value) => [SyncToStateCommand(value)])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
query: {
|
query: {
|
||||||
UserInfoQuery,
|
UserInfoQuery,
|
||||||
IsLoginQuery
|
...UserInfoStatusModule.query
|
||||||
},
|
},
|
||||||
command: {
|
command: {
|
||||||
UpdateUserInfoCommand
|
UpdateUserInfoCommand,
|
||||||
|
...UserInfoStatusModule.command
|
||||||
},
|
},
|
||||||
event: {
|
event: {
|
||||||
SyncToStateEvent,
|
SyncToStateEvent,
|
||||||
SyncToStorageEvent,
|
SyncToStorageEvent,
|
||||||
UpdateUserInfoEvent
|
UpdateUserInfoEvent,
|
||||||
|
...UserInfoStatusModule.event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
102
src/domain/modules/Status.ts
Normal file
102
src/domain/modules/Status.ts
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
import { DomainConceptName, RemeshDomainContext } from 'remesh'
|
||||||
|
|
||||||
|
export enum Status {
|
||||||
|
Initial = 0b001, // 1
|
||||||
|
Loading = 0b010, // 2
|
||||||
|
Finished = 0b100 // 4
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StatusOptions {
|
||||||
|
name: DomainConceptName<'StatusModule'>
|
||||||
|
default?: Status
|
||||||
|
}
|
||||||
|
|
||||||
|
const StatusModule = (domain: RemeshDomainContext, options: StatusOptions) => {
|
||||||
|
const StatusState = domain.state({
|
||||||
|
name: `${options.name}.StatusState`,
|
||||||
|
default: options.default ?? Status.Initial
|
||||||
|
})
|
||||||
|
|
||||||
|
const StatusQuery = domain.query({
|
||||||
|
name: `${options.name}.StatusQuery`,
|
||||||
|
impl: ({ get }) => {
|
||||||
|
return get(StatusState())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const IsInitialQuery = domain.query({
|
||||||
|
name: `${options.name}.IsInitialQuery`,
|
||||||
|
impl: ({ get }) => {
|
||||||
|
const state = get(StatusState())
|
||||||
|
return (state & Status.Initial) !== 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const IsLoadingQuery = domain.query({
|
||||||
|
name: `${options.name}.IsLoadingQuery`,
|
||||||
|
impl: ({ get }) => {
|
||||||
|
const state = get(StatusState())
|
||||||
|
return (state & Status.Loading) !== 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const IsFinishedQuery = domain.query({
|
||||||
|
name: `${options.name}.IsFinishedQuery`,
|
||||||
|
impl: ({ get }) => {
|
||||||
|
const state = get(StatusState())
|
||||||
|
return (state & Status.Finished) !== 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const UpdateStatusEvent = domain.event<Status>({
|
||||||
|
name: `${options.name}.UpdateStatusEvent`
|
||||||
|
})
|
||||||
|
|
||||||
|
const SetInitialCommand = domain.command({
|
||||||
|
name: `${options.name}.SetInitialCommand`,
|
||||||
|
impl: () => {
|
||||||
|
return [StatusState().new(Status.Initial), UpdateStatusEvent(Status.Initial)]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const SetLoadingCommand = domain.command({
|
||||||
|
name: `${options.name}.SetLoadingCommand`,
|
||||||
|
impl: () => {
|
||||||
|
return [StatusState().new(Status.Loading), UpdateStatusEvent(Status.Loading)]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const SetFinishedCommand = domain.command({
|
||||||
|
name: `${options.name}.SetFinishedCommand`,
|
||||||
|
impl: () => {
|
||||||
|
return [StatusState().new(Status.Finished), UpdateStatusEvent(Status.Finished)]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const UpdateStatusCommand = domain.command({
|
||||||
|
name: `${options.name}.UpdateStatusCommand`,
|
||||||
|
impl: (_, status: Status) => {
|
||||||
|
return [StatusState().new(status), UpdateStatusEvent(status)]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
query: {
|
||||||
|
StatusQuery,
|
||||||
|
IsInitialQuery,
|
||||||
|
IsLoadingQuery,
|
||||||
|
IsFinishedQuery
|
||||||
|
},
|
||||||
|
command: {
|
||||||
|
SetInitialCommand,
|
||||||
|
SetLoadingCommand,
|
||||||
|
SetFinishedCommand,
|
||||||
|
UpdateStatusCommand
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
UpdateStatusEvent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StatusModule
|
|
@ -57,8 +57,83 @@ function createAvatarSvg() {
|
||||||
'rgb(165, 42, 42)', // Red
|
'rgb(165, 42, 42)', // Red
|
||||||
'rgb(145, 85, 61)', // Auburn
|
'rgb(145, 85, 61)', // Auburn
|
||||||
'rgb(128, 128, 128)', // Grey
|
'rgb(128, 128, 128)', // Grey
|
||||||
'rgb(185, 55, 55)' // Fire
|
'rgb(185, 55, 55)', // Fire
|
||||||
// ... 其他颜色
|
'rgb(255, 192, 203)', // Pastel Pink
|
||||||
|
'rgb(255, 105, 180)', // Bright Pink
|
||||||
|
'rgb(230, 230, 250)', // Lavender
|
||||||
|
'rgb(64, 224, 208)', // Turquoise
|
||||||
|
'rgb(0, 191, 255)', // Bright Blue
|
||||||
|
'rgb(148, 0, 211)', // Deep Purple
|
||||||
|
'rgb(50, 205, 50)', // Lime Green
|
||||||
|
'rgb(255, 165, 0)', // Vivid Orange
|
||||||
|
'rgb(220, 20, 60)', // Crimson Red
|
||||||
|
'rgb(192, 192, 192)', // Silver
|
||||||
|
'rgb(255, 215, 0)', // Gold
|
||||||
|
'rgb(255, 255, 255)', // White
|
||||||
|
'rgb(124, 252, 0)', // Lawn Green
|
||||||
|
'rgb(127, 255, 0)', // Chartreuse
|
||||||
|
'rgb(0, 255, 127)', // Spring Green
|
||||||
|
'rgb(72, 209, 204)', // Medium Turquoise
|
||||||
|
'rgb(0, 255, 255)', // Cyan
|
||||||
|
'rgb(0, 206, 209)', // Dark Turquoise
|
||||||
|
'rgb(32, 178, 170)', // Light Sea Green
|
||||||
|
'rgb(95, 158, 160)', // Cadet Blue
|
||||||
|
'rgb(70, 130, 180)', // Steel Blue
|
||||||
|
'rgb(176, 196, 222)', // Light Steel Blue
|
||||||
|
'rgb(30, 144, 255)', // Dodger Blue
|
||||||
|
'rgb(135, 206, 235)', // Sky Blue
|
||||||
|
'rgb(0, 0, 139)', // Dark Blue
|
||||||
|
'rgb(138, 43, 226)', // Blue Violet
|
||||||
|
'rgb(75, 0, 130)', // Indigo
|
||||||
|
'rgb(139, 0, 139)', // Dark Magenta
|
||||||
|
'rgb(153, 50, 204)', // Dark Orchid
|
||||||
|
'rgb(186, 85, 211)', // Medium Orchid
|
||||||
|
'rgb(218, 112, 214)', // Orchid
|
||||||
|
'rgb(221, 160, 221)', // Plum
|
||||||
|
'rgb(238, 130, 238)', // Violet
|
||||||
|
'rgb(255, 0, 255)', // Magenta
|
||||||
|
'rgb(216, 191, 216)', // Thistle
|
||||||
|
'rgb(255, 20, 147)', // Deep Pink
|
||||||
|
'rgb(255, 69, 0)', // Orange Red
|
||||||
|
'rgb(255, 140, 0)', // Dark Orange
|
||||||
|
'rgb(255, 165, 0)', // Orange
|
||||||
|
'rgb(250, 128, 114)', // Salmon
|
||||||
|
'rgb(233, 150, 122)', // Dark Salmon
|
||||||
|
'rgb(240, 128, 128)', // Light Coral
|
||||||
|
'rgb(205, 92, 92)', // Indian Red
|
||||||
|
'rgb(255, 99, 71)', // Tomato
|
||||||
|
'rgb(255, 160, 122)', // Light Salmon
|
||||||
|
'rgb(220, 20, 60)', // Crimson
|
||||||
|
'rgb(139, 0, 0)', // Dark Red
|
||||||
|
'rgb(178, 34, 34)', // Fire Brick
|
||||||
|
'rgb(250, 235, 215)', // Antique White
|
||||||
|
'rgb(255, 239, 213)', // Papaya Whip
|
||||||
|
'rgb(255, 235, 205)', // Blanched Almond
|
||||||
|
'rgb(255, 222, 173)', // Navajo White
|
||||||
|
'rgb(245, 245, 220)', // Beige
|
||||||
|
'rgb(255, 228, 196)', // Bisque
|
||||||
|
'rgb(255, 218, 185)', // Peach Puff
|
||||||
|
'rgb(244, 164, 96)', // Sandy Brown
|
||||||
|
'rgb(210, 180, 140)', // Tan
|
||||||
|
'rgb(222, 184, 135)', // Burly Wood
|
||||||
|
'rgb(250, 250, 210)', // Light Goldenrod Yellow
|
||||||
|
'rgb(255, 250, 205)', // Lemon Chiffon
|
||||||
|
'rgb(255, 245, 238)', // Sea Shell
|
||||||
|
'rgb(253, 245, 230)', // Old Lace
|
||||||
|
'rgb(255, 228, 225)', // Misty Rose
|
||||||
|
'rgb(255, 240, 245)', // Lavender Blush
|
||||||
|
'rgb(250, 240, 230)', // Linen
|
||||||
|
'rgb(255, 228, 181)', // Moccasin
|
||||||
|
'rgb(255, 250, 250)', // Snow
|
||||||
|
'rgb(240, 255, 255)', // Azure
|
||||||
|
'rgb(240, 255, 240)', // Honeydew
|
||||||
|
'rgb(245, 245, 245)', // White Smoke
|
||||||
|
'rgb(245, 255, 250)', // Mint Cream
|
||||||
|
'rgb(240, 248, 255)', // Alice Blue
|
||||||
|
'rgb(240, 248, 255)', // Ghost White
|
||||||
|
'rgb(248, 248, 255)', // Ghost White
|
||||||
|
'rgb(255, 250, 240)', // Floral White
|
||||||
|
'rgb(253, 245, 230)' // Old Lace
|
||||||
],
|
],
|
||||||
hairColor: 'black',
|
hairColor: 'black',
|
||||||
dyeColorOffset: '50%',
|
dyeColorOffset: '50%',
|
||||||
|
@ -72,8 +147,54 @@ function createAvatarSvg() {
|
||||||
'rgb(188, 143, 143)', // Dusty Rose
|
'rgb(188, 143, 143)', // Dusty Rose
|
||||||
'rgb(135, 206, 235)', // Sky Blue
|
'rgb(135, 206, 235)', // Sky Blue
|
||||||
'rgb(245, 255, 250)', // Mint Cream
|
'rgb(245, 255, 250)', // Mint Cream
|
||||||
'rgb(245, 222, 179)' // Wheat
|
'rgb(245, 222, 179)', // Wheat
|
||||||
// ... 其他颜色
|
'rgb(47, 79, 79)', // Dark Slate Gray
|
||||||
|
'rgb(72, 61, 139)', // Dark Slate Blue
|
||||||
|
'rgb(60, 20, 20)', // Dark Brown
|
||||||
|
'rgb(25, 25, 112)', // Midnight Blue
|
||||||
|
'rgb(139, 0, 0)', // Dark Red
|
||||||
|
'rgb(85, 107, 47)', // Olive Drab
|
||||||
|
'rgb(128, 0, 128)', // Purple
|
||||||
|
'rgb(0, 100, 0)', // Dark Green
|
||||||
|
'rgb(0, 0, 139)', // Dark Blue
|
||||||
|
'rgb(105, 105, 105)', // Dim Gray
|
||||||
|
'rgb(240, 128, 128)', // Light Coral
|
||||||
|
'rgb(255, 160, 122)', // Light Salmon
|
||||||
|
'rgb(255, 218, 185)', // Peach Puff
|
||||||
|
'rgb(255, 228, 196)', // Bisque
|
||||||
|
'rgb(255, 222, 173)', // Navajo White
|
||||||
|
'rgb(255, 250, 205)', // Lemon Chiffon
|
||||||
|
'rgb(250, 250, 210)', // Light Goldenrod Yellow
|
||||||
|
'rgb(255, 239, 213)', // Papaya Whip
|
||||||
|
'rgb(255, 245, 238)', // Sea Shell
|
||||||
|
'rgb(255, 248, 220)', // Cornsilk
|
||||||
|
'rgb(255, 255, 240)', // Ivory
|
||||||
|
'rgb(240, 255, 240)', // Honeydew
|
||||||
|
'rgb(240, 255, 255)', // Azure
|
||||||
|
'rgb(240, 248, 255)', // Alice Blue
|
||||||
|
'rgb(248, 248, 255)', // Ghost White
|
||||||
|
'rgb(255, 250, 250)', // Snow
|
||||||
|
'rgb(255, 240, 245)', // Lavender Blush
|
||||||
|
'rgb(255, 228, 225)', // Misty Rose
|
||||||
|
'rgb(230, 230, 250)', // Lavender
|
||||||
|
'rgb(216, 191, 216)', // Thistle
|
||||||
|
'rgb(221, 160, 221)', // Plum
|
||||||
|
'rgb(238, 130, 238)', // Violet
|
||||||
|
'rgb(218, 112, 214)', // Orchid
|
||||||
|
'rgb(186, 85, 211)', // Medium Orchid
|
||||||
|
'rgb(147, 112, 219)', // Medium Purple
|
||||||
|
'rgb(138, 43, 226)', // Blue Violet
|
||||||
|
'rgb(148, 0, 211)', // Dark Violet
|
||||||
|
'rgb(153, 50, 204)', // Dark Orchid
|
||||||
|
'rgb(139, 69, 19)', // Saddle Brown
|
||||||
|
'rgb(160, 82, 45)', // Sienna
|
||||||
|
'rgb(210, 105, 30)', // Chocolate
|
||||||
|
'rgb(205, 133, 63)', // Peru
|
||||||
|
'rgb(244, 164, 96)', // Sandy Brown
|
||||||
|
'rgb(222, 184, 135)', // Burly Wood
|
||||||
|
'rgb(255, 250, 240)', // Floral White
|
||||||
|
'rgb(253, 245, 230)', // Old Lace
|
||||||
|
'rgb(250, 240, 230)' // Linen
|
||||||
],
|
],
|
||||||
mouthPoints: []
|
mouthPoints: []
|
||||||
}
|
}
|
||||||
|
@ -250,7 +371,6 @@ function createAvatarSvg() {
|
||||||
return createElement(svgTemplate)
|
return createElement(svgTemplate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出函数
|
|
||||||
export default function generateUglyAvatar() {
|
export default function generateUglyAvatar() {
|
||||||
const svgElement = createAvatarSvg()
|
const svgElement = createAvatarSvg()
|
||||||
const serializer = new XMLSerializer()
|
const serializer = new XMLSerializer()
|
||||||
|
|
Loading…
Reference in a new issue