diff --git a/src/renderer/components/error-boundary/root-error-boundary.tsx b/src/renderer/components/error-boundary/root-error-boundary.tsx
new file mode 100644
index 000000000..ae00ae310
--- /dev/null
+++ b/src/renderer/components/error-boundary/root-error-boundary.tsx
@@ -0,0 +1,89 @@
+import { ErrorBoundary } from 'react-error-boundary';
+import { useTranslation } from 'react-i18next';
+
+import { Box } from '/@/shared/components/box/box';
+import { Button } from '/@/shared/components/button/button';
+import { Center } from '/@/shared/components/center/center';
+import { Group } from '/@/shared/components/group/group';
+import { Icon } from '/@/shared/components/icon/icon';
+import { Stack } from '/@/shared/components/stack/stack';
+import { Text } from '/@/shared/components/text/text';
+
+interface RootErrorFallbackProps {
+ error: Error;
+ resetErrorBoundary: () => void;
+}
+
+const RootErrorFallback = ({ error, resetErrorBoundary }: RootErrorFallbackProps) => {
+ const { t } = useTranslation();
+
+ const handleReload = () => {
+ window.location.reload();
+ };
+
+ return (
+
+
+
+
+
+ {t('error.genericError')}
+
+
+ {error?.message || t('error.genericError')}
+
+ {process.env.NODE_ENV === 'development' && error?.stack && (
+
+ {error.stack}
+
+ )}
+
+
+
+
+
+
+
+ );
+};
+
+interface RootErrorBoundaryProps {
+ children: React.ReactNode;
+}
+
+export const RootErrorBoundary = ({ children }: RootErrorBoundaryProps) => {
+ return (
+ {
+ if (process.env.NODE_ENV === 'development') {
+ console.error('Root error boundary caught an error:', error, errorInfo);
+ }
+ }}
+ onReset={() => {}}
+ >
+ {children}
+
+ );
+};
diff --git a/src/renderer/main.tsx b/src/renderer/main.tsx
index 13e71113e..0731cf340 100644
--- a/src/renderer/main.tsx
+++ b/src/renderer/main.tsx
@@ -7,6 +7,7 @@ import { del, get, set } from 'idb-keyval';
import { createRoot } from 'react-dom/client';
import { App } from '/@/renderer/app';
+import { RootErrorBoundary } from '/@/renderer/components/error-boundary/root-error-boundary';
import { queryClient } from '/@/renderer/lib/react-query';
function createIDBPersister(idbValidKey: IDBValidKey = 'reactQuery') {
@@ -26,32 +27,34 @@ function createIDBPersister(idbValidKey: IDBValidKey = 'reactQuery') {
const indexedDbPersister = createIDBPersister('feishin');
createRoot(document.getElementById('root')!).render(
- {
- const isSuccess = query.state.status === 'success';
- const isLyricsQueryKey =
- query.queryKey.includes('song') &&
- query.queryKey.includes('lyrics') &&
- query.queryKey.includes('select');
+
+ {
+ const isSuccess = query.state.status === 'success';
+ const isLyricsQueryKey =
+ query.queryKey.includes('song') &&
+ query.queryKey.includes('lyrics') &&
+ query.queryKey.includes('select');
- return isSuccess && isLyricsQueryKey;
- },
- },
- hydrateOptions: {
- defaultOptions: {
- queries: {
- gcTime: Infinity,
+ return isSuccess && isLyricsQueryKey;
},
},
- },
- maxAge: Infinity,
- persister: indexedDbPersister,
- }}
- >
-
- ,
+ hydrateOptions: {
+ defaultOptions: {
+ queries: {
+ gcTime: Infinity,
+ },
+ },
+ },
+ maxAge: Infinity,
+ persister: indexedDbPersister,
+ }}
+ >
+
+
+ ,
);