@lobehub/chat 0.74.0 → 0.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +26 -5
  3. package/README.zh-CN.md +25 -4
  4. package/locales/en_US/market.json +12 -0
  5. package/locales/en_US/plugin.json +11 -2
  6. package/locales/en_US/setting.json +3 -1
  7. package/locales/ru_RU/market.json +12 -0
  8. package/locales/ru_RU/plugin.json +44 -49
  9. package/locales/ru_RU/setting.json +3 -1
  10. package/locales/zh_CN/common.json +1 -1
  11. package/locales/zh_CN/market.json +12 -0
  12. package/locales/zh_CN/plugin.json +19 -5
  13. package/locales/zh_CN/setting.json +62 -14
  14. package/package.json +5 -4
  15. package/scripts/i18nWorkflow/const.ts +19 -0
  16. package/scripts/i18nWorkflow/genDefaultLocale.ts +19 -0
  17. package/scripts/i18nWorkflow/genDiff.ts +50 -0
  18. package/scripts/i18nWorkflow/genResources.ts +26 -0
  19. package/scripts/i18nWorkflow/index.ts +15 -0
  20. package/scripts/i18nWorkflow/utils.ts +85 -0
  21. package/src/const/layoutTokens.ts +3 -1
  22. package/src/const/market.ts +15 -0
  23. package/src/const/url.ts +29 -4
  24. package/src/features/AgentSetting/AgentConfig/index.tsx +1 -2
  25. package/src/features/AgentSetting/AgentPlugin/MarketSettingModal.tsx +1 -1
  26. package/src/features/AgentSetting/store/initialState.ts +1 -1
  27. package/src/features/MobileTabBar/index.tsx +2 -2
  28. package/src/features/SideBar/TopActions.tsx +2 -2
  29. package/src/locales/default/market.ts +12 -0
  30. package/src/locales/resources/en_US.ts +2 -0
  31. package/src/locales/resources/ru_RU.ts +2 -0
  32. package/src/locales/resources/zh_CN.ts +2 -0
  33. package/src/pages/chat/features/Conversation/Input/{Action.tsx → ActionBar/ActionLeft.tsx} +2 -2
  34. package/src/pages/chat/features/Conversation/Input/ActionBar/ActionRight.tsx +36 -0
  35. package/src/pages/chat/features/Conversation/Input/Desktop.tsx +40 -0
  36. package/src/pages/chat/features/Conversation/Input/Footer/SaveTopic.tsx +27 -0
  37. package/src/pages/chat/features/Conversation/Input/Footer/index.tsx +35 -0
  38. package/src/pages/chat/features/Conversation/Input/Mobile.tsx +12 -0
  39. package/src/pages/chat/features/Conversation/Input/index.tsx +20 -38
  40. package/src/pages/chat/features/SessionList/Header/Desktop.tsx +6 -13
  41. package/src/pages/chat/features/SessionList/Header/Mobile.tsx +1 -1
  42. package/src/pages/chat/features/SessionList/List/AddButton.tsx +1 -1
  43. package/src/pages/chat/features/SessionList/List/Item/index.tsx +4 -3
  44. package/src/pages/chat/features/SessionList/List/index.tsx +1 -3
  45. package/src/pages/chat/features/SessionList/Mobile.tsx +2 -12
  46. package/src/pages/chat/features/SessionSearchBar/index.tsx +26 -0
  47. package/src/pages/chat/features/Sidebar/Topic/index.tsx +18 -6
  48. package/src/pages/chat/features/Sidebar/TopicSearchBar/index.tsx +24 -0
  49. package/src/pages/chat/features/Sidebar/index.tsx +2 -9
  50. package/src/pages/market/features/AgentCard/AgentCardBanner.tsx +64 -0
  51. package/src/pages/market/features/AgentCard/AgentCardItem.tsx +57 -0
  52. package/src/pages/market/features/AgentCard/Loading.tsx +13 -0
  53. package/src/pages/market/features/AgentCard/index.tsx +37 -0
  54. package/src/pages/market/features/AgentCard/style.ts +22 -0
  55. package/src/pages/market/features/AgentSearchBar/index.tsx +26 -0
  56. package/src/pages/market/features/Header/Desktop.tsx +15 -4
  57. package/src/pages/market/features/Header/Mobile.tsx +7 -24
  58. package/src/pages/market/features/SideBar/AgentInfo/Comment.tsx +16 -0
  59. package/src/pages/market/features/SideBar/AgentInfo/Header.tsx +68 -0
  60. package/src/pages/market/features/SideBar/AgentInfo/Loading.tsx +61 -0
  61. package/src/pages/market/features/SideBar/AgentInfo/TokenTag.tsx +25 -0
  62. package/src/pages/market/features/SideBar/AgentInfo/index.tsx +68 -0
  63. package/src/pages/market/features/SideBar/AgentInfo/style.ts +46 -0
  64. package/src/pages/market/features/SideBar/Desktop.tsx +70 -0
  65. package/src/pages/market/features/SideBar/Mobile.tsx +36 -0
  66. package/src/pages/market/features/SideBar/index.tsx +23 -0
  67. package/src/pages/market/features/TagList/index.tsx +29 -0
  68. package/src/pages/market/index.page.tsx +11 -2
  69. package/src/pages/market/layout.mobile.tsx +8 -7
  70. package/src/pages/market/layout.tsx +39 -1
  71. package/src/pages/settings/features/Header/Desktop.tsx +2 -4
  72. package/src/pages/settings/features/Header/Mobile.tsx +1 -1
  73. package/src/pages/settings/features/Settings/Common.tsx +1 -2
  74. package/src/pages/settings/features/Settings/index.tsx +17 -4
  75. package/src/services/agentMarket.ts +21 -0
  76. package/src/store/global/initialState.ts +1 -2
  77. package/src/store/market/action.ts +57 -0
  78. package/src/store/market/index.ts +3 -0
  79. package/src/store/market/initialState.ts +17 -0
  80. package/src/store/market/selectors.ts +36 -0
  81. package/src/store/market/store.ts +51 -0
  82. package/src/store/session/slices/session/action.ts +5 -3
  83. package/src/store/session/slices/session/initialState.ts +2 -0
  84. package/src/store/session/slices/session/reducers/session.test.ts +4 -4
  85. package/src/types/market.ts +19 -0
  86. package/src/types/meta.ts +1 -1
  87. package/src/utils/filter.ts +1 -1
  88. package/src/utils/findDuplicates.ts +22 -0
  89. package/scripts/genDefaultLocale.ts +0 -18
  90. package/scripts/genResources.ts +0 -51
  91. package/scripts/toc.ts +0 -7
  92. package/src/components/Empty/index.tsx +0 -63
  93. package/src/components/Empty/style.ts +0 -31
  94. package/src/components/SelectWithImg/index.tsx +0 -97
  95. package/src/components/SelectWithImg/styles.ts +0 -43
  96. package/src/pages/chat/features/Conversation/Input/ActionRight.tsx +0 -31
  97. package/src/pages/chat/features/Conversation/Input/Footer.tsx +0 -49
  98. /package/src/components/{ManifestPreviewer.tsx → ManifestPreviewer/index.tsx} +0 -0
  99. /package/src/pages/chat/features/Conversation/Input/{Token.tsx → ActionBar/Token.tsx} +0 -0
