Skip to content

Commit

Permalink
Merge pull request #58 from lobehub/fix/role-edit
Browse files Browse the repository at this point in the history
feat: 错误处理 & 配置优化
  • Loading branch information
rdmclin2 authored May 24, 2024
2 parents c58fc33 + 23b2d5d commit a4db591
Show file tree
Hide file tree
Showing 55 changed files with 1,126 additions and 585 deletions.
3 changes: 1 addition & 2 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ const nextConfig = {
compress: isProd,
pageExtensions: ['tsx', 'ts'],
experimental: {
optimizePackageImports: ['@lobehub/ui', '@lobehub/icons', 'chroma-js', 'shiki'],
webVitalsAttribution: ['CLS', 'LCP'],
optimizePackageImports: ['@lobehub/ui', '@lobehub/icons', 'chroma-js', 'shiki', '@icons-pack/react-simple-icons','gpt-tokenizer'],
},
reactStrictMode: true,
webpack(config) {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/utilities": "^3.2.2",
"@gltf-transform/core": "^3.10.1",
"@icons-pack/react-simple-icons": "^9.5.0",
"@lobehub/tts": "^1.24.1",
"@lobehub/ui": "^1.138.17",
"@pixiv/three-vrm": "^2.1.1",
Expand Down
4 changes: 2 additions & 2 deletions src/app/chat/Apps.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DancePanel, MarketPanel } from '@/panels';
import { useConfigStore } from '@/store/config';
import { useGlobalStore } from '@/store/global';
import { PanelKey } from '@/types/config';

export const apps = [
Expand All @@ -16,7 +16,7 @@ export const apps = [
];

export default () => {
const [panel] = useConfigStore((s) => [s.panel]);
const [panel] = useGlobalStore((s) => [s.panel]);

return (
<>
Expand Down
5 changes: 5 additions & 0 deletions src/app/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use client';

import dynamic from 'next/dynamic';

export default dynamic(() => import('@/components/Error'));
22 changes: 22 additions & 0 deletions src/app/global-error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use client';

import Error from 'next/error';
import { useEffect } from 'react';

export default function GlobalError({
error,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.log('error', error);
}, [error]);
return (
<html>
<body>
<Error statusCode={undefined as any} />
</body>
</html>
);
}
6 changes: 1 addition & 5 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import { Analytics } from '@vercel/analytics/react';
import { cookies } from 'next/headers';
import { PropsWithChildren } from 'react';

import { VIDOL_THEME_APPEARANCE } from '@/constants/theme';
import Layout from '@/layout';

import StyleRegistry from './StyleRegistry';

const RootLayout = ({ children }: PropsWithChildren) => {
// get default theme config to use with ssr
const cookieStore = cookies();
const appearance = cookieStore.get(VIDOL_THEME_APPEARANCE);

return (
<html lang="cn" suppressHydrationWarning>
<body>
<StyleRegistry>
<Layout defaultAppearance={appearance?.value}>{children}</Layout>
<Layout>{children}</Layout>
</StyleRegistry>
<Analytics />
</body>
Expand Down
2 changes: 1 addition & 1 deletion src/app/role/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const useStyles = createStyles(({ css }) => ({
preview: css`
overflow: auto;
width: 80rem;
margin: 32px auto;
margin: 0 auto;
`,
edit: css`
padding: 0 24px;
Expand Down
43 changes: 43 additions & 0 deletions src/components/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { createStyles } from 'antd-style';
import NextImage from 'next/image';

import { AVATAR_IMAGE_SIZE, DEFAULT_USER_AVATAR_URL } from '@/constants/common';

const useStyle = createStyles(
({ css, token }) => css`
cursor: pointer;
overflow: hidden;
border-radius: 50%;
transition:
scale 400ms ${token.motionEaseOut},
box-shadow 100ms ${token.motionEaseOut};
&:hover {
box-shadow: 0 0 0 3px ${token.colorText};
}
&:active {
scale: 0.8;
}
`,
);

interface Props {
avatar?: string;
size?: number;
}

export default (props: Props) => {
const { size = AVATAR_IMAGE_SIZE, avatar } = props;
const { styles } = useStyle();
return (
<NextImage
className={styles}
alt={avatar ? 'userAvatar' : 'LobeVidol'}
height={size}
src={!!avatar ? avatar : DEFAULT_USER_AVATAR_URL}
unoptimized
width={size}
/>
);
};
61 changes: 61 additions & 0 deletions src/components/Error/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use client';

import { FluentEmoji } from '@lobehub/ui';
import { Button } from 'antd';
import Link from 'next/link';
import { memo, useEffect } from 'react';
import { Flexbox } from 'react-layout-kit';

import { MAX_WIDTH } from '@/constants/common';
import ResetConfig from '@/features/Actions/ClearSession';
import ClearChat from '@/features/Actions/ResetConfig';

interface ErrorCaptureProps {
error: Error & { digest?: string };
reset: () => void;
}

const ErrorCapture = memo<ErrorCaptureProps>(({ reset, error }) => {
useEffect(() => {
// Log the error to an error reporting service
console.error(error);
}, [error]);

return (
<Flexbox align={'center'} justify={'center'} style={{ minHeight: '100%', width: '100%' }}>
<h1
style={{
filter: 'blur(8px)',
fontSize: `min(${MAX_WIDTH / 6}px, 25vw)`,
fontWeight: 900,
margin: 0,
opacity: 0.12,
position: 'absolute',
zIndex: 0,
}}
>
ERROR
</h1>
<FluentEmoji emoji={'🤧'} size={64} />
<h2 style={{ fontWeight: 'bold', marginTop: '1em', textAlign: 'center' }}>
页面遇到一点问题...
</h2>
<p style={{ marginBottom: '2em' }}>
项目当前正在施工中,不保证数据稳定性,如果遇到问题可以尝试
<ClearChat text="清除会话消息" type={'link'} />
<ResetConfig text="重置系统设置" type={'link'} />
,造成地不便敬请谅解
</p>
<Flexbox gap={12} horizontal style={{ marginBottom: '1em' }}>
<Button onClick={() => reset()}>重新加载</Button>
<Link href="/">
<Button type={'primary'}>返回首页</Button>
</Link>
</Flexbox>
</Flexbox>
);
});

ErrorCapture.displayName = 'ErrorCapture';

export default ErrorCapture;
97 changes: 97 additions & 0 deletions src/components/Menu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { Menu as AntdMenu, MenuProps as AntdMenuProps, ConfigProvider } from 'antd';
import { createStyles } from 'antd-style';
import { memo } from 'react';

const useStyles = createStyles(({ css, token, prefixCls }) => ({
compact: css`
display: flex;
flex-direction: column;
gap: 0.125rem;
`,
menu: css`
flex: 1;
background: transparent;
border: none !important;
.${prefixCls}-menu-item-divider {
margin-block: 0.125rem;
border-color: ${token.colorFillTertiary};
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
.${prefixCls}-menu-item, .${prefixCls}-menu-submenu-title {
display: flex;
gap: 0.75rem;
align-items: center;
height: unset;
min-height: 2rem;
padding: 0.375rem 0.75rem;
line-height: 2;
.anticon + .${prefixCls}-menu-title-content {
margin-inline-start: 0;
}
}
.${prefixCls}-menu-item-selected {
.${prefixCls}-menu-item-icon svg {
color: ${token.colorText};
}
}
.${prefixCls}-menu-item-icon svg {
color: ${token.colorTextSecondary};
}
.${prefixCls}-menu-title-content {
flex: 1;
}
`,
}));

export interface MenuProps extends AntdMenuProps {
variant?: 'default' | 'compact';
}

const Menu = memo<MenuProps>(({ className, selectable = false, variant, ...rest }) => {
const isCompact = variant === 'compact';
const { cx, styles, theme } = useStyles();
return (
<ConfigProvider
theme={{
components: {
Menu: {
controlHeightLG: 36,
iconMarginInlineEnd: 8,
iconSize: 16,
itemBorderRadius: theme.borderRadius,
itemColor: selectable ? theme.colorTextSecondary : theme.colorText,
itemHoverBg: theme.colorFillTertiary,
itemMarginBlock: isCompact ? 0 : 4,
itemMarginInline: isCompact ? 0 : 4,
itemSelectedBg: theme.colorFillSecondary,
paddingXS: -8,
},
},
}}
>
<AntdMenu
className={cx(styles.menu, isCompact && styles.compact, className)}
mode="vertical"
selectable={selectable}
{...rest}
/>
</ConfigProvider>
);
});

export default Menu;
4 changes: 3 additions & 1 deletion src/components/PageLoading/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import { Center, Flexbox } from 'react-layout-kit';

interface PageLoadingProps {
className?: string;
description?: string;
style?: React.CSSProperties;
title: string;
}

const PageLoading = (props: PageLoadingProps) => {
const { title, className, style } = props;
const { title, className, style, description } = props;
return (
<Flexbox height={'100%'} width={'100%'} className={className} style={style}>
<Center flex={1} gap={12} width={'100%'}>
Expand All @@ -19,6 +20,7 @@ const PageLoading = (props: PageLoadingProps) => {
<Icon icon={Loader2} spin />
{title}
</Center>
{description && <Center>{description}</Center>}
</Center>
</Flexbox>
);
Expand Down
2 changes: 2 additions & 0 deletions src/constants/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export const LOADING_FLAG = '...';
export const DEFAULT_USER_AVATAR = '😀';

export const MAX_NAME_LENGTH = 20;

export const MAX_WIDTH = 1024;
export const MAX_DESCRIPTION_LENGTH = 100;
export const MAX_GREETING_LENGTH = 200;
export const MAX_README_LENGTH = 800;
Expand Down
17 changes: 0 additions & 17 deletions src/constants/settings.ts

This file was deleted.

41 changes: 41 additions & 0 deletions src/features/Actions/ClearSession.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { App, Button } from 'antd';
import { ButtonType } from 'antd/es/button';
import React from 'react';

import { useAgentStore } from '@/store/agent';
import { useSessionStore } from '@/store/session';

interface Props {
text?: string;
type?: ButtonType;
}
export default (props: Props) => {
const { text = '立即清除', type = 'primary' } = props;
const clearAgentStorage = useAgentStore((s) => s.clearAgentStorage);
const clearSessions = useSessionStore((s) => s.clearSessions);
const { message, modal } = App.useApp();

const handleClear = () => {
modal.confirm({
cancelText: '取消',
centered: true,
content: '操作无法撤销,清除后数据将无法恢复,请慎重操作',
okButtonProps: {
danger: true,
},
okText: '确定',
onOk: () => {
clearSessions();
clearAgentStorage();
message.success('清除成功');
},
title: '确认清除所有会话消息?',
});
};

return (
<Button danger onClick={handleClear} type={type}>
{text}
</Button>
);
};
Loading

0 comments on commit a4db591

Please sign in to comment.