@bbki.ng/site 5.5.18 → 5.5.20
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/index.d.ts +7 -6
- package/package.json +3 -3
- package/src/blog/app.tsx +18 -54
- package/src/blog/components/BaseLayout.tsx +55 -0
- package/src/blog/components/index.tsx +2 -4
- package/src/blog/context/global_loading_state_provider.tsx +3 -9
- package/src/blog/hooks/use_loading.ts +1 -1
- package/src/blog/hooks/use_plugin_entries.ts +48 -0
- package/src/blog/hooks/use_posts.ts +16 -9
- package/src/blog/index.tsx +1 -0
- package/src/blog/pages/cover/index.tsx +33 -24
- package/src/blog/pages/extensions/txt/article.tsx +6 -3
- package/src/blog/pages/extensions/txt/index.tsx +29 -25
- package/src/blog/swr.tsx +3 -2
- package/src/blog/types/path.ts +0 -7
- package/src/blog/utils/index.ts +0 -21
- package/src/core/context/createPluginCtx.tsx +12 -7
- package/src/core/hooks/index.ts +1 -1
- package/src/core/hooks/useMiddlewareTransData.ts +32 -46
- package/src/core/hooks/useSlotComp.ts +7 -3
- package/src/core/hooks/use_plugins.ts +16 -5
- package/src/core/pluginManager.ts +15 -6
- package/src/core/registry.ts +45 -11
- package/src/plugins/extra-entry/components/page.tsx +14 -0
- package/src/plugins/extra-entry/index.ts +32 -0
- package/src/plugins/manifest.ts +6 -0
- package/src/plugins/sticker/components/StickerCom.tsx +6 -8
- package/src/plugins/xwy/components/logo.tsx +6 -2
- package/src/plugins/xwy/const/index.ts +1 -1
- package/src/types/hostApi.ts +3 -3
- package/src/types/plugin.ts +11 -1
- package/src/types/posts.ts +9 -0
- package/src/types/slots.ts +12 -2
- package/src/utils/index.tsx +52 -0
- package/tsconfig.json +2 -4
- package/src/blog/components/Auth.tsx +0 -13
- package/src/blog/components/DelayFadeIn/DelayFadeIn.tsx +0 -28
- package/src/blog/components/Spinner.tsx +0 -10
- package/src/blog/components/my_suspense.tsx +0 -11
- package/src/blog/components/share/share-btn.tsx +0 -28
- package/src/blog/components/share/share-icon.tsx +0 -19
- package/src/blog/hooks/use_font_loading.ts +0 -41
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @bbki.ng/site
|
|
2
2
|
|
|
3
|
+
## 5.5.20
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 6748bb3: fix null pointer exception
|
|
8
|
+
|
|
9
|
+
## 5.5.19
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 3edea98: fix base url config
|
|
14
|
+
- Updated dependencies [3edea98]
|
|
15
|
+
- @bbki.ng/ui@0.2.13
|
|
16
|
+
|
|
3
17
|
## 5.5.18
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/index.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
declare const GLOBAL_COMMIT_HASH: string;
|
|
5
|
-
interface ImportMeta {
|
|
6
|
-
glob: (pattern: string) => Record<string, () => Promise<unknown>>;
|
|
7
|
-
}
|
|
3
|
+
import type React from 'react';
|
|
8
4
|
|
|
9
5
|
declare global {
|
|
6
|
+
const GLOBAL_BBKING_VERSION: string;
|
|
7
|
+
const GLOBAL_COMMIT_HASH: string;
|
|
8
|
+
|
|
10
9
|
namespace JSX {
|
|
11
10
|
interface IntrinsicElements {
|
|
12
11
|
'bb-img': React.DetailedHTMLProps<
|
|
@@ -16,3 +15,5 @@ declare global {
|
|
|
16
15
|
}
|
|
17
16
|
}
|
|
18
17
|
}
|
|
18
|
+
|
|
19
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bbki.ng/site",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.20",
|
|
4
4
|
"description": "code behind bbki.ng",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"react-dom": "^18.0.0",
|
|
15
15
|
"react-router-dom": "6",
|
|
16
16
|
"swr": "^2.2.5",
|
|
17
|
-
"@bbki.ng/ui": "0.2.
|
|
17
|
+
"@bbki.ng/ui": "0.2.13"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@eslint/compat": "^1.0.0",
|
|
@@ -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.9"
|
|
61
61
|
},
|
|
62
62
|
"author": "bbbottle",
|
|
63
63
|
"license": "MIT",
|
package/src/blog/app.tsx
CHANGED
|
@@ -1,75 +1,32 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { Outlet, Route, Routes
|
|
3
|
-
import {
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Outlet, Route, Routes } from 'react-router-dom';
|
|
3
|
+
import { NotFound } from '@bbki.ng/ui';
|
|
4
4
|
|
|
5
|
-
import { usePaths } from '@/hooks';
|
|
6
5
|
import ArticlePage from '@/pages/extensions/txt/article';
|
|
7
6
|
import Txt from '@/pages/extensions/txt';
|
|
8
|
-
import { GlobalLoadingContext } from '@/context/global_loading_state_provider';
|
|
9
7
|
import { BotRedirect } from '@/pages/bot';
|
|
10
8
|
import { BBContext } from '@/context/bbcontext';
|
|
11
9
|
import { Slot } from '#/core/components/SlotComp';
|
|
12
10
|
import { usePlugins } from '#/core/hooks/use_plugins';
|
|
13
11
|
import { SWR } from '@/swr';
|
|
12
|
+
import type { PluginID } from '#/types/plugin';
|
|
14
13
|
|
|
15
14
|
import { Cover, Streaming } from './pages';
|
|
15
|
+
import { usePluginEntries } from './hooks/use_plugin_entries';
|
|
16
|
+
import { BaseLayout } from './components/BaseLayout';
|
|
16
17
|
|
|
17
|
-
const
|
|
18
|
-
const paths = usePaths();
|
|
19
|
-
const { isLoading } = useContext(GlobalLoadingContext);
|
|
20
|
-
|
|
21
|
-
const nav = useNavigate();
|
|
22
|
-
|
|
23
|
-
const defaultLogo = (
|
|
24
|
-
<Logo className="mr-2 cursor-pointer hover:opacity-80" onClick={() => nav('/')} />
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<Page
|
|
29
|
-
nav={
|
|
30
|
-
<Nav
|
|
31
|
-
paths={paths}
|
|
32
|
-
className="gradient-blur-cover select-none"
|
|
33
|
-
loading={isLoading}
|
|
34
|
-
customLogo={<Slot name="logo" data={defaultLogo} placeholder={defaultLogo} />}
|
|
35
|
-
style={{
|
|
36
|
-
paddingTop: 'var(--safe-top)',
|
|
37
|
-
transition: 'all .2s ease-in-out',
|
|
38
|
-
}}
|
|
39
|
-
/>
|
|
40
|
-
}
|
|
41
|
-
main={
|
|
42
|
-
<Grid
|
|
43
|
-
leftAside={
|
|
44
|
-
<div className="py-32 px-6">
|
|
45
|
-
<Slot name="leftCol" data={paths} />
|
|
46
|
-
</div>
|
|
47
|
-
}
|
|
48
|
-
rightAside={
|
|
49
|
-
<div className="py-32 px-6">
|
|
50
|
-
<Slot name="rightCol" data={paths} />
|
|
51
|
-
</div>
|
|
52
|
-
}
|
|
53
|
-
>
|
|
54
|
-
<Container className="py-32">
|
|
55
|
-
<ErrorBoundary>
|
|
56
|
-
<Outlet />
|
|
57
|
-
</ErrorBoundary>
|
|
58
|
-
</Container>
|
|
59
|
-
</Grid>
|
|
60
|
-
}
|
|
61
|
-
/>
|
|
62
|
-
);
|
|
63
|
-
};
|
|
18
|
+
const APP_PLUGIN_IDS: Array<PluginID> = ['sticker', 'xwy', 'extra-cd' /*'extra-entry'*/];
|
|
64
19
|
|
|
65
20
|
export const App = () => {
|
|
66
|
-
usePlugins(
|
|
21
|
+
usePlugins(APP_PLUGIN_IDS);
|
|
22
|
+
|
|
23
|
+
const pluginEntries = usePluginEntries();
|
|
67
24
|
|
|
68
25
|
return (
|
|
69
26
|
<SWR>
|
|
70
27
|
<BBContext>
|
|
71
28
|
<Routes>
|
|
72
|
-
<Route path="/" element={<
|
|
29
|
+
<Route path="/" element={<BaseLayout />}>
|
|
73
30
|
<Route index element={<Cover />} />
|
|
74
31
|
|
|
75
32
|
<Route path="blog" element={<Outlet />}>
|
|
@@ -79,6 +36,13 @@ export const App = () => {
|
|
|
79
36
|
|
|
80
37
|
<Route path="bot" element={<BotRedirect />} />
|
|
81
38
|
<Route path="now" element={<Streaming />} />
|
|
39
|
+
{pluginEntries?.map(route => (
|
|
40
|
+
<Route
|
|
41
|
+
key={route.path}
|
|
42
|
+
path={route.path}
|
|
43
|
+
element={<Slot name="route" data={route} />}
|
|
44
|
+
/>
|
|
45
|
+
))}
|
|
82
46
|
</Route>
|
|
83
47
|
<Route path="*" element={<NotFound />} />
|
|
84
48
|
</Routes>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React, { useContext } from 'react';
|
|
2
|
+
import { useNavigate, Outlet } from 'react-router-dom';
|
|
3
|
+
import { Logo, Nav, Page, Grid, ErrorBoundary, Container } from '@bbki.ng/ui';
|
|
4
|
+
|
|
5
|
+
import { Slot } from '#/core/components/SlotComp';
|
|
6
|
+
import { usePaths } from '@/hooks';
|
|
7
|
+
import { GlobalLoadingContext } from '@/context/global_loading_state_provider';
|
|
8
|
+
|
|
9
|
+
export const BaseLayout = () => {
|
|
10
|
+
const paths = usePaths();
|
|
11
|
+
const { isLoading } = useContext(GlobalLoadingContext);
|
|
12
|
+
|
|
13
|
+
const nav = useNavigate();
|
|
14
|
+
|
|
15
|
+
const defaultLogo = (
|
|
16
|
+
<Logo className="mr-2 cursor-pointer hover:opacity-80" onClick={() => nav('/')} />
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Page
|
|
21
|
+
nav={
|
|
22
|
+
<Nav
|
|
23
|
+
paths={paths}
|
|
24
|
+
className="gradient-blur-cover select-none"
|
|
25
|
+
loading={isLoading}
|
|
26
|
+
customLogo={<Slot name="logo" data={defaultLogo} placeholder={defaultLogo} />}
|
|
27
|
+
style={{
|
|
28
|
+
paddingTop: 'var(--safe-top)',
|
|
29
|
+
transition: 'all .2s ease-in-out',
|
|
30
|
+
}}
|
|
31
|
+
/>
|
|
32
|
+
}
|
|
33
|
+
main={
|
|
34
|
+
<Grid
|
|
35
|
+
leftAside={
|
|
36
|
+
<div className="py-32 px-6">
|
|
37
|
+
<Slot name="leftCol" data={paths} />
|
|
38
|
+
</div>
|
|
39
|
+
}
|
|
40
|
+
rightAside={
|
|
41
|
+
<div className="py-32 px-6">
|
|
42
|
+
<Slot name="rightCol" data={paths} />
|
|
43
|
+
</div>
|
|
44
|
+
}
|
|
45
|
+
>
|
|
46
|
+
<Container className="py-32">
|
|
47
|
+
<ErrorBoundary>
|
|
48
|
+
<Outlet />
|
|
49
|
+
</ErrorBoundary>
|
|
50
|
+
</Container>
|
|
51
|
+
</Grid>
|
|
52
|
+
}
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { LinkList } from '@bbki.ng/ui';
|
|
2
|
+
import { LinkList, LinkListProps } from '@bbki.ng/ui';
|
|
3
3
|
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
export const CenterLinkList = (props: any) => {
|
|
4
|
+
export const CenterLinkList = (props: LinkListProps) => {
|
|
7
5
|
return (
|
|
8
6
|
<div className="flex justify-center relative h-full">
|
|
9
7
|
<LinkList {...props} />
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import React, { createContext, ReactNode, useState, useCallback, useMemo } from 'react';
|
|
2
2
|
|
|
3
|
-
import { useFontLoading } from '@/hooks/use_font_loading';
|
|
4
|
-
|
|
5
3
|
type LoadingStates = Map<string, boolean>;
|
|
6
4
|
|
|
7
5
|
type LoadingContext = {
|
|
8
6
|
isLoading: boolean;
|
|
9
|
-
isFontLoading: boolean;
|
|
10
7
|
register: (id: string) => void;
|
|
11
8
|
setLoading: (id: string, loading: boolean) => void;
|
|
12
9
|
unregister: (id: string) => void;
|
|
13
10
|
};
|
|
14
11
|
|
|
15
12
|
export const GlobalLoadingContext = createContext<LoadingContext>({
|
|
16
|
-
isFontLoading: false,
|
|
17
13
|
isLoading: false,
|
|
18
14
|
register: () => {},
|
|
19
15
|
setLoading: () => {},
|
|
@@ -22,7 +18,6 @@ export const GlobalLoadingContext = createContext<LoadingContext>({
|
|
|
22
18
|
|
|
23
19
|
export const GlobalLoadingStateProvider = (props: { children: ReactNode }) => {
|
|
24
20
|
const [loadingStates, setLoadingStates] = useState<LoadingStates>(new Map());
|
|
25
|
-
const isFontLoading = useFontLoading();
|
|
26
21
|
|
|
27
22
|
const register = useCallback((id: string) => {
|
|
28
23
|
setLoadingStates(prev => {
|
|
@@ -49,18 +44,17 @@ export const GlobalLoadingStateProvider = (props: { children: ReactNode }) => {
|
|
|
49
44
|
}, []);
|
|
50
45
|
|
|
51
46
|
const isLoading = useMemo(() => {
|
|
52
|
-
return Array.from(loadingStates.values()).some(Boolean)
|
|
53
|
-
}, [loadingStates
|
|
47
|
+
return Array.from(loadingStates.values()).some(Boolean);
|
|
48
|
+
}, [loadingStates]);
|
|
54
49
|
|
|
55
50
|
const contextValue = useMemo(
|
|
56
51
|
() => ({
|
|
57
52
|
isLoading,
|
|
58
|
-
isFontLoading,
|
|
59
53
|
register,
|
|
60
54
|
setLoading,
|
|
61
55
|
unregister,
|
|
62
56
|
}),
|
|
63
|
-
[isLoading,
|
|
57
|
+
[isLoading, register, setLoading, unregister]
|
|
64
58
|
);
|
|
65
59
|
|
|
66
60
|
return (
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { type PathRouteProps } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
import { useMiddlewareRunner } from '#/core/hooks';
|
|
5
|
+
|
|
6
|
+
const protectedRoutesSet = new Set<string>([
|
|
7
|
+
'/bot',
|
|
8
|
+
'/now',
|
|
9
|
+
'/',
|
|
10
|
+
'/blog',
|
|
11
|
+
'/blog/:title',
|
|
12
|
+
'default',
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
type PluginRoute = Omit<PathRouteProps, 'element'>;
|
|
16
|
+
|
|
17
|
+
export const usePluginEntries = () => {
|
|
18
|
+
const [fullRoutes, setFullRoutes] = useState<Array<PluginRoute>>([]);
|
|
19
|
+
const runRef = useRef<(input: Array<PluginRoute>) => Promise<Array<PluginRoute>>>(() =>
|
|
20
|
+
Promise.resolve([])
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const onMiddlewareChange = useCallback(() => {
|
|
24
|
+
runRef.current([]).then(setFullRoutes);
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
const { run } = useMiddlewareRunner<Array<PluginRoute>>({
|
|
28
|
+
hookPoint: 'extendedRoutes',
|
|
29
|
+
onMiddlewareChange,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
runRef.current = run;
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
run([]).then(setFullRoutes);
|
|
36
|
+
}, [run]);
|
|
37
|
+
|
|
38
|
+
const safeRoutes = fullRoutes?.filter(route => {
|
|
39
|
+
if ('path' in route) {
|
|
40
|
+
return !protectedRoutesSet.has(route.path);
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}) as Array<PluginRoute>;
|
|
44
|
+
|
|
45
|
+
console.log('safe plugin routes:', safeRoutes);
|
|
46
|
+
|
|
47
|
+
return safeRoutes ?? [];
|
|
48
|
+
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import useSWR from 'swr';
|
|
2
|
-
import { useMemo } from 'react';
|
|
2
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
3
3
|
|
|
4
4
|
import { useGlobalLoading } from '@/hooks';
|
|
5
5
|
import { baseFetcher } from '@/utils';
|
|
6
6
|
import { API_ENDPOINT } from '@/constants/routes';
|
|
7
|
-
import {
|
|
7
|
+
import { IPost } from '#/types/posts';
|
|
8
|
+
import { useMiddlewareRunner } from '#/core/hooks/useMiddlewareTransData';
|
|
8
9
|
|
|
9
10
|
const isProd = true;
|
|
10
11
|
const POSTS_API = !isProd ? '/api/posts' : `${API_ENDPOINT}/posts`;
|
|
@@ -28,34 +29,40 @@ export const usePosts = (name: string = '', suspense?: boolean) => {
|
|
|
28
29
|
const baseTitleList: TitleListItem[] = useMemo(() => {
|
|
29
30
|
if (!data || swrError) return [];
|
|
30
31
|
|
|
31
|
-
return data.map((p:
|
|
32
|
+
return data.map((p: IPost) => ({
|
|
32
33
|
name: p.title,
|
|
33
34
|
to: p.title,
|
|
34
35
|
children: p.title,
|
|
35
36
|
}));
|
|
36
37
|
}, [data, swrError]);
|
|
37
38
|
|
|
39
|
+
const [fullTitleList, setFullTitleList] = useState<TitleListItem[]>(baseTitleList);
|
|
40
|
+
|
|
38
41
|
// Use middleware hook to transform title list
|
|
39
42
|
const {
|
|
40
|
-
data: titleList,
|
|
41
43
|
loading: isTransforming,
|
|
42
44
|
error: transformError,
|
|
43
|
-
|
|
45
|
+
run,
|
|
46
|
+
} = useMiddlewareRunner<TitleListItem[]>({
|
|
44
47
|
hookPoint: 'transformTitleList',
|
|
45
|
-
baseData: baseTitleList,
|
|
46
|
-
immediate: baseTitleList.length > 0,
|
|
47
48
|
});
|
|
48
49
|
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (baseTitleList.length > 0) {
|
|
52
|
+
run(baseTitleList).then(setFullTitleList);
|
|
53
|
+
}
|
|
54
|
+
}, [baseTitleList, run]);
|
|
55
|
+
|
|
49
56
|
const gLoading = useGlobalLoading('posts', isDataLoading || isTransforming);
|
|
50
57
|
|
|
51
58
|
const posts =
|
|
52
59
|
isDataLoading || name === '' || swrError || !data
|
|
53
60
|
? data
|
|
54
|
-
: data.find((p:
|
|
61
|
+
: data.find((p: IPost) => p.title === name);
|
|
55
62
|
|
|
56
63
|
return {
|
|
57
64
|
posts,
|
|
58
|
-
titleList:
|
|
65
|
+
titleList: fullTitleList ?? [],
|
|
59
66
|
isError: swrError || transformError,
|
|
60
67
|
isLoading: gLoading,
|
|
61
68
|
};
|
package/src/blog/index.tsx
CHANGED
|
@@ -1,31 +1,40 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useEffect, useMemo } from 'react';
|
|
2
|
+
import { LinkProps } from '@bbki.ng/ui';
|
|
3
|
+
|
|
2
4
|
import { CenterLinkList } from '@/components';
|
|
3
|
-
import {
|
|
5
|
+
import { useMiddlewareRunner } from '#/core/hooks';
|
|
6
|
+
|
|
7
|
+
export const Cover = (_: { className?: string }) => {
|
|
8
|
+
const baseEntries: Array<LinkProps> = useMemo(
|
|
9
|
+
() => [
|
|
10
|
+
{
|
|
11
|
+
to: '/blog',
|
|
12
|
+
children: 'cd ./blog',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
to: '/now',
|
|
16
|
+
children: 'cd ./now',
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
[]
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const [entries, setEntries] = React.useState<Array<LinkProps>>(baseEntries);
|
|
23
|
+
|
|
24
|
+
const { run } = useMiddlewareRunner<Array<LinkProps>>({
|
|
25
|
+
hookPoint: 'transformCoverEntry',
|
|
26
|
+
onMiddlewareChange: () => {
|
|
27
|
+
run(baseEntries).then(setEntries);
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
run(baseEntries).then(setEntries);
|
|
33
|
+
}, [baseEntries, run]);
|
|
4
34
|
|
|
5
|
-
export const Cover = (props: { className?: string }) => {
|
|
6
|
-
const globalRouteCtx = useContext(GlobalRoutesContext);
|
|
7
|
-
const routes = globalRouteCtx.globalRoutes;
|
|
8
|
-
const pluginEntry = routes.length > 0 ? [{ to: '/plugins', name: 'cd ./plugins' }] : [];
|
|
9
35
|
return (
|
|
10
36
|
<>
|
|
11
|
-
<CenterLinkList
|
|
12
|
-
className="select-none"
|
|
13
|
-
links={[
|
|
14
|
-
{
|
|
15
|
-
to: '/blog',
|
|
16
|
-
name: 'cd ./blog',
|
|
17
|
-
children: 'cd ./blog',
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
to: '/now',
|
|
21
|
-
name: 'cd ./now',
|
|
22
|
-
children: 'cd ./now',
|
|
23
|
-
},
|
|
24
|
-
...pluginEntry,
|
|
25
|
-
]}
|
|
26
|
-
title=""
|
|
27
|
-
// footer={<Version className="" />}
|
|
28
|
-
/>
|
|
37
|
+
<CenterLinkList className="select-none" links={entries} />
|
|
29
38
|
</>
|
|
30
39
|
);
|
|
31
40
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { NotFound } from '@bbki.ng/ui';
|
|
3
3
|
import { useParams } from 'react-router-dom';
|
|
4
|
+
|
|
4
5
|
import { usePosts } from '@/hooks/use_posts';
|
|
5
6
|
import { ArticlePage } from '@/components/article';
|
|
6
7
|
import { useBlogScrollReset } from '@/hooks/use_blog_scroll_pos_restoration';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
function TxtArticle() {
|
|
9
10
|
const { title } = useParams();
|
|
10
11
|
const { posts, isError, isLoading } = usePosts(title);
|
|
11
12
|
|
|
@@ -19,7 +20,7 @@ export default () => {
|
|
|
19
20
|
return <NotFound />;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
if (isLoading) {
|
|
23
|
+
if (isLoading || !posts) {
|
|
23
24
|
return null;
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -30,4 +31,6 @@ export default () => {
|
|
|
30
31
|
<div dangerouslySetInnerHTML={{ __html: posts.content }} />
|
|
31
32
|
</ArticlePage>
|
|
32
33
|
);
|
|
33
|
-
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default TxtArticle;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { LinkProps, Button } from '@bbki.ng/ui';
|
|
3
|
+
|
|
3
4
|
import { usePosts } from '@/hooks/use_posts';
|
|
4
5
|
import { CenterLinkList } from '@/components';
|
|
5
6
|
import { useBlogScroll, useBlogScrollRestoration } from '@/hooks/use_blog_scroll_pos_restoration';
|
|
@@ -9,43 +10,46 @@ type TxtProps = {
|
|
|
9
10
|
articleList?: LinkProps[];
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
const { titleList,
|
|
13
|
+
const Txt = (props: TxtProps) => {
|
|
14
|
+
const { titleList, isError } = usePosts();
|
|
14
15
|
|
|
15
16
|
useBlogScrollRestoration();
|
|
16
17
|
|
|
17
18
|
const { gotoTop } = useBlogScroll();
|
|
18
19
|
|
|
19
|
-
if (isLoading) {
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
20
|
if (isError) {
|
|
24
|
-
return <CenterLinkList links={props.articleList} />;
|
|
21
|
+
return <CenterLinkList links={props.articleList ?? titleList} />;
|
|
25
22
|
}
|
|
26
23
|
|
|
24
|
+
const links = props.articleList ?? titleList;
|
|
25
|
+
|
|
27
26
|
return (
|
|
28
27
|
<CenterLinkList
|
|
29
|
-
links={
|
|
30
|
-
loading={isLoading}
|
|
28
|
+
links={links}
|
|
31
29
|
footer={
|
|
32
|
-
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
30
|
+
links.length > 0 ? (
|
|
31
|
+
<Button onClick={gotoTop} className="mt-32">
|
|
32
|
+
<svg
|
|
33
|
+
data-testid="geist-icon"
|
|
34
|
+
height="16"
|
|
35
|
+
strokeLinejoin="round"
|
|
36
|
+
viewBox="0 0 16 16"
|
|
37
|
+
width="16"
|
|
38
|
+
>
|
|
39
|
+
<path
|
|
40
|
+
fillRule="evenodd"
|
|
41
|
+
clipRule="evenodd"
|
|
42
|
+
d="M8.70711 1.39644C8.31659 1.00592 7.68342 1.00592 7.2929 1.39644L2.21968 6.46966L1.68935 6.99999L2.75001 8.06065L3.28034 7.53032L7.25001 3.56065V14.25V15H8.75001V14.25V3.56065L12.7197 7.53032L13.25 8.06065L14.3107 6.99999L13.7803 6.46966L8.70711 1.39644Z"
|
|
43
|
+
fill="currentColor"
|
|
44
|
+
></path>
|
|
45
|
+
</svg>
|
|
46
|
+
</Button>
|
|
47
|
+
) : null
|
|
48
48
|
}
|
|
49
49
|
/>
|
|
50
50
|
);
|
|
51
51
|
};
|
|
52
|
+
|
|
53
|
+
Txt.displayName = 'Txt';
|
|
54
|
+
|
|
55
|
+
export default Txt;
|
package/src/blog/swr.tsx
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
2
|
import { SWRConfig } from 'swr';
|
|
3
|
+
|
|
3
4
|
import { cfApiFetcher } from '@/utils';
|
|
4
5
|
|
|
5
|
-
export const SWR = (props: { children:
|
|
6
|
+
export const SWR = (props: { children: ReactNode }) => {
|
|
6
7
|
return (
|
|
7
8
|
<SWRConfig
|
|
8
9
|
value={{
|
package/src/blog/types/path.ts
CHANGED
package/src/blog/utils/index.ts
CHANGED
|
@@ -32,24 +32,3 @@ export const withBBApi =
|
|
|
32
32
|
fetcher(`${apiEndPoint}/${resource}`, { ...init, mode: 'cors' });
|
|
33
33
|
|
|
34
34
|
export const cfApiFetcher = withBBApi(baseFetcher)(API_ENDPOINT);
|
|
35
|
-
|
|
36
|
-
export const changeFont = (type: FontType) => {
|
|
37
|
-
const rootDiv = document.getElementById('root');
|
|
38
|
-
if (rootDiv == null) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (rootDiv.classList.contains(type)) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// remove all font type class
|
|
47
|
-
for (const fontType in FontType) {
|
|
48
|
-
rootDiv.classList.remove(fontType);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
rootDiv.classList.add(type);
|
|
52
|
-
|
|
53
|
-
// save font type to local storage
|
|
54
|
-
localStorage.setItem('font', type);
|
|
55
|
-
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { createContext, useContext, ComponentType } from 'react';
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
import { IComPropsRegisteredToSlot } from '#/types/slots';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* 创建插件专属的 Context 工具集
|
|
@@ -33,15 +34,19 @@ export function createPluginCtx<T>() {
|
|
|
33
34
|
* const Enhanced = withCtx(picker, BaseComp)(ctx);
|
|
34
35
|
* ctx.api.registerSlot('slotName', Enhanced, pluginId);
|
|
35
36
|
*/
|
|
36
|
-
const withCtx = <P extends
|
|
37
|
+
const withCtx = <P extends IComPropsRegisteredToSlot>(
|
|
37
38
|
ctx: T,
|
|
38
39
|
Component: React.ComponentType<P>
|
|
39
40
|
): ComponentType<P> => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
const WrappedComponent: React.FC<P> = props => {
|
|
42
|
+
return (
|
|
43
|
+
<Ctx.Provider value={ctx}>
|
|
44
|
+
<Component {...props} />
|
|
45
|
+
</Ctx.Provider>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return WrappedComponent;
|
|
45
50
|
};
|
|
46
51
|
|
|
47
52
|
return {
|