@bbki.ng/site 5.6.7 → 5.8.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.
- package/CHANGELOG.md +12 -0
- package/index.html +1 -12
- package/package.json +1 -1
- package/src/app/app.tsx +46 -0
- package/src/{blog → app}/components/BaseLayout.tsx +2 -2
- package/src/{blog/pages → app/components}/cover/index.tsx +12 -13
- package/src/app/constants/index.ts +1 -0
- package/src/{blog → app}/context/bbcontext.tsx +2 -2
- package/src/{blog/hooks/use_loading.ts → app/hooks/use_global_loading.ts} +1 -1
- package/src/{blog → app}/hooks/use_paths.ts +14 -12
- package/src/{blog → app}/hooks/use_plugin_entries.ts +1 -3
- package/src/{blog → app}/index.tsx +2 -2
- package/src/{blog → app}/main.css +3 -3
- package/src/{blog → app}/swr.tsx +1 -1
- package/src/{blog → app}/utils/index.ts +1 -1
- package/src/core/components/SlotComp.tsx +2 -3
- package/src/core/hooks/useMiddlewareTransData.ts +12 -7
- package/src/core/hooks/useSlotComp.ts +8 -7
- package/src/core/hooks/use_plugins.ts +28 -15
- package/src/core/{pluginManager.ts → plugin-system/pluginManager.ts} +26 -43
- package/src/core/{pluginManifestService.ts → plugin-system/pluginManifestService.ts} +4 -4
- package/src/core/plugin-system/pluginStore.ts +190 -0
- package/src/core/{registry.ts → plugin-system/registry.ts} +1 -3
- package/src/core/plugin-system/services/coreService.ts +56 -0
- package/src/core/plugin-system/services/systemUIService.ts +159 -0
- package/src/core/shared-service/contract/ICoreService.ts +23 -0
- package/src/core/shared-service/contract/IUIService.ts +49 -0
- package/src/core/shared-service/service-proxy.ts +26 -0
- package/src/core/shared-service/service-registry.ts +52 -0
- package/src/index.tsx +3 -3
- package/src/plugins/blog/components/BlogSlotCom.tsx +27 -0
- package/src/plugins/blog/components/app.tsx +15 -0
- package/src/{blog → plugins/blog}/components/article/index.tsx +2 -2
- package/src/plugins/blog/constants/index.ts +1 -0
- package/src/plugins/blog/context/index.ts +7 -0
- package/src/plugins/blog/hooks/useMiddlewareTransData.ts +79 -0
- package/src/{blog → plugins/blog}/hooks/use_blog_scroll_pos_restoration.ts +4 -6
- package/src/plugins/blog/hooks/use_blog_slot_com.ts +27 -0
- package/src/{blog → plugins/blog}/hooks/use_posts.ts +11 -11
- package/src/plugins/blog/index.ts +61 -0
- package/src/{blog → plugins/blog}/pages/extensions/txt/article.tsx +5 -5
- package/src/{blog → plugins/blog}/pages/extensions/txt/index.tsx +6 -3
- package/src/plugins/blog/services/BlogUIService.ts +120 -0
- package/src/plugins/blog/services/IBlogUIService.ts +31 -0
- package/src/plugins/extra-cd/index.ts +13 -2
- package/src/plugins/extra-entry/index.ts +8 -4
- package/src/plugins/fx/index.ts +18 -5
- package/src/plugins/manifest.ts +8 -6
- package/src/plugins/now/hooks/use_streaming.ts +3 -1
- package/src/plugins/now/index.ts +17 -6
- package/src/plugins/sticker/const.ts +2 -2
- package/src/plugins/sticker/index.ts +18 -3
- package/src/plugins/store/components/storePage.tsx +15 -4
- package/src/plugins/store/context/index.ts +1 -0
- package/src/plugins/store/index.ts +18 -7
- package/src/plugins/xwy/index.ts +24 -19
- package/src/plugins/xwy/types/index.ts +0 -18
- package/src/types/hostApi.ts +3 -33
- package/src/types/plugin.ts +2 -0
- package/src/utils/index.tsx +12 -44
- package/tsconfig.json +0 -1
- package/vite.config.js +1 -1
- package/src/blog/app.tsx +0 -52
- package/src/blog/constants/index.ts +0 -1
- package/src/blog/constants/routes.ts +0 -20
- package/src/blog/hooks/index.ts +0 -2
- package/src/blog/hooks/use_blog_context.ts +0 -14
- package/src/blog/hooks/use_mouse_position.ts +0 -17
- package/src/blog/hooks/use_role.ts +0 -14
- package/src/blog/hooks/use_sticker.ts +0 -11
- package/src/blog/pages/index.tsx +0 -2
- package/src/blog/pages/login/index.tsx +0 -24
- package/src/blog/types/blog-context.ts +0 -6
- package/src/blog/types/font.ts +0 -4
- package/src/blog/types/glsl.d.ts +0 -8
- package/src/core/pluginStore.ts +0 -70
- /package/src/{blog/pages → app/components}/bot/index.tsx +0 -0
- /package/src/{blog → app}/context/global_loading_state_provider.tsx +0 -0
- /package/src/{blog → app}/context/global_routes_provider.tsx +0 -0
- /package/src/{blog → app}/hooks/use_pathname.ts +0 -0
- /package/src/{blog → app}/utils/fingerprints.ts +0 -0
- /package/src/core/{bbplugin.ts → plugin-system/bbplugin.ts} +0 -0
- /package/src/{blog → plugins/blog}/components/index.tsx +0 -0
- /package/src/{blog/types → types}/path.ts +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BBPlugin } from '#/core/bbplugin';
|
|
1
|
+
import { BBPlugin } from '#/core/plugin-system/bbplugin';
|
|
2
2
|
import { IHostContext } from '#/types/hostApi';
|
|
3
3
|
import { PluginID } from '#/types/plugin';
|
|
4
4
|
|
|
@@ -9,8 +9,17 @@ class Sticker extends BBPlugin {
|
|
|
9
9
|
id: PluginID = 'sticker';
|
|
10
10
|
|
|
11
11
|
private createPluginCtx = async (ctx: IHostContext): Promise<IStickerCtx> => {
|
|
12
|
+
const coreService = ctx.service.get('core:baseService');
|
|
13
|
+
|
|
14
|
+
if (!coreService) {
|
|
15
|
+
console.error('Core service not found. StickerPlugin installation failed.');
|
|
16
|
+
return {
|
|
17
|
+
deviceId: '',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
12
21
|
return {
|
|
13
|
-
deviceId: (await
|
|
22
|
+
deviceId: (await coreService.getDeviceId()).id,
|
|
14
23
|
};
|
|
15
24
|
};
|
|
16
25
|
|
|
@@ -21,7 +30,13 @@ class Sticker extends BBPlugin {
|
|
|
21
30
|
|
|
22
31
|
const Sticker = withCtx(pluginCtx, StickerCom);
|
|
23
32
|
|
|
24
|
-
ctx.
|
|
33
|
+
const systemUIService = ctx.service.get('core:uiService');
|
|
34
|
+
if (!systemUIService) {
|
|
35
|
+
console.error('UI service not found. StickerPlugin installation failed.');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
systemUIService.registerSlot('leftCol', Sticker, this.id);
|
|
25
40
|
};
|
|
26
41
|
}
|
|
27
42
|
|
|
@@ -25,7 +25,7 @@ const ErrorState = ({ error, onRetry }: { error: Error; onRetry: () => void }) =
|
|
|
25
25
|
);
|
|
26
26
|
|
|
27
27
|
export const StorePage = (_: IComPropsRegisteredToSlot) => {
|
|
28
|
-
const { list, setLoading, isInstalled, install, uninstall } = StoreCtx.useCtx();
|
|
28
|
+
const { list, setLoading, isInstalled, install, uninstall, get } = StoreCtx.useCtx();
|
|
29
29
|
const [plugins, setPlugins] = useState<Array<IPluginStoreEntry>>([]);
|
|
30
30
|
const [error, setError] = useState<Error | null>(null);
|
|
31
31
|
|
|
@@ -106,8 +106,9 @@ export const StorePage = (_: IComPropsRegisteredToSlot) => {
|
|
|
106
106
|
const headerRenderer = useCallback(() => {
|
|
107
107
|
return (
|
|
108
108
|
<>
|
|
109
|
-
<Table.HCell
|
|
110
|
-
<Table.HCell
|
|
109
|
+
<Table.HCell>功能</Table.HCell>
|
|
110
|
+
<Table.HCell>描述</Table.HCell>
|
|
111
|
+
<Table.HCell>依赖</Table.HCell>
|
|
111
112
|
<Table.HCell style={{ textAlign: 'right' }}>安装/卸载</Table.HCell>
|
|
112
113
|
</>
|
|
113
114
|
);
|
|
@@ -126,6 +127,16 @@ export const StorePage = (_: IComPropsRegisteredToSlot) => {
|
|
|
126
127
|
<>
|
|
127
128
|
<Table.Cell>{plugin.name}</Table.Cell>
|
|
128
129
|
<Table.Cell>{plugin.description}</Table.Cell>
|
|
130
|
+
<Table.Cell>
|
|
131
|
+
{plugin.dependencies && plugin.dependencies.length > 0
|
|
132
|
+
? plugin.dependencies
|
|
133
|
+
.map(dep => {
|
|
134
|
+
const depPlugin = get(dep);
|
|
135
|
+
return depPlugin ? depPlugin.name : dep;
|
|
136
|
+
})
|
|
137
|
+
.join(', ')
|
|
138
|
+
: ''}
|
|
139
|
+
</Table.Cell>
|
|
129
140
|
<Table.Cell style={{ textAlign: 'right' }}>
|
|
130
141
|
{pluginInstalled ? (
|
|
131
142
|
<Button
|
|
@@ -144,7 +155,7 @@ export const StorePage = (_: IComPropsRegisteredToSlot) => {
|
|
|
144
155
|
</>
|
|
145
156
|
);
|
|
146
157
|
},
|
|
147
|
-
[plugins, isInstalled,
|
|
158
|
+
[plugins, isInstalled, get, handleUninstall, handleInstall]
|
|
148
159
|
);
|
|
149
160
|
|
|
150
161
|
if (error) {
|
|
@@ -6,6 +6,7 @@ export interface IStoreCtx {
|
|
|
6
6
|
uninstall: (pid: PluginID) => Promise<void>;
|
|
7
7
|
isInstalled: (pid: PluginID) => boolean;
|
|
8
8
|
list: () => Promise<Array<IPluginStoreEntry>> | Array<IPluginStoreEntry>;
|
|
9
|
+
get: (pid: PluginID) => IPluginStoreEntry | undefined;
|
|
9
10
|
setLoading: (loading: boolean) => void;
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { BBPlugin } from '#/core/bbplugin';
|
|
1
|
+
import { BBPlugin } from '#/core/plugin-system/bbplugin';
|
|
2
2
|
import { IHostContext } from '#/types/hostApi';
|
|
3
3
|
import { PluginID } from '#/types/plugin';
|
|
4
|
-
import { buildEntryCreator } from '#/utils';
|
|
5
4
|
|
|
6
5
|
import { StorePage } from './components/storePage';
|
|
7
6
|
import { StoreCtx } from './context';
|
|
@@ -9,8 +8,19 @@ import { StoreCtx } from './context';
|
|
|
9
8
|
export class StorePlugin extends BBPlugin {
|
|
10
9
|
id: PluginID = 'store';
|
|
11
10
|
override onInstall = async (ctx: IHostContext): Promise<void> => {
|
|
12
|
-
const
|
|
13
|
-
|
|
11
|
+
const coreService = ctx.service.get('core:baseService');
|
|
12
|
+
if (!coreService) {
|
|
13
|
+
console.error('Core service not found. StorePlugin installation failed.');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const systemUIService = ctx.service.get('core:uiService');
|
|
18
|
+
if (!systemUIService) {
|
|
19
|
+
console.error('UI service not found. StorePlugin installation failed.');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
systemUIService.registerPluginEntry(
|
|
14
24
|
{
|
|
15
25
|
path: '/store',
|
|
16
26
|
label: 'cd ./store',
|
|
@@ -19,14 +29,15 @@ export class StorePlugin extends BBPlugin {
|
|
|
19
29
|
install: ctx.store?.installPlugin || (async () => {}),
|
|
20
30
|
uninstall: ctx.store?.disablePlugin || (async () => {}),
|
|
21
31
|
isInstalled: ctx.store?.isPluginInstalled || ((_: PluginID) => false),
|
|
32
|
+
get: ctx.store?.getPlugin || ((_: PluginID) => undefined),
|
|
22
33
|
list: async () => {
|
|
23
|
-
|
|
34
|
+
coreService.setLoading('store', true);
|
|
24
35
|
const all = Array.from((await ctx.store?.getAllPlugins()) || []);
|
|
25
|
-
|
|
36
|
+
coreService.setLoading('store', false);
|
|
26
37
|
return all.filter(({ id }) => id !== this.id);
|
|
27
38
|
},
|
|
28
39
|
setLoading: (loading: boolean) => {
|
|
29
|
-
|
|
40
|
+
coreService.setLoading('store', loading);
|
|
30
41
|
},
|
|
31
42
|
},
|
|
32
43
|
StorePage
|
package/src/plugins/xwy/index.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { IHostContext } from '#/types/hostApi';
|
|
2
|
-
import { BBPlugin } from '#/core/bbplugin';
|
|
3
|
-
import { HookPoint } from '#/types/slots';
|
|
2
|
+
import { BBPlugin } from '#/core/plugin-system/bbplugin';
|
|
4
3
|
import { PluginID } from '#/types/plugin';
|
|
5
4
|
|
|
6
|
-
import { HookPointTypeMap, Transformer } from './types';
|
|
7
5
|
import { SpecialTitle } from './components/article';
|
|
8
6
|
import { XwyLogo } from './components/logo';
|
|
9
7
|
import { FontRules, LOADING_CLASS } from './const';
|
|
@@ -35,27 +33,34 @@ class XwyPlugin extends BBPlugin {
|
|
|
35
33
|
this.batchRegisterMiddlewares(ctx);
|
|
36
34
|
|
|
37
35
|
// 注册logo插槽组件
|
|
38
|
-
ctx.
|
|
36
|
+
const systemUIService = ctx.service.get('core:uiService');
|
|
37
|
+
systemUIService?.registerSlot('logo', XwyLogo, this.id);
|
|
39
38
|
|
|
40
39
|
// 注册「小乌鸦合集」标题组件
|
|
41
|
-
ctx.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
private trasformerMap: {
|
|
45
|
-
[K in Extract<HookPoint, keyof HookPointTypeMap>]?: Array<Transformer<K>>;
|
|
46
|
-
} = {
|
|
47
|
-
transformTitleList: [pinTitle, transformTitleList],
|
|
48
|
-
transformBreadcrumbPath: [transformBreadcrumbPaths],
|
|
49
|
-
transformPostContent: [transformPostContent],
|
|
40
|
+
const blogUIService = ctx.service.get('blog:uiService');
|
|
41
|
+
blogUIService?.registerSlot('blog:articleTitle', SpecialTitle, this.id);
|
|
50
42
|
};
|
|
51
43
|
|
|
52
44
|
private batchRegisterMiddlewares(ctx: IHostContext) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
45
|
+
const blogUIService = ctx.service.get('blog:uiService');
|
|
46
|
+
const systemUIService = ctx.service.get('core:uiService');
|
|
47
|
+
|
|
48
|
+
if (!blogUIService || !systemUIService) {
|
|
49
|
+
console.warn(`[${this.id}] Required UI services not found, skipping middleware registration`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 注册博客相关的中间件
|
|
54
|
+
for (const transformer of [pinTitle, transformTitleList]) {
|
|
55
|
+
blogUIService.registerMiddleware('blog:transformTitleList', transformer, this.id);
|
|
56
|
+
}
|
|
57
|
+
for (const transformer of [transformPostContent]) {
|
|
58
|
+
blogUIService.registerMiddleware('blog:transformPostContent', transformer, this.id);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 注册系统相关的中间件
|
|
62
|
+
for (const transformer of [transformBreadcrumbPaths]) {
|
|
63
|
+
systemUIService.registerMiddleware('transformBreadcrumbPath', transformer, this.id);
|
|
59
64
|
}
|
|
60
65
|
}
|
|
61
66
|
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import { PathObj } from '@bbki.ng/ui';
|
|
2
|
-
|
|
3
|
-
import { TitleListItem } from '#/types/posts';
|
|
4
|
-
|
|
5
1
|
export interface FontConfig {
|
|
6
2
|
name: string;
|
|
7
3
|
src: string;
|
|
@@ -19,17 +15,3 @@ export interface FontRule {
|
|
|
19
15
|
extraCls?: string;
|
|
20
16
|
variant?: 'default' | 'special';
|
|
21
17
|
}
|
|
22
|
-
|
|
23
|
-
// 1. 先定义每个 HookPoint 对应的类型映射
|
|
24
|
-
export interface HookPointTypeMap {
|
|
25
|
-
transformTitleList: { input: TitleListItem[]; output: TitleListItem[] };
|
|
26
|
-
transformBreadcrumbPath: { input: PathObj[]; output: PathObj[] };
|
|
27
|
-
transformPostContent: { input: string; output: string };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
type HookPoint = keyof HookPointTypeMap;
|
|
31
|
-
|
|
32
|
-
// 2. 定义带类型的 Transformer
|
|
33
|
-
export type Transformer<K extends HookPoint> = (
|
|
34
|
-
baseData: HookPointTypeMap[K]['input']
|
|
35
|
-
) => HookPointTypeMap[K]['output'];
|
package/src/types/hostApi.ts
CHANGED
|
@@ -1,37 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { type FingerprintData } from '@/utils/fingerprints';
|
|
5
|
-
import { PluginStore } from '#/core/pluginStore';
|
|
6
|
-
|
|
7
|
-
import { HookPoint, IComPropsRegisteredToSlot, SlotName } from './slots';
|
|
8
|
-
import { PluginEvents, PluginID } from './plugin';
|
|
9
|
-
|
|
10
|
-
export interface IHostApi {
|
|
11
|
-
getDeviceId: () => Promise<{ id: string; fp: FingerprintData }>;
|
|
12
|
-
getVersionHash: () => Promise<string> | string;
|
|
13
|
-
setLoading: (id: PluginID, loading: boolean) => void;
|
|
14
|
-
onLoadingChanged: (
|
|
15
|
-
listener: (payload: PluginEvents['site:loading:changed']) => void
|
|
16
|
-
) => () => void;
|
|
17
|
-
registerMiddleware: <T>(
|
|
18
|
-
point: HookPoint,
|
|
19
|
-
fn: (baseData: T) => T,
|
|
20
|
-
pluginId: string,
|
|
21
|
-
weight?: number
|
|
22
|
-
) => void;
|
|
23
|
-
registerSlot: (
|
|
24
|
-
slotName: SlotName,
|
|
25
|
-
component: React.ComponentType<IComPropsRegisteredToSlot>,
|
|
26
|
-
pluginId: string,
|
|
27
|
-
weight?: number
|
|
28
|
-
) => void;
|
|
29
|
-
fetch: Fetcher;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export type PluginInitializer = (api: IHostApi) => void;
|
|
1
|
+
import { PluginStore } from '#/core/plugin-system/pluginStore';
|
|
2
|
+
import { type ServiceRegistry } from '#/core/shared-service/service-registry';
|
|
33
3
|
|
|
34
4
|
export interface IHostContext {
|
|
35
5
|
store?: PluginStore;
|
|
36
|
-
|
|
6
|
+
service: ServiceRegistry;
|
|
37
7
|
}
|
package/src/types/plugin.ts
CHANGED
|
@@ -21,6 +21,7 @@ export type PluginID =
|
|
|
21
21
|
| 'store'
|
|
22
22
|
| 'now'
|
|
23
23
|
| 'default'
|
|
24
|
+
| 'blog'
|
|
24
25
|
| 'fx';
|
|
25
26
|
|
|
26
27
|
export interface IPluginEntry {
|
|
@@ -30,6 +31,7 @@ export interface IPluginEntry {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
export type PluginEvents = {
|
|
34
|
+
'plugin:uninstall': PluginID;
|
|
33
35
|
'plugin:loading:changed': IPluginLoadingPayload;
|
|
34
36
|
'site:loading:changed': boolean;
|
|
35
37
|
};
|
package/src/utils/index.tsx
CHANGED
|
@@ -1,52 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PathRouteProps } from 'react-router-dom';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
|
-
import { IHostContext } from '#/types/hostApi';
|
|
5
4
|
import { IPluginEntry } from '#/types/plugin';
|
|
6
5
|
import { IComPropsRegisteredToSlot } from '#/types/slots';
|
|
7
6
|
|
|
8
|
-
export const
|
|
9
|
-
|
|
10
|
-
'
|
|
11
|
-
(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
];
|
|
18
|
-
},
|
|
19
|
-
id,
|
|
20
|
-
10
|
|
21
|
-
);
|
|
7
|
+
export const buildEntrySlotCom = (entry: IPluginEntry) => {
|
|
8
|
+
const Component = (props: IComPropsRegisteredToSlot) => {
|
|
9
|
+
const route = props.data as Omit<PathRouteProps, 'element'>;
|
|
10
|
+
if (route.path === entry.path) {
|
|
11
|
+
const Com = entry.pageComponent;
|
|
12
|
+
return <Com data={props.data} />;
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
};
|
|
22
16
|
|
|
23
|
-
|
|
24
|
-
'route',
|
|
25
|
-
(props: IComPropsRegisteredToSlot) => {
|
|
26
|
-
const route = props.data as Omit<PathRouteProps, 'element'>;
|
|
27
|
-
if (route.path === entry.path) {
|
|
28
|
-
const Com = entry.pageComponent;
|
|
29
|
-
return <Com data={props.data} />;
|
|
30
|
-
}
|
|
31
|
-
return null;
|
|
32
|
-
},
|
|
33
|
-
id
|
|
34
|
-
);
|
|
17
|
+
Component.displayName = `EntrySlotCom(${entry.path})`;
|
|
35
18
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
ctx.api.registerMiddleware(
|
|
39
|
-
'transformCoverEntry',
|
|
40
|
-
(entries: Array<LinkProps>) => {
|
|
41
|
-
return [
|
|
42
|
-
...entries,
|
|
43
|
-
{
|
|
44
|
-
to: entry.path,
|
|
45
|
-
children: entry.label,
|
|
46
|
-
},
|
|
47
|
-
];
|
|
48
|
-
},
|
|
49
|
-
id,
|
|
50
|
-
10
|
|
51
|
-
);
|
|
19
|
+
return Component;
|
|
52
20
|
};
|
package/tsconfig.json
CHANGED
package/vite.config.js
CHANGED
package/src/blog/app.tsx
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Outlet, Route, Routes } from 'react-router-dom';
|
|
3
|
-
import { NotFound } from '@bbki.ng/ui';
|
|
4
|
-
|
|
5
|
-
import ArticlePage from '@/pages/extensions/txt/article';
|
|
6
|
-
import Txt from '@/pages/extensions/txt';
|
|
7
|
-
import { BotRedirect } from '@/pages/bot';
|
|
8
|
-
import { BBContext } from '@/context/bbcontext';
|
|
9
|
-
import { Slot } from '#/core/components/SlotComp';
|
|
10
|
-
import { usePlugins } from '#/core/hooks/use_plugins';
|
|
11
|
-
import { SWR } from '@/swr';
|
|
12
|
-
|
|
13
|
-
import { Cover } from './pages';
|
|
14
|
-
import { usePluginEntries } from './hooks/use_plugin_entries';
|
|
15
|
-
import { BaseLayout } from './components/BaseLayout';
|
|
16
|
-
|
|
17
|
-
const AppRoutes = () => {
|
|
18
|
-
usePlugins();
|
|
19
|
-
|
|
20
|
-
const pluginEntries = usePluginEntries();
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<Routes>
|
|
24
|
-
<Route path="/" element={<BaseLayout />}>
|
|
25
|
-
<Route index element={<Cover />} />
|
|
26
|
-
|
|
27
|
-
<Route path="blog" element={<Outlet />}>
|
|
28
|
-
<Route path="" element={<Txt />} />
|
|
29
|
-
<Route path=":title" element={<ArticlePage />} />
|
|
30
|
-
</Route>
|
|
31
|
-
|
|
32
|
-
<Route path="bot" element={<BotRedirect />} />
|
|
33
|
-
{pluginEntries?.map(route => (
|
|
34
|
-
<Route key={route.path} path={route.path} element={<Slot name="route" data={route} />} />
|
|
35
|
-
))}
|
|
36
|
-
<Route path="*" element={pluginEntries?.length ? <NotFound /> : null} />
|
|
37
|
-
</Route>
|
|
38
|
-
</Routes>
|
|
39
|
-
);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const App = () => {
|
|
43
|
-
return (
|
|
44
|
-
<SWR>
|
|
45
|
-
<BBContext>
|
|
46
|
-
<AppRoutes />
|
|
47
|
-
</BBContext>
|
|
48
|
-
</SWR>
|
|
49
|
-
);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export default App;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { ROUTES, ROUTE_NAME, GITHUB_REPO_ADDRESS } from './routes';
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export const ROUTES = {
|
|
2
|
-
INDEX: '/',
|
|
3
|
-
CONTENT: '/blog',
|
|
4
|
-
HELP: '/blog/说明书',
|
|
5
|
-
TAGS: '/tags',
|
|
6
|
-
LOGIN: '/login',
|
|
7
|
-
BLOG: '/blog',
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const ROUTE_NAME = {
|
|
11
|
-
[ROUTES.CONTENT]: '目录',
|
|
12
|
-
[ROUTES.BLOG]: '文章',
|
|
13
|
-
unknown: '未知',
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export const GITHUB_REPO_ADDRESS = 'https://github.com/bbbottle/bottle/tree/main/apps/site';
|
|
17
|
-
export const API_ENDPOINT = 'https://cf.bbki.ng';
|
|
18
|
-
export const API = {
|
|
19
|
-
POSTS: 'posts',
|
|
20
|
-
};
|
package/src/blog/hooks/index.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { GlobalLoadingContext } from '@/context/global_loading_state_provider';
|
|
2
|
-
import { IBlogContext } from '@/types/blog-context';
|
|
3
|
-
import { useContext } from 'react';
|
|
4
|
-
import { useLocation } from 'react-router-dom';
|
|
5
|
-
|
|
6
|
-
export const useBlogContext = (): IBlogContext => {
|
|
7
|
-
const globalLoading = useContext(GlobalLoadingContext);
|
|
8
|
-
const location = useLocation();
|
|
9
|
-
|
|
10
|
-
return {
|
|
11
|
-
gloalLoading: globalLoading.isLoading,
|
|
12
|
-
location,
|
|
13
|
-
};
|
|
14
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef } from 'react';
|
|
2
|
-
|
|
3
|
-
export const useMousePosition = () => {
|
|
4
|
-
const posRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
|
|
5
|
-
useEffect(() => {
|
|
6
|
-
const updateMousePosition = (e: MouseEvent) => {
|
|
7
|
-
posRef.current = {
|
|
8
|
-
x: e.clientX,
|
|
9
|
-
y: e.clientY,
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
window.addEventListener('mousemove', updateMousePosition);
|
|
13
|
-
return () => window.removeEventListener('mousemove', updateMousePosition);
|
|
14
|
-
}, []);
|
|
15
|
-
|
|
16
|
-
return posRef;
|
|
17
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export enum Role {
|
|
2
|
-
KING = 'king',
|
|
3
|
-
QUEEN = 'queen',
|
|
4
|
-
ANNO = 'anno',
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Returns user role
|
|
9
|
-
* Currently always returns ANNO as role-based authentication is now handled via API keys in CLI
|
|
10
|
-
* Frontend role management may be re-implemented in the future
|
|
11
|
-
*/
|
|
12
|
-
export const useRole = (): Role => {
|
|
13
|
-
return Role.ANNO;
|
|
14
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { pluginManager } from '#/core/pluginManager';
|
|
2
|
-
import { useEffect } from 'react';
|
|
3
|
-
export const useSticker = () => {
|
|
4
|
-
useEffect(() => {
|
|
5
|
-
pluginManager.loadPlugin('sticker');
|
|
6
|
-
|
|
7
|
-
return () => {
|
|
8
|
-
pluginManager.disablePlugin('sticker');
|
|
9
|
-
};
|
|
10
|
-
}, []);
|
|
11
|
-
};
|
package/src/blog/pages/index.tsx
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ArticlePage } from '@/components/article';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Login page
|
|
6
|
-
* Note: OAuth authentication has been removed. Authentication is now handled
|
|
7
|
-
* via API keys in the CLI tool. Frontend authentication may be re-implemented
|
|
8
|
-
* in the future.
|
|
9
|
-
*/
|
|
10
|
-
export const Login = () => {
|
|
11
|
-
return (
|
|
12
|
-
<ArticlePage title="登录">
|
|
13
|
-
<div className="prose dark:prose-invert">
|
|
14
|
-
<p className="text-gray-600 dark:text-gray-400">网页登录功能已暂时禁用。</p>
|
|
15
|
-
<p className="text-gray-600 dark:text-gray-400">
|
|
16
|
-
如需管理内容,请使用 CLI 工具并通过 API Key 进行认证:
|
|
17
|
-
</p>
|
|
18
|
-
<pre className="bg-gray-100 dark:bg-gray-800 p-4 rounded">
|
|
19
|
-
<code>bbking login</code>
|
|
20
|
-
</pre>
|
|
21
|
-
</div>
|
|
22
|
-
</ArticlePage>
|
|
23
|
-
);
|
|
24
|
-
};
|
package/src/blog/types/font.ts
DELETED
package/src/blog/types/glsl.d.ts
DELETED
package/src/core/pluginStore.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { IPluginStoreEntry, PluginID } from '#/types/plugin';
|
|
2
|
-
|
|
3
|
-
import { pluginManager } from './pluginManager';
|
|
4
|
-
import { PluginManifestService } from './pluginManifestService';
|
|
5
|
-
|
|
6
|
-
export class PluginStore {
|
|
7
|
-
private static instance: PluginStore;
|
|
8
|
-
|
|
9
|
-
private installedSet: Set<PluginID> = new Set();
|
|
10
|
-
|
|
11
|
-
private constructor() {
|
|
12
|
-
this.parse();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
private parse = () => {
|
|
16
|
-
this.installedSet.clear();
|
|
17
|
-
const installedPluginsStr = localStorage.getItem('installed_plugins');
|
|
18
|
-
if (installedPluginsStr) {
|
|
19
|
-
try {
|
|
20
|
-
const entries = JSON.parse(installedPluginsStr) as Array<PluginID>;
|
|
21
|
-
entries.forEach(id => this.installedSet.add(id));
|
|
22
|
-
} catch (e) {
|
|
23
|
-
console.error('Failed to parse installed plugins from localStorage', e);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return this.installedSet;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
private stringify = () => {
|
|
31
|
-
localStorage.setItem('installed_plugins', JSON.stringify(Array.from(this.installedSet)));
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
getInstalledPlugins: () => Set<PluginID> = () => {
|
|
35
|
-
return this.parse();
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
async getAllPlugins(): Promise<Array<IPluginStoreEntry>> {
|
|
39
|
-
const installedPlugins = this.getInstalledPlugins();
|
|
40
|
-
await PluginManifestService.getInstance().fetch();
|
|
41
|
-
const manifest = PluginManifestService.getInstance().getAllPlugins();
|
|
42
|
-
return manifest.map(plugin => ({
|
|
43
|
-
...plugin,
|
|
44
|
-
enabled: installedPlugins.has(plugin.id),
|
|
45
|
-
}));
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
isPluginInstalled: (id: PluginID) => boolean = id => {
|
|
49
|
-
return this.getInstalledPlugins().has(id);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
installPlugin: (id: PluginID) => Promise<void> = async id => {
|
|
53
|
-
await pluginManager.loadPlugin(id);
|
|
54
|
-
this.installedSet.add(id);
|
|
55
|
-
this.stringify();
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
disablePlugin: (id: PluginID) => Promise<void> = async id => {
|
|
59
|
-
await pluginManager.disablePlugin(id);
|
|
60
|
-
this.installedSet.delete(id);
|
|
61
|
-
this.stringify();
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
static getInstance() {
|
|
65
|
-
if (!PluginStore.instance) {
|
|
66
|
-
PluginStore.instance = new PluginStore();
|
|
67
|
-
}
|
|
68
|
-
return PluginStore.instance;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|