import isMobileUI from "../utils/isMobileUI.ts" import useEventListener from "../utils/useEventListener.ts" import AvatarMySelf from "./AvatarMySelf.tsx" import MainSharedContext from './MainSharedContext.ts' import * as React from 'react' import { createBrowserRouter, Outlet, RouterProvider, useNavigate, useRouteError } from "react-router" import LoginDialog from "./main-page/LoginDialog.tsx" import useAsyncEffect from "../utils/useAsyncEffect.ts" import performAuth from "../performAuth.ts" import { CallbackError, Chat, UserMySelf } from "lingchair-client-protocol" import showCircleProgressDialog from "./showCircleProgressDialog.ts" import RegisterDialog from "./main-page/RegisterDialog.tsx" import sleep from "../utils/sleep.ts" import { $, dialog, NavigationDrawer } from "mdui" import getClient from "../getClient.ts" import showSnackbar from "../utils/showSnackbar.ts" import AllChatsList from "./main-page/AllChatsList.tsx" import FavouriteChatsList from "./main-page/FavouriteChatsList.tsx" import RecentChatsList from "./main-page/RecentChatsList.tsx" import UserOrChatInfoDialog from "./routers/UserOrChatInfoDialog.tsx" import UserOrChatInfoDialogLoader from "./routers/UserOrChatInfoDialogDataLoader.ts" import ChatInfoDialogDataLoader from "./routers/ChatInfoDialogDataLoader.ts" import ChatFragmentDialog from "./routers/ChatFragmentDialog.tsx" import EffectOnly from "./EffectOnly.tsx" import MainSharedReducer from "./MainSharedReducer.ts" import gotoUserInfo from "./routers/gotoUserInfo.ts" import EditMyProfileDialog from "./routers/EditMyProfileDialog.tsx" import ProgressDialogFallback from "./ProgressDialogFallback.tsx" import Split from 'split.js' import data from "../data.ts" import LazyChatFragment from "./chat-fragment/LazyChatFragment.tsx" import AddFavourtieChatDialog from "./routers/AddFavourtieChatDialog.tsx" import RouterDialogsContextWrapper from './routers/RouterDialogsContextWrapper.tsx' function Root() { const [myProfileCache, setMyProfileCache] = React.useState() // 多页面切换 const navigationRef = React.useRef() const [currentShowPage, setCurrentShowPage] = React.useState('Recents') type HTMLElementWithValue = HTMLElement & { value: string } useEventListener(navigationRef, 'change', (event) => { setCurrentShowPage((event.target as HTMLElementWithValue).value) }) const drawerRef = React.useRef() React.useEffect(() => { $(drawerRef.current!.shadowRoot).append(` `) }, []) const [showLoginDialog, setShowLoginDialog] = React.useState(false) const [showRegisterDialog, setShowRegisterDialog] = React.useState(false) const nav = useNavigate() const [state, dispatch] = React.useReducer(MainSharedReducer, { favouriteChats: [], currentSelectedChatId: '', }) const sharedContext = { functions_lazy: React.useRef({ updateFavouriteChats: () => { }, updateRecentChats: () => { }, updateAllChats: () => { }, }), state, setFavouriteChats: (chats: Chat[]) => dispatch({ type: 'update_favourite_chat', data: chats }), setShowLoginDialog, setShowRegisterDialog, setCurrentSelectedChatId: (id: string) => dispatch({ type: 'update_selected_chat_id', data: id }), } useAsyncEffect(async () => { const waitingForAuth = showCircleProgressDialog("加载中...") try { await performAuth({}) try { setMyProfileCache(await UserMySelf.getMySelfOrThrow(getClient())) } catch (e) { if (e instanceof CallbackError) showSnackbar({ message: '获取资料失败: ' + e.message }) } } catch (e) { if (e instanceof CallbackError) if (e.code == 401 || e.code == 400) setShowLoginDialog(true) } // 动画都没来得及, 稍微等一下 ( await sleep(100) waitingForAuth.open = false }) React.useEffect(() => { if (!isMobileUI()) { const split = Split(['#SideBar', '#ChatFragment'], { sizes: data.split_sizes ? data.split_sizes : [25, 75], minSize: [200, 400], gutterSize: 2, onDragEnd: function () { data.split_sizes = split.getSizes() data.apply() } }) } }, []) return (
{ // 将子路由渲染到此处 } gotoUserInfo(nav, myProfileCache!.getId())}> {myProfileCache?.getNickName()} 账号设置 客户端设置 nav('/add/favourite_chat')}>添加收藏对话 创建新的群组
LingChair Web v{__APP_VERSION__}
Build: {__GIT_HASH__} ({__BUILD_TIME__})
在 Codeberg 上查看源代码
{ /** * Default: 侧边列表提供列表切换 */ !isMobileUI() ? drawerRef.current!.open = true}> /** * Mobile: 底部导航栏提供列表切换 */ : drawerRef.current!.open = true}> { ({ Recents: "最近对话", Favourites: "收藏对话", AllChats: "所有对话", })[currentShowPage] }
} { /** * Mobile: 指定高度的容器 * Default: 侧边列表 */ } { !isMobileUI() &&
{ (state.currentSelectedChatId && state.currentSelectedChatId != '') ? :
选择以开始对话......
}
} { /** * Mobile: 底部导航栏提供列表切换 * Default: 侧边列表提供列表切换 */ isMobileUI() && 最近对话 收藏对话 全部对话 }
) } function SnackbarErrorBoundary() { const error = useRouteError() return { const d = dialog({ headline: "错误", description: error instanceof Error ? ('[' + error.name + '] ' + (error.stack || error.message)) : error + '', closeOnEsc: true, closeOnOverlayClick: true, }) return () => { d.open = false } }} deps={[]} /> } export default function Main() { const router = createBrowserRouter([{ path: "/", Component: Root, hydrateFallbackElement: , ErrorBoundary: SnackbarErrorBoundary, children: [ { path: 'info/:type', Component: UserOrChatInfoDialog, loader: UserOrChatInfoDialogLoader, }, { path: 'add', children: [ { path: 'favourite_chat', Component: AddFavourtieChatDialog, }, ], }, { path: 'settings', children: [ { path: 'edit_profile', Component: EditMyProfileDialog, } ], }, { path: 'chat', Component: ChatFragmentDialog, children: [ { path: 'info', Component: UserOrChatInfoDialog, loader: ChatInfoDialogDataLoader, }, ], }, ], }]) return }