forked from mirror/cinny
Compare commits
6 commits
custom
...
refactor-n
Author | SHA1 | Date | |
---|---|---|---|
|
d70b75e7f3 | ||
|
c2b4e18008 | ||
|
08b0bdb431 | ||
|
5722311306 | ||
|
3c8e244a00 | ||
|
e4e6601a6b |
19 changed files with 310 additions and 105 deletions
|
@ -9,7 +9,7 @@
|
|||
status = 200
|
||||
|
||||
[[redirects]]
|
||||
from = "/olm.wasm"
|
||||
from = "*/olm.wasm"
|
||||
to = "/olm.wasm"
|
||||
status = 200
|
||||
|
||||
|
|
36
src/app/components/CapabilitiesAndMediaConfigLoader.tsx
Normal file
36
src/app/components/CapabilitiesAndMediaConfigLoader.tsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { ReactNode, useCallback, useEffect } from 'react';
|
||||
import { Capabilities } from 'matrix-js-sdk';
|
||||
import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback';
|
||||
import { useMatrixClient } from '../hooks/useMatrixClient';
|
||||
import { MediaConfig } from '../hooks/useMediaConfig';
|
||||
import { promiseFulfilledResult } from '../utils/common';
|
||||
|
||||
type CapabilitiesAndMediaConfigLoaderProps = {
|
||||
children: (capabilities?: Capabilities, mediaConfig?: MediaConfig) => ReactNode;
|
||||
};
|
||||
export function CapabilitiesAndMediaConfigLoader({
|
||||
children,
|
||||
}: CapabilitiesAndMediaConfigLoaderProps) {
|
||||
const mx = useMatrixClient();
|
||||
|
||||
const [state, load] = useAsyncCallback<
|
||||
[Capabilities | undefined, MediaConfig | undefined],
|
||||
unknown,
|
||||
[]
|
||||
>(
|
||||
useCallback(async () => {
|
||||
const result = await Promise.allSettled([mx.getCapabilities(true), mx.getMediaConfig()]);
|
||||
const capabilities = promiseFulfilledResult(result[0]);
|
||||
const mediaConfig = promiseFulfilledResult(result[1]);
|
||||
return [capabilities, mediaConfig];
|
||||
}, [mx])
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
load();
|
||||
}, [load]);
|
||||
|
||||
const [capabilities, mediaConfig] =
|
||||
state.status === AsyncStatus.Success ? state.data : [undefined, undefined];
|
||||
return children(capabilities, mediaConfig);
|
||||
}
|
19
src/app/components/CapabilitiesLoader.tsx
Normal file
19
src/app/components/CapabilitiesLoader.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { ReactNode, useCallback, useEffect } from 'react';
|
||||
import { Capabilities } from 'matrix-js-sdk';
|
||||
import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback';
|
||||
import { useMatrixClient } from '../hooks/useMatrixClient';
|
||||
|
||||
type CapabilitiesLoaderProps = {
|
||||
children: (capabilities: Capabilities | undefined) => ReactNode;
|
||||
};
|
||||
export function CapabilitiesLoader({ children }: CapabilitiesLoaderProps) {
|
||||
const mx = useMatrixClient();
|
||||
|
||||
const [state, load] = useAsyncCallback(useCallback(() => mx.getCapabilities(true), [mx]));
|
||||
|
||||
useEffect(() => {
|
||||
load();
|
||||
}, [load]);
|
||||
|
||||
return children(state.status === AsyncStatus.Success ? state.data : undefined);
|
||||
}
|
19
src/app/components/MediaConfigLoader.tsx
Normal file
19
src/app/components/MediaConfigLoader.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { ReactNode, useCallback, useEffect } from 'react';
|
||||
import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback';
|
||||
import { useMatrixClient } from '../hooks/useMatrixClient';
|
||||
import { MediaConfig } from '../hooks/useMediaConfig';
|
||||
|
||||
type MediaConfigLoaderProps = {
|
||||
children: (mediaConfig: MediaConfig | undefined) => ReactNode;
|
||||
};
|
||||
export function MediaConfigLoader({ children }: MediaConfigLoaderProps) {
|
||||
const mx = useMatrixClient();
|
||||
|
||||
const [state, load] = useAsyncCallback(useCallback(() => mx.getMediaConfig(), [mx]));
|
||||
|
||||
useEffect(() => {
|
||||
load();
|
||||
}, [load]);
|
||||
|
||||
return children(state.status === AsyncStatus.Success ? state.data : undefined);
|
||||
}
|
|
@ -1,20 +1,25 @@
|
|||
import { ReactNode, useCallback, useEffect } from 'react';
|
||||
import { ReactNode, useCallback, useEffect, useState } from 'react';
|
||||
import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback';
|
||||
import { SpecVersions, specVersions } from '../cs-api';
|
||||
import { useAutoDiscoveryInfo } from '../hooks/useAutoDiscoveryInfo';
|
||||
|
||||
type SpecVersionsLoaderProps = {
|
||||
baseUrl: string;
|
||||
fallback?: () => ReactNode;
|
||||
error?: (err: unknown) => ReactNode;
|
||||
error?: (err: unknown, retry: () => void, ignore: () => void) => ReactNode;
|
||||
children: (versions: SpecVersions) => ReactNode;
|
||||
};
|
||||
export function SpecVersionsLoader({ fallback, error, children }: SpecVersionsLoaderProps) {
|
||||
const autoDiscoveryInfo = useAutoDiscoveryInfo();
|
||||
const baseUrl = autoDiscoveryInfo['m.homeserver'].base_url;
|
||||
|
||||
export function SpecVersionsLoader({
|
||||
baseUrl,
|
||||
fallback,
|
||||
error,
|
||||
children,
|
||||
}: SpecVersionsLoaderProps) {
|
||||
const [state, load] = useAsyncCallback(
|
||||
useCallback(() => specVersions(fetch, baseUrl), [baseUrl])
|
||||
);
|
||||
const [ignoreError, setIgnoreError] = useState(false);
|
||||
|
||||
const ignoreCallback = useCallback(() => setIgnoreError(true), []);
|
||||
|
||||
useEffect(() => {
|
||||
load();
|
||||
|
@ -24,9 +29,15 @@ export function SpecVersionsLoader({ fallback, error, children }: SpecVersionsLo
|
|||
return fallback?.();
|
||||
}
|
||||
|
||||
if (state.status === AsyncStatus.Error) {
|
||||
return error?.(state.error);
|
||||
if (!ignoreError && state.status === AsyncStatus.Error) {
|
||||
return error?.(state.error, load, ignoreCallback);
|
||||
}
|
||||
|
||||
return children(state.data);
|
||||
return children(
|
||||
state.status === AsyncStatus.Success
|
||||
? state.data
|
||||
: {
|
||||
versions: [],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ export const specVersions = async (
|
|||
request: typeof fetch,
|
||||
baseUrl: string
|
||||
): Promise<SpecVersions> => {
|
||||
const res = await request(`${baseUrl}/_matrix/client/versions`);
|
||||
const res = await request(`${trimTrailingSlash(baseUrl)}/_matrix/client/versions`);
|
||||
|
||||
const data = (await res.json()) as unknown;
|
||||
|
||||
|
|
12
src/app/hooks/useCapabilities.ts
Normal file
12
src/app/hooks/useCapabilities.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { Capabilities } from 'matrix-js-sdk';
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
const CapabilitiesContext = createContext<Capabilities | null>(null);
|
||||
|
||||
export const CapabilitiesProvider = CapabilitiesContext.Provider;
|
||||
|
||||
export function useCapabilities(): Capabilities {
|
||||
const capabilities = useContext(CapabilitiesContext);
|
||||
if (!capabilities) throw new Error('Capabilities are not provided!');
|
||||
return capabilities;
|
||||
}
|
16
src/app/hooks/useMediaConfig.ts
Normal file
16
src/app/hooks/useMediaConfig.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { createContext, useContext } from 'react';
|
||||
|
||||
export interface MediaConfig {
|
||||
[key: string]: unknown;
|
||||
'm.upload.size'?: number;
|
||||
}
|
||||
|
||||
const MediaConfigContext = createContext<MediaConfig | null>(null);
|
||||
|
||||
export const MediaConfigProvider = MediaConfigContext.Provider;
|
||||
|
||||
export function useMediaConfig(): MediaConfig {
|
||||
const mediaConfig = useContext(MediaConfigContext);
|
||||
if (!mediaConfig) throw new Error('Media configs are not provided!');
|
||||
return mediaConfig;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import {
|
||||
Outlet,
|
||||
Route,
|
||||
RouterProvider,
|
||||
createBrowserRouter,
|
||||
|
@ -12,12 +13,27 @@ import {
|
|||
import { ClientConfigLoader } from '../components/ClientConfigLoader';
|
||||
import { ClientConfig, ClientConfigProvider } from '../hooks/useClientConfig';
|
||||
import { AuthLayout, Login, Register, ResetPassword, authLayoutLoader } from './auth';
|
||||
import { LOGIN_PATH, REGISTER_PATH, RESET_PASSWORD_PATH, ROOT_PATH } from './paths';
|
||||
import {
|
||||
DIRECT_PATH,
|
||||
EXPLORE_PATH,
|
||||
HOME_PATH,
|
||||
LOGIN_PATH,
|
||||
NOTIFICATIONS_PATH,
|
||||
REGISTER_PATH,
|
||||
RESET_PASSWORD_PATH,
|
||||
ROOT_PATH,
|
||||
SPACE_PATH,
|
||||
_CREATE_PATH,
|
||||
_LOBBY_PATH,
|
||||
_ROOM_PATH,
|
||||
_SEARCH_PATH,
|
||||
} from './paths';
|
||||
import { isAuthenticated } from '../../client/state/auth';
|
||||
import Client from '../templates/client/Client';
|
||||
import { getLoginPath } from './pathUtils';
|
||||
import { ConfigConfigError, ConfigConfigLoading } from './ConfigConfig';
|
||||
import { FeatureCheck } from './FeatureCheck';
|
||||
import Client from '../templates/client/Client';
|
||||
import { ClientLayout } from './client';
|
||||
|
||||
const createRouter = (clientConfig: ClientConfig) => {
|
||||
const { hashRouter } = clientConfig;
|
||||
|
@ -27,7 +43,7 @@ const createRouter = (clientConfig: ClientConfig) => {
|
|||
<Route
|
||||
path={ROOT_PATH}
|
||||
loader={() => {
|
||||
if (isAuthenticated()) return redirect('/home');
|
||||
if (isAuthenticated()) return redirect(HOME_PATH);
|
||||
return redirect(getLoginPath());
|
||||
}}
|
||||
/>
|
||||
|
@ -42,11 +58,26 @@ const createRouter = (clientConfig: ClientConfig) => {
|
|||
if (!isAuthenticated()) return redirect(getLoginPath());
|
||||
return null;
|
||||
}}
|
||||
element={<ClientLayout />}
|
||||
>
|
||||
<Route path="/home" element={<Client />} />
|
||||
<Route path="/direct" element={<p>direct</p>} />
|
||||
<Route path="/:spaceIdOrAlias" element={<p>:spaceIdOrAlias</p>} />
|
||||
<Route path="/explore" element={<p>explore</p>} />
|
||||
<Route path={HOME_PATH} element={<Outlet />}>
|
||||
<Route index element={<Client />} />
|
||||
<Route path={_SEARCH_PATH} element={<p>search</p>} />
|
||||
<Route path={_ROOM_PATH} element={<p>room</p>} />
|
||||
</Route>
|
||||
<Route path={DIRECT_PATH} element={<Outlet />}>
|
||||
<Route index element={<p>index</p>} />
|
||||
<Route path={_CREATE_PATH} element={<p>create</p>} />
|
||||
<Route path={_ROOM_PATH} element={<p>room</p>} />
|
||||
</Route>
|
||||
<Route path={NOTIFICATIONS_PATH} element={<p>notifications</p>} />
|
||||
<Route path={SPACE_PATH} element={<Outlet />}>
|
||||
<Route index element={<p>index</p>} />
|
||||
<Route path={_LOBBY_PATH} element={<p>lobby</p>} />
|
||||
<Route path={_SEARCH_PATH} element={<p>search</p>} />
|
||||
<Route path={_ROOM_PATH} element={<p>room</p>} />
|
||||
</Route>
|
||||
<Route path={EXPLORE_PATH} element={<p>explore</p>} />
|
||||
</Route>
|
||||
<Route path="/*" element={<p>Page not found</p>} />
|
||||
</Route>
|
||||
|
|
|
@ -175,6 +175,7 @@ export function AuthLayout() {
|
|||
<AuthServerProvider value={discoveryState.data.serverName}>
|
||||
<AutoDiscoveryInfoProvider value={autoDiscoveryInfo}>
|
||||
<SpecVersionsLoader
|
||||
baseUrl={autoDiscoveryInfo['m.homeserver'].base_url}
|
||||
fallback={() => (
|
||||
<AuthLayoutLoading
|
||||
message={`Connecting to ${autoDiscoveryInfo['m.homeserver'].base_url}`}
|
||||
|
|
56
src/app/pages/client/ClientLayout.tsx
Normal file
56
src/app/pages/client/ClientLayout.tsx
Normal file
|
@ -0,0 +1,56 @@
|
|||
import { Box, Spinner, Text } from 'folds';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
import initMatrix from '../../../client/initMatrix';
|
||||
import { initHotkeys } from '../../../client/event/hotkeys';
|
||||
import { initRoomListListener } from '../../../client/event/roomList';
|
||||
import { getSecret } from '../../../client/state/auth';
|
||||
import { SplashScreen } from '../../components/splash-screen';
|
||||
import { CapabilitiesAndMediaConfigLoader } from '../../components/CapabilitiesAndMediaConfigLoader';
|
||||
import { CapabilitiesProvider } from '../../hooks/useCapabilities';
|
||||
import { MediaConfigProvider } from '../../hooks/useMediaConfig';
|
||||
import { MatrixClientProvider } from '../../hooks/useMatrixClient';
|
||||
import { SpecVersions } from './SpecVersions';
|
||||
|
||||
export function ClientLayout() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { baseUrl } = getSecret();
|
||||
|
||||
useEffect(() => {
|
||||
const handleStart = () => {
|
||||
initHotkeys();
|
||||
initRoomListListener(initMatrix.roomList);
|
||||
setLoading(false);
|
||||
};
|
||||
initMatrix.once('init_loading_finished', handleStart);
|
||||
if (!initMatrix.matrixClient) initMatrix.init();
|
||||
return () => {
|
||||
initMatrix.removeListener('init_loading_finished', handleStart);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SpecVersions baseUrl={baseUrl!}>
|
||||
{loading ? (
|
||||
<SplashScreen>
|
||||
<Box direction="Column" grow="Yes" alignItems="Center" justifyContent="Center" gap="400">
|
||||
<Spinner variant="Secondary" size="600" />
|
||||
<Text>Heating up</Text>
|
||||
</Box>
|
||||
</SplashScreen>
|
||||
) : (
|
||||
<MatrixClientProvider value={initMatrix.matrixClient!}>
|
||||
<CapabilitiesAndMediaConfigLoader>
|
||||
{(capabilities, mediaConfig) => (
|
||||
<CapabilitiesProvider value={capabilities ?? {}}>
|
||||
<MediaConfigProvider value={mediaConfig ?? {}}>
|
||||
<Outlet />
|
||||
</MediaConfigProvider>
|
||||
</CapabilitiesProvider>
|
||||
)}
|
||||
</CapabilitiesAndMediaConfigLoader>
|
||||
</MatrixClientProvider>
|
||||
)}
|
||||
</SpecVersions>
|
||||
);
|
||||
}
|
0
src/app/pages/client/SidebarLayout.tsx
Normal file
0
src/app/pages/client/SidebarLayout.tsx
Normal file
46
src/app/pages/client/SpecVersions.tsx
Normal file
46
src/app/pages/client/SpecVersions.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import React, { ReactNode } from 'react';
|
||||
import { Box, Dialog, config, Text, Button, Spinner } from 'folds';
|
||||
import { SpecVersionsLoader } from '../../components/SpecVersionsLoader';
|
||||
import { SpecVersionsProvider } from '../../hooks/useSpecVersions';
|
||||
import { SplashScreen } from '../../components/splash-screen';
|
||||
|
||||
export function SpecVersions({ baseUrl, children }: { baseUrl: string; children: ReactNode }) {
|
||||
return (
|
||||
<SpecVersionsLoader
|
||||
baseUrl={baseUrl}
|
||||
fallback={() => (
|
||||
<SplashScreen>
|
||||
<Box direction="Column" grow="Yes" alignItems="Center" justifyContent="Center" gap="400">
|
||||
<Spinner variant="Secondary" size="600" />
|
||||
<Text>Connecting to server</Text>
|
||||
</Box>
|
||||
</SplashScreen>
|
||||
)}
|
||||
error={(err, retry, ignore) => (
|
||||
<SplashScreen>
|
||||
<Box direction="Column" grow="Yes" alignItems="Center" justifyContent="Center" gap="400">
|
||||
<Dialog>
|
||||
<Box direction="Column" gap="400" style={{ padding: config.space.S400 }}>
|
||||
<Text>
|
||||
Failed to connect to homeserver. Either homeserver is down or your internet.
|
||||
</Text>
|
||||
<Button variant="Critical" onClick={retry}>
|
||||
<Text as="span" size="B400">
|
||||
Retry
|
||||
</Text>
|
||||
</Button>
|
||||
<Button variant="Critical" onClick={ignore} fill="Soft">
|
||||
<Text as="span" size="B400">
|
||||
Continue
|
||||
</Text>
|
||||
</Button>
|
||||
</Box>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</SplashScreen>
|
||||
)}
|
||||
>
|
||||
{(versions) => <SpecVersionsProvider value={versions}>{children}</SpecVersionsProvider>}
|
||||
</SpecVersionsLoader>
|
||||
);
|
||||
}
|
1
src/app/pages/client/index.ts
Normal file
1
src/app/pages/client/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './ClientLayout';
|
|
@ -15,3 +15,14 @@ export type RegisterPathSearchParams = {
|
|||
export const REGISTER_PATH = '/register/:server?/';
|
||||
|
||||
export const RESET_PASSWORD_PATH = '/reset-password/:server?/';
|
||||
|
||||
export const HOME_PATH = '/home/';
|
||||
export const DIRECT_PATH = '/direct/';
|
||||
export const NOTIFICATIONS_PATH = '/notifications/';
|
||||
export const SPACE_PATH = '/:spaceIdOrAlias/';
|
||||
export const EXPLORE_PATH = '/explore/';
|
||||
|
||||
export const _CREATE_PATH = './create/';
|
||||
export const _LOBBY_PATH = './lobby/';
|
||||
export const _SEARCH_PATH = './search/';
|
||||
export const _ROOM_PATH = './:roomIdOrAlias/:eventId?/';
|
||||
|
|
|
@ -2,12 +2,15 @@ import { useCallback } from 'react';
|
|||
import type * as PdfJsDist from 'pdfjs-dist';
|
||||
import type { GetViewportParameters } from 'pdfjs-dist/types/src/display/api';
|
||||
import { useAsyncCallback } from '../hooks/useAsyncCallback';
|
||||
import { trimTrailingSlash } from '../utils/common';
|
||||
|
||||
export const usePdfJSLoader = () =>
|
||||
useAsyncCallback(
|
||||
useCallback(async () => {
|
||||
const pdf = await import('pdfjs-dist');
|
||||
pdf.GlobalWorkerOptions.workerSrc = 'pdf.worker.min.js';
|
||||
pdf.GlobalWorkerOptions.workerSrc = `${trimTrailingSlash(
|
||||
import.meta.env.BASE_URL
|
||||
)}/pdf.worker.min.js`;
|
||||
return pdf;
|
||||
}, [])
|
||||
);
|
||||
|
|
|
@ -1,24 +1,14 @@
|
|||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import './Client.scss';
|
||||
|
||||
import { initHotkeys } from '../../../client/event/hotkeys';
|
||||
import { initRoomListListener } from '../../../client/event/roomList';
|
||||
|
||||
import Text from '../../atoms/text/Text';
|
||||
import Spinner from '../../atoms/spinner/Spinner';
|
||||
import Navigation from '../../organisms/navigation/Navigation';
|
||||
import ContextMenu, { MenuItem } from '../../atoms/context-menu/ContextMenu';
|
||||
import IconButton from '../../atoms/button/IconButton';
|
||||
import ReusableContextMenu from '../../atoms/context-menu/ReusableContextMenu';
|
||||
import Windows from '../../organisms/pw/Windows';
|
||||
import Dialogs from '../../organisms/pw/Dialogs';
|
||||
|
||||
import initMatrix from '../../../client/initMatrix';
|
||||
import navigation from '../../../client/state/navigation';
|
||||
import cons from '../../../client/state/cons';
|
||||
|
||||
import VerticalMenuIC from '../../../../public/res/ic/outlined/vertical-menu.svg';
|
||||
import { MatrixClientProvider } from '../../hooks/useMatrixClient';
|
||||
import { ClientContent } from './ClientContent';
|
||||
import { useSetting } from '../../state/hooks/settings';
|
||||
import { settingsAtom } from '../../state/settings';
|
||||
|
@ -36,8 +26,6 @@ function SystemEmojiFeature() {
|
|||
}
|
||||
|
||||
function Client() {
|
||||
const [isLoading, changeLoading] = useState(true);
|
||||
const [loadingMsg, setLoadingMsg] = useState('Heating up');
|
||||
const classNameHidden = 'client__item-hidden';
|
||||
|
||||
const navWrapperRef = useRef(null);
|
||||
|
@ -62,76 +50,19 @@ function Client() {
|
|||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
changeLoading(true);
|
||||
let counter = 0;
|
||||
const iId = setInterval(() => {
|
||||
const msgList = ['Almost there...', 'Looks like you have a lot of stuff to heat up!'];
|
||||
if (counter === msgList.length - 1) {
|
||||
setLoadingMsg(msgList[msgList.length - 1]);
|
||||
clearInterval(iId);
|
||||
return;
|
||||
}
|
||||
setLoadingMsg(msgList[counter]);
|
||||
counter += 1;
|
||||
}, 15000);
|
||||
initMatrix.once('init_loading_finished', () => {
|
||||
clearInterval(iId);
|
||||
initHotkeys();
|
||||
initRoomListListener(initMatrix.roomList);
|
||||
changeLoading(false);
|
||||
});
|
||||
initMatrix.init();
|
||||
}, []);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="loading-display">
|
||||
<div className="loading__menu">
|
||||
<ContextMenu
|
||||
placement="bottom"
|
||||
content={
|
||||
<>
|
||||
<MenuItem onClick={() => initMatrix.clearCacheAndReload()}>
|
||||
Clear cache & reload
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => initMatrix.logout()}>Logout</MenuItem>
|
||||
</>
|
||||
}
|
||||
render={(toggle) => (
|
||||
<IconButton size="extra-small" onClick={toggle} src={VerticalMenuIC} />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Spinner />
|
||||
<Text className="loading__message" variant="b2">
|
||||
{loadingMsg}
|
||||
</Text>
|
||||
|
||||
<div className="loading__appname">
|
||||
<Text variant="h2" weight="medium">
|
||||
Cinny
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<MatrixClientProvider value={initMatrix.matrixClient}>
|
||||
<div className="client-container">
|
||||
<div className="navigation__wrapper" ref={navWrapperRef}>
|
||||
<Navigation />
|
||||
</div>
|
||||
<div className={`room__wrapper ${classNameHidden}`} ref={roomWrapperRef}>
|
||||
<ClientContent />
|
||||
</div>
|
||||
<Windows />
|
||||
<Dialogs />
|
||||
<ReusableContextMenu />
|
||||
<SystemEmojiFeature />
|
||||
<div className="client-container">
|
||||
<div className="navigation__wrapper" ref={navWrapperRef}>
|
||||
<Navigation />
|
||||
</div>
|
||||
</MatrixClientProvider>
|
||||
<div className={`room__wrapper ${classNameHidden}`} ref={roomWrapperRef}>
|
||||
<ClientContent />
|
||||
</div>
|
||||
<Windows />
|
||||
<Dialogs />
|
||||
<ReusableContextMenu />
|
||||
<SystemEmojiFeature />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,14 +23,20 @@ class InitMatrix extends EventEmitter {
|
|||
}
|
||||
|
||||
async init() {
|
||||
if (this.matrixClient) {
|
||||
if (this.matrixClient || this.initializing) {
|
||||
console.warn('Client is already initialized!')
|
||||
return;
|
||||
}
|
||||
this.initializing = true;
|
||||
|
||||
await this.startClient();
|
||||
this.setupSync();
|
||||
this.listenEvents();
|
||||
try {
|
||||
await this.startClient();
|
||||
this.setupSync();
|
||||
this.listenEvents();
|
||||
this.initializing = false;
|
||||
} catch {
|
||||
this.initializing = false;
|
||||
}
|
||||
}
|
||||
|
||||
async startClient() {
|
||||
|
|
|
@ -44,6 +44,12 @@ export default defineConfig({
|
|||
server: {
|
||||
port: 8080,
|
||||
host: true,
|
||||
proxy: {
|
||||
"^\\/.*?\\/olm\\.wasm$": {
|
||||
target: 'http://localhost:8080',
|
||||
rewrite: () => '/olm.wasm'
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
viteStaticCopy(copyFiles),
|
||||
|
|
Loading…
Reference in a new issue