@bbki.ng/site 5.5.15 → 5.5.17
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/package.json +2 -2
- package/src/blog/app.tsx +8 -8
- package/src/blog/components/Spinner.tsx +3 -13
- package/src/blog/components/effect-layer/EffectContextProvider.tsx +0 -1
- package/src/blog/context/bbcontext.tsx +2 -1
- package/src/blog/context/global_loading_state_provider.tsx +52 -11
- package/src/blog/hooks/index.ts +1 -0
- package/src/blog/hooks/use_loading.ts +26 -0
- package/src/blog/hooks/use_posts.ts +35 -51
- package/src/blog/hooks/use_streaming.ts +6 -9
- package/src/core/components/SlotComp.tsx +1 -1
- package/src/core/hooks/index.ts +6 -0
- package/src/core/hooks/useMiddlewareTransData.ts +68 -0
- package/src/core/hooks/useSlotComp.ts +4 -2
- package/src/{blog → core}/hooks/use_plugins.ts +3 -1
- package/src/core/pluginManager.ts +2 -0
- package/src/plugins/extra-cd/index.ts +38 -0
- package/src/plugins/manifest.ts +7 -0
- package/src/plugins/test/index.ts +1 -0
- package/src/types/hostApi.ts +12 -4
- package/src/types/plugin.ts +2 -0
- package/src/types/posts.ts +6 -0
- package/tsconfig.json +1 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bbki.ng/site",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.17",
|
|
4
4
|
"description": "code behind bbki.ng",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"vite-plugin-mdx": "^3.5.8",
|
|
58
58
|
"vite-plugin-pwa": "0.19",
|
|
59
59
|
"workbox-window": "^6.3.0",
|
|
60
|
-
"@bbki.ng/config": "1.0.
|
|
60
|
+
"@bbki.ng/config": "1.0.7"
|
|
61
61
|
},
|
|
62
62
|
"author": "bbbottle",
|
|
63
63
|
"license": "MIT",
|
package/src/blog/app.tsx
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import React, { useContext
|
|
1
|
+
import React, { useContext } from 'react';
|
|
2
2
|
import { Outlet, Route, Routes } from 'react-router-dom';
|
|
3
|
-
import { Cover, Streaming } from './pages';
|
|
4
3
|
import { Nav, NotFound, Page, Grid, ErrorBoundary, Container } from '@bbki.ng/ui';
|
|
5
4
|
|
|
5
|
+
import { usePaths } from '@/hooks';
|
|
6
6
|
import ArticlePage from '@/pages/extensions/txt/article';
|
|
7
7
|
import Txt from '@/pages/extensions/txt';
|
|
8
|
-
|
|
9
|
-
import { usePaths } from '@/hooks';
|
|
10
|
-
import { SWR } from '@/swr';
|
|
11
8
|
import { GlobalLoadingContext } from '@/context/global_loading_state_provider';
|
|
12
9
|
import { BotRedirect } from '@/pages/bot';
|
|
13
10
|
import { BBContext } from '@/context/bbcontext';
|
|
11
|
+
import { Slot } from '#/core/components/SlotComp';
|
|
12
|
+
import { usePlugins } from '#/core/hooks/use_plugins';
|
|
13
|
+
import { SWR } from '@/swr';
|
|
14
|
+
|
|
15
|
+
import { Cover, Streaming } from './pages';
|
|
14
16
|
import { useDynamicLogo } from './hooks/use_dynamic_logo';
|
|
15
|
-
import { Slot } from '../core/components/SlotComp';
|
|
16
|
-
import { usePlugins } from './hooks/use_plugins';
|
|
17
17
|
|
|
18
18
|
const Layout = () => {
|
|
19
19
|
const paths = usePaths();
|
|
@@ -59,7 +59,7 @@ const Layout = () => {
|
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
export const App = () => {
|
|
62
|
-
usePlugins(['sticker', 'fontstyler']);
|
|
62
|
+
usePlugins(['sticker', 'fontstyler', 'extra-cd']);
|
|
63
63
|
|
|
64
64
|
return (
|
|
65
65
|
<SWR>
|
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useGlobalLoading } from '@/hooks';
|
|
3
3
|
|
|
4
4
|
export const Spinner = (props: { disableDotIndicator?: boolean }) => {
|
|
5
5
|
const { disableDotIndicator } = props;
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
useEffect(() => {
|
|
10
|
-
if (disableDotIndicator) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
setIsLoading(true);
|
|
14
|
-
return () => {
|
|
15
|
-
setIsLoading(false);
|
|
16
|
-
};
|
|
17
|
-
}, []);
|
|
7
|
+
useGlobalLoading('spinner', !disableDotIndicator);
|
|
18
8
|
|
|
19
9
|
return <div className="h-full w-full grid place-items-center"></div>;
|
|
20
10
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
|
+
|
|
2
3
|
import { GlobalLoadingStateProvider } from '@/context/global_loading_state_provider';
|
|
3
|
-
import {
|
|
4
|
+
import { GlobalRoutesProvider } from '@/context/global_routes_provider';
|
|
4
5
|
import { EffectContextProvider } from '@/components/effect-layer/EffectContextProvider';
|
|
5
6
|
|
|
6
7
|
export const BBContext = (props: { children: ReactNode }) => {
|
|
@@ -1,29 +1,70 @@
|
|
|
1
|
-
import React, { createContext, ReactNode, useState,
|
|
1
|
+
import React, { createContext, ReactNode, useState, useCallback, useMemo } from 'react';
|
|
2
|
+
|
|
2
3
|
import { useFontLoading } from '@/hooks/use_font_loading';
|
|
3
4
|
|
|
5
|
+
type LoadingStates = Map<string, boolean>;
|
|
6
|
+
|
|
4
7
|
type LoadingContext = {
|
|
5
8
|
isLoading: boolean;
|
|
6
9
|
isFontLoading: boolean;
|
|
7
|
-
|
|
10
|
+
register: (id: string) => void;
|
|
11
|
+
setLoading: (id: string, loading: boolean) => void;
|
|
12
|
+
unregister: (id: string) => void;
|
|
8
13
|
};
|
|
9
14
|
|
|
10
15
|
export const GlobalLoadingContext = createContext<LoadingContext>({
|
|
11
16
|
isFontLoading: false,
|
|
12
17
|
isLoading: false,
|
|
13
|
-
|
|
18
|
+
register: () => {},
|
|
19
|
+
setLoading: () => {},
|
|
20
|
+
unregister: () => {},
|
|
14
21
|
});
|
|
15
22
|
|
|
16
23
|
export const GlobalLoadingStateProvider = (props: { children: ReactNode }) => {
|
|
17
|
-
const [
|
|
24
|
+
const [loadingStates, setLoadingStates] = useState<LoadingStates>(new Map());
|
|
18
25
|
const isFontLoading = useFontLoading();
|
|
26
|
+
|
|
27
|
+
const register = useCallback((id: string) => {
|
|
28
|
+
setLoadingStates(prev => {
|
|
29
|
+
const next = new Map(prev);
|
|
30
|
+
next.set(id, false);
|
|
31
|
+
return next;
|
|
32
|
+
});
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
const setLoading = useCallback((id: string, loading: boolean) => {
|
|
36
|
+
setLoadingStates(prev => {
|
|
37
|
+
const next = new Map(prev);
|
|
38
|
+
next.set(id, loading);
|
|
39
|
+
return next;
|
|
40
|
+
});
|
|
41
|
+
}, []);
|
|
42
|
+
|
|
43
|
+
const unregister = useCallback((id: string) => {
|
|
44
|
+
setLoadingStates(prev => {
|
|
45
|
+
const next = new Map(prev);
|
|
46
|
+
next.delete(id);
|
|
47
|
+
return next;
|
|
48
|
+
});
|
|
49
|
+
}, []);
|
|
50
|
+
|
|
51
|
+
const isLoading = useMemo(() => {
|
|
52
|
+
return Array.from(loadingStates.values()).some(Boolean) || isFontLoading;
|
|
53
|
+
}, [loadingStates, isFontLoading]);
|
|
54
|
+
|
|
55
|
+
const contextValue = useMemo(
|
|
56
|
+
() => ({
|
|
57
|
+
isLoading,
|
|
58
|
+
isFontLoading,
|
|
59
|
+
register,
|
|
60
|
+
setLoading,
|
|
61
|
+
unregister,
|
|
62
|
+
}),
|
|
63
|
+
[isLoading, isFontLoading, register, setLoading, unregister]
|
|
64
|
+
);
|
|
65
|
+
|
|
19
66
|
return (
|
|
20
|
-
<GlobalLoadingContext.Provider
|
|
21
|
-
value={{
|
|
22
|
-
isLoading,
|
|
23
|
-
setIsLoading,
|
|
24
|
-
isFontLoading,
|
|
25
|
-
}}
|
|
26
|
-
>
|
|
67
|
+
<GlobalLoadingContext.Provider value={contextValue}>
|
|
27
68
|
{props.children}
|
|
28
69
|
</GlobalLoadingContext.Provider>
|
|
29
70
|
);
|
package/src/blog/hooks/index.ts
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useContext, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { GlobalLoadingContext } from '@/context/global_loading_state_provider';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook to register a loading state with the global loading context.
|
|
7
|
+
* The global loading state is true if ANY registered loading state is true.
|
|
8
|
+
*
|
|
9
|
+
* @param id - Unique identifier for this loading state
|
|
10
|
+
* @param loading - Whether this specific loading state is active
|
|
11
|
+
*/
|
|
12
|
+
export function useGlobalLoading(id: string | undefined, loading: boolean | undefined) {
|
|
13
|
+
const { register, setLoading, unregister, isLoading } = useContext(GlobalLoadingContext);
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (!id || loading === undefined) return;
|
|
17
|
+
|
|
18
|
+
register(id);
|
|
19
|
+
setLoading(id, loading);
|
|
20
|
+
return () => {
|
|
21
|
+
unregister(id);
|
|
22
|
+
};
|
|
23
|
+
}, [id, loading]);
|
|
24
|
+
|
|
25
|
+
return isLoading;
|
|
26
|
+
}
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import useSWR from 'swr';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
|
|
4
|
+
import { useGlobalLoading } from '@/hooks';
|
|
4
5
|
import { baseFetcher } from '@/utils';
|
|
5
6
|
import { API_ENDPOINT } from '@/constants/routes';
|
|
6
|
-
import {
|
|
7
|
+
import { useMiddlewareTransData } from '#/core/hooks';
|
|
7
8
|
|
|
8
|
-
// In dev, use /api prefix to leverage Vite proxy to localhost:8787
|
|
9
9
|
const isProd = true;
|
|
10
|
-
// const isProd = typeof window !== 'undefined' && /^https:\/\/bbki\.ng/.test(window.location.href);
|
|
11
10
|
const POSTS_API = !isProd ? '/api/posts' : `${API_ENDPOINT}/posts`;
|
|
12
11
|
|
|
13
|
-
// Use baseFetcher for full URLs, cfApiFetcher is for relative paths
|
|
14
|
-
const postsFetcher = (resource: string) => baseFetcher(resource);
|
|
15
|
-
|
|
16
12
|
export interface TitleListItem {
|
|
17
13
|
name: string;
|
|
18
14
|
to: string;
|
|
@@ -21,58 +17,46 @@ export interface TitleListItem {
|
|
|
21
17
|
}
|
|
22
18
|
|
|
23
19
|
export const usePosts = (name: string = '', suspense?: boolean) => {
|
|
24
|
-
const { data: response, error } = useSWR(POSTS_API,
|
|
20
|
+
const { data: response, error: swrError } = useSWR(POSTS_API, baseFetcher, {
|
|
25
21
|
revalidateOnFocus: false,
|
|
26
22
|
suspense,
|
|
27
23
|
});
|
|
28
24
|
|
|
29
|
-
// Extract posts array from API response { status: "success", data: [...] }
|
|
30
25
|
const data = response?.data;
|
|
26
|
+
const isDataLoading = !data && !swrError;
|
|
27
|
+
|
|
28
|
+
const baseTitleList: TitleListItem[] = useMemo(() => {
|
|
29
|
+
if (!data || swrError) return [];
|
|
30
|
+
|
|
31
|
+
return data.map((p: any) => ({
|
|
32
|
+
name: p.title,
|
|
33
|
+
to: p.title,
|
|
34
|
+
children: p.title,
|
|
35
|
+
}));
|
|
36
|
+
}, [data, swrError]);
|
|
37
|
+
|
|
38
|
+
// Use middleware hook to transform title list
|
|
39
|
+
const {
|
|
40
|
+
data: titleList,
|
|
41
|
+
loading: isTransforming,
|
|
42
|
+
error: transformError,
|
|
43
|
+
} = useMiddlewareTransData({
|
|
44
|
+
hookPoint: 'transformTitleList',
|
|
45
|
+
baseData: baseTitleList,
|
|
46
|
+
immediate: baseTitleList.length > 0,
|
|
47
|
+
});
|
|
31
48
|
|
|
32
|
-
const
|
|
33
|
-
let isLoading = !data && !error;
|
|
34
|
-
const { setIsLoading } = useContext(GlobalLoadingContext);
|
|
35
|
-
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
setIsLoading(isLoading);
|
|
38
|
-
}, [isLoading, setIsLoading]);
|
|
39
|
-
|
|
40
|
-
// Apply middleware to transform titleList
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
const transformTitleList = async () => {
|
|
43
|
-
if (isLoading || error || !data) {
|
|
44
|
-
setTitleList([]);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const baseTitleList: TitleListItem[] = [
|
|
49
|
-
...data.map((p: any) => ({
|
|
50
|
-
name: p.title,
|
|
51
|
-
to: p.title,
|
|
52
|
-
children: p.title,
|
|
53
|
-
})),
|
|
54
|
-
{
|
|
55
|
-
name: 'cd ~',
|
|
56
|
-
to: '/',
|
|
57
|
-
children: 'cd ~',
|
|
58
|
-
},
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
// Run middleware to allow plugins to transform the title list
|
|
62
|
-
const transformedList = await registry.runMiddleware('transformTitleList', baseTitleList);
|
|
63
|
-
setTitleList(transformedList);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
transformTitleList();
|
|
67
|
-
}, [data, isLoading, error]);
|
|
49
|
+
const gLoading = useGlobalLoading('posts', isDataLoading || isTransforming);
|
|
68
50
|
|
|
69
51
|
const posts =
|
|
70
|
-
|
|
52
|
+
isDataLoading || name === '' || swrError || !data
|
|
53
|
+
? data
|
|
54
|
+
: data.find((p: any) => p.title === name);
|
|
71
55
|
|
|
72
56
|
return {
|
|
73
|
-
posts
|
|
74
|
-
titleList,
|
|
75
|
-
isError:
|
|
76
|
-
isLoading:
|
|
57
|
+
posts,
|
|
58
|
+
titleList: titleList ?? [],
|
|
59
|
+
isError: swrError || transformError,
|
|
60
|
+
isLoading: gLoading,
|
|
77
61
|
};
|
|
78
62
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import useSWR from 'swr';
|
|
2
|
-
import
|
|
3
|
-
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
import { baseFetcher } from '@/utils';
|
|
4
5
|
import { API_ENDPOINT } from '@/constants/routes';
|
|
5
|
-
|
|
6
|
-
import {
|
|
6
|
+
|
|
7
|
+
import { useGlobalLoading } from './use_loading';
|
|
7
8
|
|
|
8
9
|
// In dev, use /api prefix to leverage Vite proxy to localhost:8787
|
|
9
10
|
// const isProd = typeof window !== 'undefined' && /^https:\/\/bbki.ng/.test(window.location.href);
|
|
@@ -101,11 +102,7 @@ export function useStreaming(options: UseStreamingOptions = {}) {
|
|
|
101
102
|
});
|
|
102
103
|
}, []);
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
useEffect(() => {
|
|
107
|
-
setIsLoading(isLoading);
|
|
108
|
-
}, [isLoading, setIsLoading]);
|
|
105
|
+
useGlobalLoading('streaming', isLoading);
|
|
109
106
|
|
|
110
107
|
return {
|
|
111
108
|
streaming: data?.data ?? [],
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { registry } from '#/core/registry';
|
|
4
|
+
import type { HookPoint } from '#/types/slots';
|
|
5
|
+
|
|
6
|
+
export interface UseMiddlewareTransDataOptions<T> {
|
|
7
|
+
hookPoint: HookPoint;
|
|
8
|
+
baseData: T;
|
|
9
|
+
immediate?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UseMiddlewareTransDataResult<T> {
|
|
13
|
+
data: T | undefined;
|
|
14
|
+
loading: boolean;
|
|
15
|
+
error: Error | null;
|
|
16
|
+
run: () => Promise<T>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function useMiddlewareTransData<T>({
|
|
20
|
+
hookPoint,
|
|
21
|
+
baseData,
|
|
22
|
+
immediate = true,
|
|
23
|
+
}: UseMiddlewareTransDataOptions<T>): UseMiddlewareTransDataResult<T> {
|
|
24
|
+
const [data, setData] = useState<T | undefined>(undefined);
|
|
25
|
+
const [loading, setLoading] = useState(false);
|
|
26
|
+
const [error, setError] = useState<Error | null>(null);
|
|
27
|
+
|
|
28
|
+
const immediateRef = useRef(immediate);
|
|
29
|
+
immediateRef.current = immediate;
|
|
30
|
+
|
|
31
|
+
const run = useCallback(async (): Promise<T> => {
|
|
32
|
+
setLoading(true);
|
|
33
|
+
setError(null);
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const result = await registry.runMiddleware(hookPoint, baseData);
|
|
37
|
+
setData(result);
|
|
38
|
+
return result;
|
|
39
|
+
} catch (err) {
|
|
40
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
41
|
+
setError(error);
|
|
42
|
+
throw error;
|
|
43
|
+
} finally {
|
|
44
|
+
setLoading(false);
|
|
45
|
+
}
|
|
46
|
+
}, [hookPoint, baseData]);
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!immediateRef.current) return;
|
|
50
|
+
|
|
51
|
+
let cancelled = false;
|
|
52
|
+
|
|
53
|
+
run()
|
|
54
|
+
.then(result => {
|
|
55
|
+
if (cancelled) return;
|
|
56
|
+
setData(result);
|
|
57
|
+
})
|
|
58
|
+
.catch(() => {
|
|
59
|
+
// 错误已在 run 中设置到 state
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return () => {
|
|
63
|
+
cancelled = true;
|
|
64
|
+
};
|
|
65
|
+
}, [hookPoint, baseData, run]);
|
|
66
|
+
|
|
67
|
+
return { data, loading, error, run };
|
|
68
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { SlotName } from '#/types/slots';
|
|
4
|
+
|
|
3
5
|
import { registry } from '../registry';
|
|
4
6
|
|
|
5
7
|
export const useSlotComp = (slotName: SlotName) => {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
+
|
|
2
3
|
import { pluginManager } from '#/core/pluginManager';
|
|
4
|
+
import { PluginID } from '#/types/plugin';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* 通用插件管理 hook
|
|
@@ -10,7 +12,7 @@ import { pluginManager } from '#/core/pluginManager';
|
|
|
10
12
|
* @example
|
|
11
13
|
* usePlugins(['sticker', 'fontstyler']);
|
|
12
14
|
*/
|
|
13
|
-
export const usePlugins = (pluginIds:
|
|
15
|
+
export const usePlugins = (pluginIds: Array<PluginID>) => {
|
|
14
16
|
useEffect(() => {
|
|
15
17
|
// 加载指定的插件
|
|
16
18
|
pluginIds.forEach(id => {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { IHostContext } from '#/types/hostApi';
|
|
2
|
+
import { IPlugin } from '#/types/plugin';
|
|
3
|
+
import { TitleListItem } from '#/types/posts';
|
|
4
|
+
|
|
5
|
+
class ExtraCd implements IPlugin {
|
|
6
|
+
id: string = 'extra-cd';
|
|
7
|
+
name: string = 'Extra CD';
|
|
8
|
+
description: string =
|
|
9
|
+
'Provides additional change directory functionalities for enhanced user experience.';
|
|
10
|
+
version: string = '1.0.0';
|
|
11
|
+
author: string = 'bbki.ng';
|
|
12
|
+
|
|
13
|
+
async onInstall(ctx: IHostContext): Promise<void> {
|
|
14
|
+
// Initialize any required resources or settings
|
|
15
|
+
ctx.api.registerMiddleware('transformTitleList', this.transformTitleList, this.id, 10);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async onDisable(): Promise<void> {
|
|
19
|
+
// Clean up active operations
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onDestroy(): void {
|
|
23
|
+
// Release all resources
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private transformTitleList = (titleList: Array<TitleListItem>) => {
|
|
27
|
+
return [
|
|
28
|
+
...titleList,
|
|
29
|
+
{
|
|
30
|
+
name: 'cd ~',
|
|
31
|
+
to: '/',
|
|
32
|
+
children: 'cd ~',
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default new ExtraCd();
|
package/src/plugins/manifest.ts
CHANGED
|
@@ -11,6 +11,13 @@ export const PLUGIN_MANIFEST = [
|
|
|
11
11
|
version: '0.1.0',
|
|
12
12
|
description: 'A sticker plugin',
|
|
13
13
|
},
|
|
14
|
+
{
|
|
15
|
+
name: 'extra-cd',
|
|
16
|
+
id: 'extra-cd',
|
|
17
|
+
version: '0.1.0',
|
|
18
|
+
description:
|
|
19
|
+
'Provides additional change directory functionalities for enhanced user experience.',
|
|
20
|
+
},
|
|
14
21
|
{
|
|
15
22
|
name: 'fontstyler',
|
|
16
23
|
id: 'fontstyler',
|
package/src/types/hostApi.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
2
3
|
import { type FingerprintData } from '@/utils/fingerprints';
|
|
3
4
|
|
|
5
|
+
import { HookPoint, SlotName } from './slots';
|
|
6
|
+
|
|
4
7
|
export interface IHostApi {
|
|
5
8
|
getDeviceId: () => Promise<{ id: string; fp: FingerprintData }>;
|
|
6
|
-
registerMiddleware: (
|
|
7
|
-
|
|
9
|
+
registerMiddleware: <T>(
|
|
10
|
+
point: HookPoint,
|
|
11
|
+
fn: (baseData: T) => T,
|
|
12
|
+
pluginId: string,
|
|
13
|
+
weight?: number
|
|
14
|
+
) => void;
|
|
15
|
+
registerSlot: <T>(
|
|
8
16
|
slotName: SlotName,
|
|
9
|
-
component: React.ComponentType<
|
|
17
|
+
component: React.ComponentType<T>,
|
|
10
18
|
pluginId: string,
|
|
11
19
|
weight?: number
|
|
12
20
|
) => void;
|
package/src/types/plugin.ts
CHANGED