Skip to content

Commit

Permalink
Merge pull request #21 from lobehub/chore/update-assets
Browse files Browse the repository at this point in the history
feat:重构 Agent 和 Dance Panel
  • Loading branch information
rdmclin2 authored Apr 14, 2024
2 parents d1cdd75 + fef8b07 commit d67b6c4
Show file tree
Hide file tree
Showing 52 changed files with 581 additions and 655 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Please be aware that LobeVidol is currently under active development, and feedba
| [@lobehub/tts][lobe-tts-link] | [lobehub/lobe-tts][lobe-tts-github] | High-quality & reliable TTS/STT React Hooks library | [![][lobe-tts-shield]][lobe-tts-link] |
| [@lobehub/lint][lobe-lint-link] | [lobehub/lobe-lint][lobe-lint-github] | Configurations for ESlint, Stylelint, Commitlint, Prettier, Remark, and Semantic Release for LobeHub. | [![][lobe-lint-shield]][lobe-lint-link] |

- **[Vidol chat market](https://github.com/v-idol/vidol-chat-agents)** - This is the Market Index of Vidol Chat. Vidol accesses index.json from this repo to show user the list of available agents.
- **[Vidol market](https://github.com/v-idol/vidol-chat-agents)** - This is the Market Index of Vidol Chat. Vidol accesses index.json from this repo to show user the list of available agents and dances.
- **[Vidol agent sample](https://github.com/v-idol/vidol-agent-sample)** - This is the sample repo to define an AI agent in Vidol.
- **[Vidol dance sample](https://github.com/v-idol/vidol-dance-sample)** - This is the sample repo to define a dance in Vidol.

Expand Down
49 changes: 49 additions & 0 deletions src/app/home/QuickSwitch/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use client';

import { Avatar } from '@lobehub/ui';

import { sessionSelectors, useSessionStore } from '@/store/session';

import { useStyles } from './style';

const AvatarSize = 64;

const QuickSwitch = () => {
const { styles } = useStyles({ avatarSize: AvatarSize });
const [sessionList, getAgentById] = useSessionStore((s) => [
s.sessionList,
sessionSelectors.getAgentById(s),
]);
const [switchSession, activeId] = useSessionStore((s) => [s.switchSession, s.activeId]);

return (
<div className={styles.sidebar}>
{/*<div className={styles.header}>聊天列表</div>*/}
<div className={styles.list}>
{sessionList.map((item) => {
const agent = getAgentById(item.agentId);
if (!agent) return null;
const isActive = activeId === agent.agentId;
return (
<div key={agent.agentId} style={{ position: 'relative' }}>
<Avatar
className={isActive ? styles.active : ''}
onClick={() => switchSession(agent.agentId)}
size={AvatarSize}
src={agent.meta.avatar}
/>
{isActive ? (
<>
{/*<div className={styles.satellite} />*/}
<div className={styles.orbit} />
</>
) : null}
</div>
);
})}
</div>
</div>
);
};

export default QuickSwitch;
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,22 @@ export const useStyles = createStyles(({ css, token }) => ({
border: 3px solid ${token.colorPrimary}; /* 轨道颜色和透明度 */
border-radius: 50%;
`,

roleSelect: css`
sidebar: css`
position: fixed;
top: 64px;
left: 0;
`,

header: css`
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px;
border-bottom: 1px solid ${token.colorBorder};
`,
list: css`
overflow: auto;
display: grid;
grid-auto-flow: row;
Expand All @@ -51,7 +61,6 @@ export const useStyles = createStyles(({ css, token }) => ({
grid-template-rows: repeat(auto-fill, 64px);
justify-items: center;
height: calc(100vh - 64px - 64px);
padding: 32px;
`,
}));
46 changes: 0 additions & 46 deletions src/app/home/RoleSelect/index.tsx

This file was deleted.

14 changes: 3 additions & 11 deletions src/app/home/apps.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
// @ts-ignore
import { AgentPanel, ChatPanel, ConfigPanel, DancePanel, MarketPanel, RolePanel } from '@/panels';
import { AgentPanel, ChatPanel, ConfigPanel, DancePanel, RolePanel } from '@/panels';

export const apps = [
{
avatar:
'https://registry.npmmirror.com/@lobehub/assets-emoji/latest/files/assets/card-index.webp',
component: <AgentPanel />,
key: 'agent',
label: '角色订阅',
label: '角色',
},
{
avatar:
'https://registry.npmmirror.com/@lobehub/assets-emoji/latest/files/assets/folding-hand-fan.webp',
component: <DancePanel />,
key: 'dance',
label: '舞蹈',
label: '跳舞',
},
{
avatar:
Expand All @@ -23,14 +23,6 @@ export const apps = [
key: 'chat',
label: '聊天',
},
{
avatar:
'https://registry.npmmirror.com/@lobehub/assets-emoji/latest/files/assets/convenience-store.webp',
component: <MarketPanel />,
key: 'market',
label: '商店',
},

{
avatar:
'https://registry.npmmirror.com/@lobehub/assets-emoji/latest/files/assets/black-nib.webp',
Expand Down
7 changes: 3 additions & 4 deletions src/app/home/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@

import Background from '@/app/home/Background';
import Dialog from '@/app/home/Dialog';
import Docker from '@/app/home/Docker';
import Header from '@/app/home/Header';
import RoleSelect from '@/app/home/RoleSelect';
import QuickSwitch from '@/app/home/QuickSwitch';
import VirtualIdol from '@/app/home/VirtualIdol';
import { apps } from '@/app/home/apps';
import { useConfigStore } from '@/store/config';
import { PanelKey } from '@/types/config';

import Docker from './Docker';

const Desktop = () => {
const [panel] = useConfigStore((s) => [s.panel]);
return (
Expand All @@ -29,7 +28,7 @@ const Desktop = () => {
})}
</div>
<Docker />
<RoleSelect />
<QuickSwitch />
<Dialog />
<Background />
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/app/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ const metadata: Metadata = {
{
alt: title,
height: 360,
url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/og-480x270.png',
url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/og-vidol-480x270.png',
width: 480,
},
{
alt: title,
height: 720,
url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/og-960x540.png',
url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/og-vidol-960x540.png',
width: 960,
},
],
Expand Down
2 changes: 1 addition & 1 deletion src/components/DanceInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const DanceInfo = (props: DanceInfoProps) => {
return (
<div className={styles.container}>
<Center className={styles.header} gap={16}>
<Avatar avatar={cover} background={theme.colorFillTertiary} shape="square" size={120} />
<Avatar avatar={cover} background={theme.colorFillTertiary} shape="square" size={180} />
<div className={styles.title}>{name}</div>
<div className={styles.actions}>
<Space>{actions}</Space>
Expand Down
36 changes: 36 additions & 0 deletions src/components/GridList/ListItem/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { CheckCircleFilled } from '@ant-design/icons';
import { Typography } from 'antd';
import classNames from 'classnames';
import React, { memo } from 'react';

import { useStyles } from './style';

const { Text } = Typography;

interface AvatarProps {
active?: boolean;
avatar: string;
checked?: boolean;
className?: string;
onClick?: () => void;
style?: React.CSSProperties;
title: string;
}

const ListItem = (props: AvatarProps) => {
const { avatar, title, style, className, onClick, active = false, checked = false } = props;
const { styles } = useStyles({ active, avatar });
return (
<div style={style} className={classNames(className, styles.item)} onClick={onClick}>
<div className={styles.avatar} />
<div className={styles.info}>
<Text ellipsis={{ tooltip: title }} className={styles.title}>
{title}
</Text>
{checked ? <CheckCircleFilled className={styles.check} /> : null}
</div>
</div>
);
};

export default memo(ListItem);
47 changes: 47 additions & 0 deletions src/components/GridList/ListItem/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { createStyles } from 'antd-style';
import { rgba } from 'polished';

interface ListItemProps {
active: boolean;
avatar: string;
}

export const useStyles = createStyles(({ css, token }, { active, avatar }: ListItemProps) => ({
item: css`
cursor: pointer;
position: relative;
width: 100%;
height: 100%;
background: url(${avatar}) no-repeat center center;
background-size: cover;
border: 2px solid ${active ? token.colorPrimary : token.colorFillTertiary};
`,
avatar: css``,

info: css`
position: absolute;
bottom: 0;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 24px;
padding: 4px;
background-color: ${rgba(token.colorBgContainer, 0.8)};
backdrop-filter: saturate(180%) blur(2px);
`,
title: css`
font-size: ${token.sizeSM}px;
line-height: 16px;
`,
check: css`
font-size: ${token.sizeSM}px;
color: ${token.colorSuccessText};
`,
}));
83 changes: 83 additions & 0 deletions src/components/GridList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Icon } from '@lobehub/ui';
import { Empty, Space } from 'antd';
import classNames from 'classnames';
import { Loader2 } from 'lucide-react';
import React, { memo } from 'react';
import { Center } from 'react-layout-kit';

import ListItem from './ListItem';
import { useStyles } from './style';

interface Item {
avatar: string;
id: string;
name: string;
}

interface GridListProps {
className?: string;
empty?: {
actions?: React.ReactNode[];
};
isActivated?: (id: string) => boolean;
isChecked?: (id: string) => boolean;
items: Item[];
loading?: boolean;
onClick?: (id: string) => void;
style?: React.CSSProperties;
}

const GridList = (props: GridListProps) => {
const {
items,
className,
style,
onClick,
isActivated,
isChecked,
loading = false,
empty,
} = props;
const { styles } = useStyles();

const Loading = () => (
<Center gap={16} horizontal className={styles.loading}>
<Icon icon={Loader2} spin />
加载中...
</Center>
);

const List = () => (
<div className={styles.list}>
{items.map((item) => {
const { avatar, name, id } = item;
return (
<ListItem
key={id}
title={name}
avatar={avatar}
onClick={() => {
if (onClick) onClick(id);
}}
active={isActivated ? isActivated(id) : false}
checked={isChecked ? isChecked(id) : false}
/>
);
})}
</div>
);

const EmptyList = () => (
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无数据">
{empty?.actions ? <Space>{empty.actions}</Space> : null}
</Empty>
);

return (
<div className={classNames(className, styles.grid)} style={style}>
{loading ? <Loading /> : items.length === 0 ? <EmptyList /> : <List />}
</div>
);
};

export default memo(GridList);
Loading

0 comments on commit d67b6c4

Please sign in to comment.