@@ -9,7 +9,7 @@ const Header = memo(() => {
9
9
  return (
10
10
  <MobileNavBar
11
11
  center={<MobileNavBarTitle title={t('header.global')} />}
12
- onBackClick={() => Router.push('/chat')}
12
+ onBackClick={() => Router.back()}
13
13
  showBackButton
14
14
  />
15
15
  );
@@ -1,4 +1,4 @@
1
- import { Form, type ItemGroup, SliderWithInput } from '@lobehub/ui';
1
+ import { Form, type ItemGroup, SelectWithImg, SliderWithInput } from '@lobehub/ui';
2
2
  import { Form as AntForm, App, Button, Input, Select } from 'antd';
3
3
  import isEqual from 'fast-deep-equal';
4
4
  import { changeLanguage } from 'i18next';
@@ -7,7 +7,6 @@ import { AppWindow, Monitor, Moon, Palette, Sun } from 'lucide-react';
7
7
  import { memo, useCallback, useMemo } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
9
 
10
- import SelectWithImg from '@/components/SelectWithImg';
11
10
  import { FORM_STYLE } from '@/const/layoutTokens';
12
11
  import { DEFAULT_SETTINGS } from '@/const/settings';
13
12
  import AvatarWithUpload from '@/features/AvatarWithUpload';
@@ -2,7 +2,7 @@ import { GridBackground, Icon, Logo, TabsNav } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
3
  import { PackageCheck } from 'lucide-react';
4
4
  import { rgba } from 'polished';
5
- import { memo } from 'react';
5
+ import { memo, useMemo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { Center, Flexbox } from 'react-layout-kit';
8
8
 
@@ -64,6 +64,21 @@ const Settings = memo(() => {
64
64
 
65
65
  const [tab, setTab] = useGlobalStore((s) => [s.settingsTab, s.switchSettingTabs]);
66
66
 
67
+ const content = useMemo(() => {
68
+ switch (tab) {
69
+ case 'llm': {
70
+ return <LLM />;
71
+ }
72
+ case 'agent': {
73
+ return <Agent />;
74
+ }
75
+ default:
76
+ case 'common': {
77
+ return <Common />;
78
+ }
79
+ }
80
+ }, [tab]);
81
+
67
82
  return (
68
83
  <Center gap={16} width={'100%'}>
69
84
  <Flexbox align={'flex-end'} className={styles.tabs} horizontal justify={'center'}>
@@ -91,9 +106,7 @@ const Settings = memo(() => {
91
106
  <div>{`${pkg.version}`}</div>
92
107
  </Flexbox>
93
108
  </Flexbox>
94
- {tab === 'common' && <Common />}
95
- {tab === 'llm' && <LLM />}
96
- {tab === 'agent' && <Agent />}
109
+ {content}
97
110
  </Center>
98
111
  );
99
112
  });
@@ -0,0 +1,21 @@
1
+ import { getAgentIndexJSON, getAgentJSON } from '@/const/url';
2
+ import { useGlobalStore } from '@/store/global';
3
+
4
+ /**
5
+ * 请求助手列表
6
+ */
7
+ export const getAgentList = async () => {
8
+ const res = await fetch(getAgentIndexJSON(useGlobalStore.getState().settings.language));
9
+
10
+ return res.json();
11
+ };
12
+
13
+ /**
14
+ * 请求助手 manifest
15
+ */
16
+ export const getAgentManifest = async (identifier?: string) => {
17
+ if (!identifier) return;
18
+ const res = await fetch(getAgentJSON(identifier, useGlobalStore.getState().settings.language));
19
+
20
+ return res.json();
21
+ };
@@ -21,7 +21,7 @@ export interface GlobalState {
21
21
  * 用户设置
22
22
  */
23
23
  settings: GlobalSettings;
24
- settingsTab: SettingsTabs;
24
+ settingsTab?: SettingsTabs;
25
25
  sidebarKey: SidebarTabKey;
26
26
  }
27
27
 
@@ -44,6 +44,5 @@ export const initialState: GlobalState = {
44
44
  showSessionPanel: true,
45
45
  },
46
46
  settings: DEFAULT_SETTINGS,
47
- settingsTab: 'common',
48
47
  sidebarKey: 'chat',
49
48
  };
@@ -0,0 +1,57 @@
1
+ import isEqual from 'fast-deep-equal';
2
+ import { produce } from 'immer';
3
+ import useSWR, { SWRResponse } from 'swr';
4
+ import type { StateCreator } from 'zustand/vanilla';
5
+
6
+ import { getAgentList, getAgentManifest } from '@/services/agentMarket';
7
+ import { AgentsMarketItem, LobeChatAgentsMarketIndex } from '@/types/market';
8
+
9
+ import type { Store } from './store';
10
+
11
+ export interface StoreAction {
12
+ activateAgent: (identifier: string) => void;
13
+ deactivateAgent: () => void;
14
+ updateAgentMap: (key: string, value: AgentsMarketItem) => void;
15
+ useFetchAgent: (identifier: string) => SWRResponse<AgentsMarketItem>;
16
+ useFetchAgentList: () => SWRResponse<LobeChatAgentsMarketIndex>;
17
+ }
18
+
19
+ export const createMarketAction: StateCreator<
20
+ Store,
21
+ [['zustand/devtools', never]],
22
+ [],
23
+ StoreAction
24
+ > = (set, get) => ({
25
+ activateAgent: (identifier) => {
26
+ set({ currentIdentifier: identifier });
27
+ },
28
+ deactivateAgent: () => {
29
+ set({ currentIdentifier: undefined }, false, 'deactivateAgent');
30
+ },
31
+ updateAgentMap: (key, value) => {
32
+ const { agentMap } = get();
33
+
34
+ const nextAgentMap = produce(agentMap, (draft) => {
35
+ draft[key] = value;
36
+ });
37
+
38
+ if (isEqual(nextAgentMap, agentMap)) return;
39
+
40
+ set({ agentMap: nextAgentMap }, false, `setAgentMap/${key}`);
41
+ },
42
+ useFetchAgent: (identifier) =>
43
+ useSWR<AgentsMarketItem>(identifier, getAgentManifest, {
44
+ onError: () => {
45
+ get().deactivateAgent();
46
+ },
47
+ onSuccess: (data, key) => {
48
+ get().updateAgentMap(key, data);
49
+ },
50
+ }),
51
+ useFetchAgentList: () =>
52
+ useSWR<LobeChatAgentsMarketIndex>('fetchAgentList', getAgentList, {
53
+ onSuccess: (agentMarketIndex) => {
54
+ set({ agentList: agentMarketIndex.agents }, false, 'useFetchAgentList');
55
+ },
56
+ }),
57
+ });
@@ -0,0 +1,3 @@
1
+ export { agentMarketSelectors } from './selectors';
2
+ export { useMarketStore } from './store';
3
+ export { type Store } from './store';
@@ -0,0 +1,17 @@
1
+ import { AgentsMarketIndexItem, AgentsMarketItem } from '@/types/market';
2
+
3
+ export type MarketAgentMap = Record<string, AgentsMarketItem>;
4
+
5
+ export interface StoreState {
6
+ agentList: AgentsMarketIndexItem[];
7
+ agentMap: MarketAgentMap;
8
+ currentIdentifier: string;
9
+ searchKeywords: string;
10
+ }
11
+
12
+ export const initialState: StoreState = {
13
+ agentList: [],
14
+ agentMap: {},
15
+ currentIdentifier: '',
16
+ searchKeywords: '',
17
+ };
@@ -0,0 +1,36 @@
1
+ import { flatten } from 'lodash-es';
2
+
3
+ import { DEFAULT_AGENTS_MARKET_ITEM } from '@/const/market';
4
+ import { AgentsMarketItem } from '@/types/market';
5
+ import { findDuplicates } from '@/utils/findDuplicates';
6
+
7
+ import type { Store } from './store';
8
+
9
+ const getAgentList = (s: Store) => s.agentList;
10
+ const getAgentTagList = (s: Store) => {
11
+ const agentList = s.agentList;
12
+ const rawAgentTagList = flatten(agentList.map((item) => item.meta.tags)) as string[];
13
+ return findDuplicates(rawAgentTagList);
14
+ };
15
+
16
+ const getAgentItemById = (d: string) => (s: Store) => s.agentMap[d];
17
+
18
+ const currentAgentItem = (s: Store) => getAgentItemById(s.currentIdentifier)(s);
19
+
20
+ const currentAgentItemSafe = (s: Store): AgentsMarketItem => {
21
+ const item = getAgentItemById(s.currentIdentifier)(s);
22
+ if (!item) return DEFAULT_AGENTS_MARKET_ITEM;
23
+
24
+ return item;
25
+ };
26
+
27
+ const showSideBar = (s: Store) => !!s.currentIdentifier;
28
+
29
+ export const agentMarketSelectors = {
30
+ currentAgentItem,
31
+ currentAgentItemSafe,
32
+ getAgentItemById,
33
+ getAgentList,
34
+ getAgentTagList,
35
+ showSideBar,
36
+ };
@@ -0,0 +1,51 @@
1
+ import { PersistOptions, devtools, persist } from 'zustand/middleware';
2
+ import { shallow } from 'zustand/shallow';
3
+ import { createWithEqualityFn } from 'zustand/traditional';
4
+ import type { StateCreator } from 'zustand/vanilla';
5
+
6
+ import { createHyperStorage } from '@/store/middleware/createHyperStorage';
7
+ import { isDev } from '@/utils/env';
8
+
9
+ import { type StoreAction, createMarketAction } from './action';
10
+ import { type StoreState, initialState } from './initialState';
11
+
12
+ export type Store = StoreAction & StoreState;
13
+
14
+ const LOBE_AGENT_MARKET = 'LOBE_AGENT_MARKET';
15
+
16
+ const persistOptions: PersistOptions<Store> = {
17
+ name: LOBE_AGENT_MARKET,
18
+
19
+ skipHydration: true,
20
+
21
+ storage: createHyperStorage({
22
+ localStorage: {
23
+ dbName: 'LobeHub',
24
+ selectors: ['agentMap'],
25
+ },
26
+ url: {
27
+ mode: 'hash',
28
+ selectors: [
29
+ // map state key to storage key
30
+ { currentIdentifier: 'agent' },
31
+ ],
32
+ },
33
+ }),
34
+
35
+ version: 0,
36
+ };
37
+
38
+ const createStore: StateCreator<Store, [['zustand/devtools', never]]> = (...parameters) => ({
39
+ ...initialState,
40
+ ...createMarketAction(...parameters),
41
+ });
42
+
43
+ export const useMarketStore = createWithEqualityFn<Store>()(
44
+ persist(
45
+ devtools(createStore, {
46
+ name: LOBE_AGENT_MARKET + (isDev ? '_DEV' : ''),
47
+ }),
48
+ persistOptions,
49
+ ),
50
+ shallow,
51
+ );
@@ -1,13 +1,14 @@
1
1
  import { produce } from 'immer';
2
2
  import { merge } from 'lodash-es';
3
3
  import Router from 'next/router';
4
+ import { DeepPartial } from 'utility-types';
4
5
  import { StateCreator } from 'zustand/vanilla';
5
6
 
6
7
  import { INBOX_SESSION_ID } from '@/const/session';
7
8
  import { SESSION_CHAT_URL } from '@/const/url';
8
9
  import { useGlobalStore } from '@/store/global';
9
10
  import { SessionStore } from '@/store/session';
10
- import { LobeAgentSession, LobeSessions } from '@/types/session';
11
+ import { LobeAgentSession, LobeAgentSettings, LobeSessions } from '@/types/session';
11
12
  import { setNamespace } from '@/utils/storeDebug';
12
13
  import { uuid } from '@/utils/uuid';
13
14
 
@@ -24,7 +25,7 @@ export interface SessionAction {
24
25
  * @param session - 会话信息
25
26
  * @returns void
26
27
  */
27
- createSession: () => Promise<string>;
28
+ createSession: (agent?: DeepPartial<LobeAgentSettings>) => Promise<string>;
28
29
  /**
29
30
  * 变更session
30
31
  * @param payload - 聊天记录
@@ -79,7 +80,7 @@ export const createSessionSlice: StateCreator<
79
80
  set({ sessions: {} }, false, t('clearSessions'));
80
81
  },
81
82
 
82
- createSession: async () => {
83
+ createSession: async (agent) => {
83
84
  const { dispatchSession, switchSession } = get();
84
85
 
85
86
  const timestamp = Date.now();
@@ -87,6 +88,7 @@ export const createSessionSlice: StateCreator<
87
88
  // 合并 settings 里的 defaultAgent
88
89
  const globalDefaultAgent = useGlobalStore.getState().settings.defaultAgent;
89
90
  const newSession: LobeAgentSession = merge({}, initLobeSession, globalDefaultAgent, {
91
+ ...agent,
90
92
  createAt: timestamp,
91
93
  id: uuid(),
92
94
  updateAt: timestamp,
@@ -16,6 +16,7 @@ export interface SessionState {
16
16
  isMobile?: boolean;
17
17
  searchKeywords: string;
18
18
  sessions: Record<string, LobeAgentSession>;
19
+ topicSearchKeywords: string;
19
20
  }
20
21
 
21
22
  export const initLobeSession: LobeAgentSession = {
@@ -44,4 +45,5 @@ export const initialSessionState: SessionState = {
44
45
  isMobile: false,
45
46
  searchKeywords: '',
46
47
  sessions: {},
48
+ topicSearchKeywords: '',
47
49
  };
@@ -109,7 +109,7 @@ describe('sessionsReducer', () => {
109
109
  avatar: 'avatar-url',
110
110
  backgroundColor: 'background-color',
111
111
  description: 'description',
112
- tag: ['tag1', 'tag2'],
112
+ tags: ['tag1', 'tag2'],
113
113
  title: 'title',
114
114
  },
115
115
  } as LobeAgentSession,
@@ -151,7 +151,7 @@ describe('sessionsReducer', () => {
151
151
  avatar: 'avatar-url',
152
152
  backgroundColor: 'background-color',
153
153
  description: 'description',
154
- tag: ['tag1', 'tag2'],
154
+ tags: ['tag1', 'tag2'],
155
155
  title: 'title',
156
156
  },
157
157
  } as LobeAgentSession,
@@ -185,7 +185,7 @@ describe('sessionsReducer', () => {
185
185
  avatar: 'avatar-url',
186
186
  backgroundColor: 'background-color',
187
187
  description: 'description',
188
- tag: ['tag1', 'tag2'],
188
+ tags: ['tag1', 'tag2'],
189
189
  title: 'title',
190
190
  },
191
191
  } as LobeAgentSession,
@@ -221,7 +221,7 @@ describe('sessionsReducer', () => {
221
221
  avatar: 'avatar-url',
222
222
  backgroundColor: 'background-color',
223
223
  description: 'description',
224
- tag: ['tag1', 'tag2'],
224
+ tags: ['tag1', 'tag2'],
225
225
  title: 'title',
226
226
  },
227
227
  } as LobeAgentSession,
@@ -0,0 +1,19 @@
1
+ import { MetaData } from '@/types/meta';
2
+ import { LobeAgentSettings } from '@/types/session';
3
+
4
+ export interface AgentsMarketIndexItem {
5
+ author: string;
6
+ createAt: string;
7
+ homepage: string;
8
+ identifier: string;
9
+ manifest: string;
10
+ meta: MetaData;
11
+ schemaVersion: 1;
12
+ }
13
+
14
+ export type AgentsMarketItem = AgentsMarketIndexItem & LobeAgentSettings;
15
+
16
+ export interface LobeChatAgentsMarketIndex {
17
+ agents: AgentsMarketIndexItem[];
18
+ schemaVersion: 1;
19
+ }
package/src/types/meta.ts CHANGED
@@ -10,7 +10,7 @@ export interface MetaData {
10
10
  */
11
11
  backgroundColor?: string;
12
12
  description?: string;
13
- tag?: string[];
13
+ tags?: string[];
14
14
  /**
15
15
  * 名称
16
16
  * @description 可选参数,如果不传则使用默认名称
@@ -11,7 +11,7 @@ export const filterWithKeywords = <T extends BaseDataModel>(
11
11
  Object.entries(map).filter(([, item]) => {
12
12
  const meta = item.meta;
13
13
 
14
- const keyList = [meta.title, meta.description, meta.tag?.join('')].filter(
14
+ const keyList = [meta.title, meta.description, meta.tags?.join('')].filter(
15
15
  Boolean,
16
16
  ) as string[];
17
17
 
@@ -0,0 +1,22 @@
1
+ export const findDuplicates = (arr: string[]): string[] => {
2
+ const duplicates: { [key: string]: number } = {};
3
+
4
+ // 统计每个项目出现的次数
5
+ for (const item of arr) {
6
+ if (duplicates[item]) {
7
+ duplicates[item]++;
8
+ } else {
9
+ duplicates[item] = 1;
10
+ }
11
+ }
12
+
13
+ // 挑出重复出现 3 次以上的项目
14
+ const COUNT = 3;
15
+
16
+ const result = Object.keys(duplicates).filter((item) => duplicates[item] >= COUNT);
17
+
18
+ // 按重复次数从多到少排序
19
+ result.sort((a, b) => duplicates[b] - duplicates[a]);
20
+
21
+ return result;
22
+ };
@@ -1,18 +0,0 @@
1
- import { consola } from 'consola';
2
- import { colors } from 'consola/utils';
3
- import fs from 'node:fs';
4
- import { resolve } from 'node:path';
5
-
6
- import i18nConfig from '../.i18nrc';
7
-
8
- export const genDefaultLocale = (input: string) => {
9
- consola.info(`Default locale is ${i18nConfig.entryLocale}...`);
10
- const resources = require(`../${input}/${i18nConfig.entryLocale}`);
11
- const data = Object.entries(resources.default);
12
- consola.start(`Generate default locale json, found ${data.length} namespaces...`);
13
- for (const [ns, value] of data) {
14
- const filepath = resolve(i18nConfig.output, i18nConfig.entryLocale, `${ns}.json`);
15
- fs.writeFileSync(filepath, JSON.stringify(value, null, 2));
16
- consola.success(colors.bgWhiteBright(colors.black(` ${ns} `)), colors.gray(filepath));
17
- }
18
- };
@@ -1,51 +0,0 @@
1
- import { consola } from 'consola';
2
- import { colors } from 'consola/utils';
3
- import { tocForResources } from 'i18next-resources-for-ts';
4
- import fs from 'node:fs';
5
- import { resolve } from 'node:path';
6
-
7
- import i18nConfig from '../.i18nrc.js';
8
-
9
- const locales = [i18nConfig.entryLocale, ...i18nConfig.outputLocales];
10
- export const genResources = (output: string) => {
11
- let index = '';
12
- let indexObj = '';
13
- consola.start(`Generate locale resources and types, found ${locales.length} locales...`);
14
- for (const locale of locales) {
15
- const files = fs
16
- .readdirSync(resolve(i18nConfig.output, locale))
17
- .filter((name) => name.includes('.json'));
18
- index += `import ${locale} from "./${locale}";\n`;
19
- indexObj += ` "${locale.replace('_', '-')}": ${locale},\n`;
20
- const ns = [];
21
- for (const file of files) {
22
- ns.push({
23
- name: file.replace('.json', ''),
24
- path: resolve(i18nConfig.output, locale, file),
25
- });
26
- }
27
- let toc = tocForResources(ns, resolve(output)).replaceAll('\\', '/');
28
- if (locale === i18nConfig.entryLocale) {
29
- toc = toc.replaceAll('.json', '').replaceAll('../../../locales/zh_CN', '../default');
30
- }
31
- const filepath = resolve(output, `${locale}.ts`);
32
- fs.writeFileSync(filepath, toc);
33
- consola.success(colors.bgBlue(colors.black(` ${locale} `)), colors.gray(filepath));
34
- }
35
- const indexFilepath = resolve(output, `index.ts`);
36
- fs.writeFileSync(
37
- indexFilepath,
38
- `${index}
39
- const resources = {
40
- ${indexObj}} as const;
41
- export default resources;
42
- export const defaultResources = ${i18nConfig.entryLocale};
43
- export type Resources = typeof resources;
44
- export type DefaultResources = typeof defaultResources;
45
- export type Namespaces = keyof DefaultResources;
46
- export type Locales = keyof Resources;
47
- `,
48
- );
49
-
50
- consola.success(colors.bgGreen(colors.black(` INDEX `)), colors.gray(indexFilepath));
51
- };
package/scripts/toc.ts DELETED
@@ -1,7 +0,0 @@
1
- import { genDefaultLocale } from './genDefaultLocale';
2
- import { genResources } from './genResources';
3
-
4
- const RES_OUTPUT = 'src/locales/resources';
5
-
6
- genDefaultLocale(RES_OUTPUT);
7
- genResources(RES_OUTPUT);
@@ -1,63 +0,0 @@
1
- import { ActionIcon, DivProps } from '@lobehub/ui';
2
- import { X } from 'lucide-react';
3
- import Image from 'next/image';
4
- import { memo } from 'react';
5
- import { Flexbox } from 'react-layout-kit';
6
- import useMergeState from 'use-merge-value';
7
-
8
- import { useStyles } from './style';
9
-
10
- interface EmptyProps extends DivProps {
11
- alt: string;
12
- cover: string;
13
- defaultVisible?: boolean;
14
- desc: string;
15
- height?: number;
16
- onVisibleChange?: (visible: boolean) => void;
17
- title: string;
18
- visible?: boolean;
19
- width?: number;
20
- }
21
-
22
- const Empty = memo<EmptyProps>(
23
- ({
24
- cover,
25
- visible,
26
- defaultVisible,
27
- onVisibleChange,
28
- alt,
29
- title,
30
- desc,
31
- width,
32
- height,
33
- ...props
34
- }) => {
35
- const [value, setValue] = useMergeState(true, {
36
- defaultValue: defaultVisible,
37
- onChange: onVisibleChange,
38
- value: visible,
39
- });
40
-
41
- const { styles } = useStyles();
42
- if (!value) return null;
43
- return (
44
- <Flexbox className={styles.container} {...props}>
45
- <ActionIcon
46
- className={styles.close}
47
- icon={X}
48
- onClick={() => setValue(false)}
49
- size={{ blockSize: 24, fontSize: 16 }}
50
- />
51
- {cover && (
52
- <Image alt={alt} className={styles.image} height={height} src={cover} width={width} />
53
- )}
54
- <div className={styles.content}>
55
- {title && <h3>{title}</h3>}
56
- {desc && <p className={styles.desc}>{desc}</p>}
57
- </div>
58
- </Flexbox>
59
- );
60
- },
61
- );
62
-
63
- export default Empty;
@@ -1,31 +0,0 @@
1
- import { createStyles } from 'antd-style';
2
-
3
- export const useStyles = createStyles(({ css, token, isDarkMode }) => ({
4
- close: css`
5
- position: absolute;
6
- top: 8px;
7
- right: 8px;
8
- `,
9
- container: css`
10
- position: relative;
11
-
12
- overflow: hidden;
13
-
14
- background: linear-gradient(
15
- to bottom,
16
- ${isDarkMode ? token.colorBgElevated : token.colorBgLayout},
17
- ${token.colorBgContainer}
18
- );
19
- border: 1px solid ${token.colorBorderSecondary};
20
- border-radius: ${token.borderRadius}px;
21
- `,
22
- content: css`
23
- padding: 0 16px 16px;
24
- `,
25
- desc: css`
26
- color: ${token.colorTextDescription};
27
- `,
28
- image: css`
29
- align-self: center;
30
- `,
31
- }));