@bbki.ng/site 5.8.3 → 5.8.5
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 +14 -0
- package/package.json +2 -2
- package/src/app/app.tsx +4 -8
- package/src/app/components/BaseLayout.tsx +2 -3
- package/src/app/components/cover/index.tsx +23 -15
- package/src/app/hooks/use_plugin_entries.ts +21 -26
- package/src/core/hooks/use_plugins.ts +11 -1
- package/src/core/plugin-system/services/systemUIService.ts +28 -34
- package/src/core/shared-service/contract/IUIService.ts +9 -6
- package/src/plugins/store/components/ArrowCom.tsx +15 -0
- package/src/plugins/store/components/ArrowSvg.tsx +1133 -0
- package/src/plugins/store/components/storeIcon.tsx +16 -0
- package/src/plugins/store/index.ts +6 -1
- package/src/types/slots.ts +0 -17
- package/src/utils/index.tsx +0 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @bbki.ng/site
|
|
2
2
|
|
|
3
|
+
## 5.8.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 6b14c28: add empty placeholder
|
|
8
|
+
|
|
9
|
+
## 5.8.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 5efa382: move store entry to nav
|
|
14
|
+
- Updated dependencies [5efa382]
|
|
15
|
+
- @bbki.ng/ui@0.2.20
|
|
16
|
+
|
|
3
17
|
## 5.8.3
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bbki.ng/site",
|
|
3
|
-
"version": "5.8.
|
|
3
|
+
"version": "5.8.5",
|
|
4
4
|
"description": "code behind bbki.ng",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"react-router-dom": "6",
|
|
16
16
|
"sonner": "^2.0.7",
|
|
17
17
|
"swr": "^2.2.5",
|
|
18
|
-
"@bbki.ng/ui": "0.2.
|
|
18
|
+
"@bbki.ng/ui": "0.2.20"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@eslint/compat": "^1.0.0",
|
package/src/app/app.tsx
CHANGED
|
@@ -3,7 +3,6 @@ import { Route, Routes } from 'react-router-dom';
|
|
|
3
3
|
|
|
4
4
|
import { BotRedirect } from '#/app/components/bot';
|
|
5
5
|
import { BBContext } from '#/app/context/bbcontext';
|
|
6
|
-
import { Slot } from '#/core/components/SlotComp';
|
|
7
6
|
import { usePlugins } from '#/core/hooks/use_plugins';
|
|
8
7
|
import { Cover } from '#/app/components/cover';
|
|
9
8
|
import { SWR } from '#/app/swr';
|
|
@@ -20,13 +19,10 @@ const AppRoutes = () => {
|
|
|
20
19
|
<Route path="/" element={<BaseLayout />}>
|
|
21
20
|
<Route index element={<Cover />} />
|
|
22
21
|
<Route path="bot" element={<BotRedirect />} />
|
|
23
|
-
{pluginEntries?.map(route =>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
element={<Slot name="route" data={route} />}
|
|
28
|
-
/>
|
|
29
|
-
))}
|
|
22
|
+
{pluginEntries?.map(route => {
|
|
23
|
+
const Com = route.pageComponent;
|
|
24
|
+
return <Route key={route.path} path={`${route.path}/*`} element={<Com data={route} />} />;
|
|
25
|
+
})}
|
|
30
26
|
<Route path="*" element={null} />
|
|
31
27
|
</Route>
|
|
32
28
|
</Routes>
|
|
@@ -14,9 +14,7 @@ export const BaseLayout = () => {
|
|
|
14
14
|
|
|
15
15
|
const nav = useNavigate();
|
|
16
16
|
|
|
17
|
-
const defaultLogo = (
|
|
18
|
-
<Logo className="mr-2 cursor-pointer hover:opacity-80" onClick={() => nav('/')} />
|
|
19
|
-
);
|
|
17
|
+
const defaultLogo = <Logo className="cursor-pointer hover:opacity-80" onClick={() => nav('/')} />;
|
|
20
18
|
|
|
21
19
|
return (
|
|
22
20
|
<>
|
|
@@ -31,6 +29,7 @@ export const BaseLayout = () => {
|
|
|
31
29
|
paddingTop: 'calc(var(--safe-top) + 4px)',
|
|
32
30
|
transition: 'all .2s ease-in-out',
|
|
33
31
|
}}
|
|
32
|
+
rightElement={<Slot name="nav-right" data={paths} />}
|
|
34
33
|
/>
|
|
35
34
|
}
|
|
36
35
|
main={
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { LinkProps, LinkListProps, LinkList } from '@bbki.ng/ui';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { usePluginEntries } from '#/app/hooks/use_plugin_entries';
|
|
5
|
+
import { useMiddlewareTransformedData } from '#/core/hooks/useMiddlewareTransData';
|
|
6
|
+
import { Slot } from '#/core/components/SlotComp';
|
|
7
|
+
import { useGlobalLoading } from '#/app/hooks/use_global_loading';
|
|
5
8
|
|
|
6
9
|
const CenterLinkList = (props: LinkListProps) => {
|
|
7
10
|
return (
|
|
@@ -11,25 +14,30 @@ const CenterLinkList = (props: LinkListProps) => {
|
|
|
11
14
|
);
|
|
12
15
|
};
|
|
13
16
|
|
|
14
|
-
const baseEntries: Array<LinkProps> = [];
|
|
15
|
-
|
|
16
17
|
export const Cover = (_: { className?: string }) => {
|
|
17
|
-
const
|
|
18
|
+
const pluginEntries = usePluginEntries();
|
|
19
|
+
|
|
20
|
+
const entries: Array<LinkProps> = React.useMemo(() => {
|
|
21
|
+
return pluginEntries
|
|
22
|
+
.filter(entry => entry.label)
|
|
23
|
+
.map(entry => ({
|
|
24
|
+
to: entry.path,
|
|
25
|
+
children: entry.label,
|
|
26
|
+
})) as Array<LinkProps>;
|
|
27
|
+
}, [pluginEntries]);
|
|
18
28
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
},
|
|
24
|
-
});
|
|
29
|
+
const transformedEntries = useMiddlewareTransformedData(
|
|
30
|
+
'transformEntryLink',
|
|
31
|
+
entries
|
|
32
|
+
) as Array<LinkProps>;
|
|
25
33
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}, [run]);
|
|
34
|
+
const { isLoading } = useGlobalLoading();
|
|
35
|
+
const hasEntries = pluginEntries.length > 1 && !isLoading;
|
|
29
36
|
|
|
30
37
|
return (
|
|
31
38
|
<>
|
|
32
|
-
<CenterLinkList className="select-none" links={
|
|
39
|
+
<CenterLinkList className="select-none" links={transformedEntries} />
|
|
40
|
+
<Slot name="centerEntryArea" data={hasEntries} />
|
|
33
41
|
</>
|
|
34
42
|
);
|
|
35
43
|
};
|
|
@@ -1,39 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { type PathRouteProps } from 'react-router-dom';
|
|
1
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
3
2
|
|
|
4
|
-
import {
|
|
3
|
+
import { SystemUIService } from '#/core/plugin-system/services/systemUIService';
|
|
4
|
+
import { IPluginEntry } from '#/types/plugin';
|
|
5
5
|
|
|
6
6
|
const protectedRoutesSet = new Set<string>(['/bot', '/', 'default']);
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const emptyEntries: Array<IPluginEntry> = [];
|
|
9
9
|
|
|
10
10
|
export const usePluginEntries = () => {
|
|
11
|
-
const [
|
|
12
|
-
|
|
13
|
-
Promise.resolve([])
|
|
11
|
+
const [entries, setEntries] = useState<Array<IPluginEntry>>(() =>
|
|
12
|
+
SystemUIService.getInstance().getPluginEntries()
|
|
14
13
|
);
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const { run } = useMiddlewareRunner<Array<PluginRoute>>({
|
|
21
|
-
hookPoint: 'extendedRoutes',
|
|
22
|
-
onMiddlewareChange,
|
|
23
|
-
});
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const service = SystemUIService.getInstance();
|
|
17
|
+
setEntries(service.getPluginEntries());
|
|
24
18
|
|
|
25
|
-
|
|
19
|
+
const unsubscribe = service.subscribePluginEntryChange(() => {
|
|
20
|
+
setEntries(service.getPluginEntries());
|
|
21
|
+
});
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
return () => {
|
|
24
|
+
unsubscribe();
|
|
25
|
+
};
|
|
26
|
+
}, []);
|
|
30
27
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return false;
|
|
36
|
-
}) as Array<PluginRoute>;
|
|
28
|
+
const safeEntries = useMemo(
|
|
29
|
+
() => entries?.filter(entry => !protectedRoutesSet.has(entry.path)),
|
|
30
|
+
[entries]
|
|
31
|
+
);
|
|
37
32
|
|
|
38
|
-
return
|
|
33
|
+
return safeEntries ?? emptyEntries;
|
|
39
34
|
};
|
|
@@ -43,13 +43,23 @@ export const usePlugins = () => {
|
|
|
43
43
|
|
|
44
44
|
const installedPlugins = PluginStore.getInstance().getInstalledPlugins();
|
|
45
45
|
|
|
46
|
+
const { setGlobalLoading } = useGlobalLoading();
|
|
47
|
+
|
|
46
48
|
const pluginIds: Array<PluginID> = useMemo(
|
|
47
|
-
() => [
|
|
49
|
+
() => [...Array.from(installedPlugins), 'store'],
|
|
48
50
|
[installedPlugins]
|
|
49
51
|
);
|
|
50
52
|
|
|
51
53
|
usePluginsLoading();
|
|
52
54
|
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
const unregister = setGlobalLoading('plugins', !done);
|
|
57
|
+
|
|
58
|
+
return () => {
|
|
59
|
+
unregister();
|
|
60
|
+
};
|
|
61
|
+
}, [done, setGlobalLoading]);
|
|
62
|
+
|
|
53
63
|
useEffect(() => {
|
|
54
64
|
let cancelled = false;
|
|
55
65
|
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { PathRouteProps } from 'react-router-dom';
|
|
2
|
-
import { LinkProps } from '@bbki.ng/ui';
|
|
3
|
-
|
|
4
|
-
import { buildEntrySlotCom } from '#/utils';
|
|
5
1
|
import { createUIService } from '#/core/shared-service/factory/createUIService';
|
|
2
|
+
import { createEventBus } from '#/core/utils/eventBus';
|
|
6
3
|
import {
|
|
7
4
|
ISystemUIService,
|
|
8
5
|
SystemDataHookPoint,
|
|
@@ -15,6 +12,10 @@ const baseService = createUIService<SystemSlotName, SystemDataHookPoint>('system
|
|
|
15
12
|
export class SystemUIService implements ISystemUIService {
|
|
16
13
|
private static instance: SystemUIService;
|
|
17
14
|
|
|
15
|
+
private pluginEntries = new Map<string, IPluginEntry & { pluginId: PluginID }>();
|
|
16
|
+
|
|
17
|
+
private entryBus = createEventBus<{ pluginEntriesChanged: void }>();
|
|
18
|
+
|
|
18
19
|
private constructor() {}
|
|
19
20
|
|
|
20
21
|
static getInstance(): SystemUIService {
|
|
@@ -26,7 +27,6 @@ export class SystemUIService implements ISystemUIService {
|
|
|
26
27
|
|
|
27
28
|
registerSlot = baseService.registerSlot.bind(baseService);
|
|
28
29
|
registerMiddleware = baseService.registerMiddleware.bind(baseService);
|
|
29
|
-
unregisterAllByPluginId = baseService.unregisterAllByPluginId.bind(baseService);
|
|
30
30
|
getSlotEntries = baseService.getSlotEntries.bind(baseService);
|
|
31
31
|
getComponents = baseService.getComponents.bind(baseService);
|
|
32
32
|
subscribeSlotChange = baseService.subscribeSlotChange.bind(baseService);
|
|
@@ -34,37 +34,31 @@ export class SystemUIService implements ISystemUIService {
|
|
|
34
34
|
runMiddlewares = baseService.runMiddlewares.bind(baseService);
|
|
35
35
|
|
|
36
36
|
registerPluginEntry: (entry: IPluginEntry, id: PluginID) => void = (entry, id) => {
|
|
37
|
-
this.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return [
|
|
41
|
-
...routes,
|
|
42
|
-
{
|
|
43
|
-
path: entry.path,
|
|
44
|
-
},
|
|
45
|
-
];
|
|
46
|
-
},
|
|
47
|
-
id,
|
|
48
|
-
10
|
|
49
|
-
);
|
|
37
|
+
this.pluginEntries.set(entry.path, { ...entry, pluginId: id });
|
|
38
|
+
this.entryBus.emit('pluginEntriesChanged', undefined);
|
|
39
|
+
};
|
|
50
40
|
|
|
51
|
-
|
|
41
|
+
getPluginEntries = (): Array<IPluginEntry & { pluginId: PluginID }> => {
|
|
42
|
+
return Array.from(this.pluginEntries.values());
|
|
43
|
+
};
|
|
52
44
|
|
|
53
|
-
|
|
45
|
+
subscribePluginEntryChange = (listener: () => void): (() => void) => {
|
|
46
|
+
return this.entryBus.on('pluginEntriesChanged', listener);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
unregisterAllByPluginId: (pluginId: string) => void = pluginId => {
|
|
50
|
+
baseService.unregisterAllByPluginId(pluginId);
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
id,
|
|
67
|
-
10
|
|
68
|
-
);
|
|
52
|
+
let changed = false;
|
|
53
|
+
this.pluginEntries.forEach((entry, path) => {
|
|
54
|
+
if (entry.pluginId === pluginId) {
|
|
55
|
+
this.pluginEntries.delete(path);
|
|
56
|
+
changed = true;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (changed) {
|
|
61
|
+
this.entryBus.emit('pluginEntriesChanged', undefined);
|
|
62
|
+
}
|
|
69
63
|
};
|
|
70
64
|
}
|
|
@@ -38,12 +38,15 @@ export interface IBaseUIService<T extends string, K extends string> {
|
|
|
38
38
|
runMiddlewares: <S>(point: K, data: S) => Promise<S>;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export type SystemSlotName =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
| '
|
|
45
|
-
| '
|
|
46
|
-
| '
|
|
41
|
+
export type SystemSlotName =
|
|
42
|
+
| 'leftCol'
|
|
43
|
+
| 'rightCol'
|
|
44
|
+
| 'logo'
|
|
45
|
+
| 'pageFooter'
|
|
46
|
+
| 'nav-right'
|
|
47
|
+
| 'centerEntryArea';
|
|
48
|
+
|
|
49
|
+
export type SystemDataHookPoint = 'transformBreadcrumbPath' | 'transformEntryLink';
|
|
47
50
|
|
|
48
51
|
export interface ISystemUIService extends IBaseUIService<SystemSlotName, SystemDataHookPoint> {
|
|
49
52
|
registerPluginEntry: (entry: IPluginEntry, id: PluginID) => void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
|
|
3
|
+
import { IComPropsRegisteredToSlot } from '#/types/slots';
|
|
4
|
+
|
|
5
|
+
import { ArrowSvg } from './ArrowSvg';
|
|
6
|
+
|
|
7
|
+
export const ArrowCom: FC<IComPropsRegisteredToSlot> = ({ data }) => {
|
|
8
|
+
const hasEntry = data as boolean;
|
|
9
|
+
|
|
10
|
+
if (hasEntry) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return <ArrowSvg />;
|
|
15
|
+
};
|