@bbki.ng/site 5.5.36 → 5.5.37
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 +8 -0
- package/eslint.config.js +7 -0
- package/index.d.ts +0 -2
- package/package.json +2 -2
- package/src/blog/app.tsx +1 -1
- package/src/blog/hooks/use_posts.ts +6 -1
- package/src/blog/pages/extensions/txt/article.tsx +5 -2
- package/src/blog/utils/index.ts +15 -10
- package/src/plugins/now/components/streaming/index.tsx +2 -1
- package/src/plugins/xwy/index.ts +4 -1
- package/src/plugins/xwy/types/index.ts +18 -0
- package/tsconfig.json +1 -1
package/CHANGELOG.md
CHANGED
package/eslint.config.js
CHANGED
|
@@ -9,6 +9,13 @@ const __dirname = path.dirname(__filename);
|
|
|
9
9
|
export default [
|
|
10
10
|
includeIgnoreFile(path.resolve(__dirname, '.gitignore')),
|
|
11
11
|
...webConfig,
|
|
12
|
+
{
|
|
13
|
+
languageOptions: {
|
|
14
|
+
globals: {
|
|
15
|
+
GLOBAL_COMMIT_HASH: 'readonly',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
12
19
|
{
|
|
13
20
|
rules: {
|
|
14
21
|
// Site specific overrides
|
package/index.d.ts
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.37",
|
|
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.18"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@eslint/compat": "^1.0.0",
|
package/src/blog/app.tsx
CHANGED
|
@@ -36,8 +36,8 @@ const AppRoutes = () => {
|
|
|
36
36
|
{pluginEntries?.map(route => (
|
|
37
37
|
<Route key={route.path} path={route.path} element={<Slot name="route" data={route} />} />
|
|
38
38
|
))}
|
|
39
|
+
<Route path="*" element={pluginEntries?.length ? <NotFound /> : null} />
|
|
39
40
|
</Route>
|
|
40
|
-
<Route path="*" element={<NotFound />} />
|
|
41
41
|
</Routes>
|
|
42
42
|
);
|
|
43
43
|
};
|
|
@@ -10,6 +10,11 @@ import { useMiddlewareRunner } from '#/core/hooks/useMiddlewareTransData';
|
|
|
10
10
|
const isProd = true;
|
|
11
11
|
const POSTS_API = !isProd ? '/api/posts' : `${API_ENDPOINT}/posts`;
|
|
12
12
|
|
|
13
|
+
interface PostsApiResponse {
|
|
14
|
+
data: IPost[];
|
|
15
|
+
// 可能还有其他字段如 status, message 等
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
export interface TitleListItem {
|
|
14
19
|
name: string;
|
|
15
20
|
to: string;
|
|
@@ -18,7 +23,7 @@ export interface TitleListItem {
|
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
export const usePosts = (name: string = '', suspense?: boolean) => {
|
|
21
|
-
const { data: response, error: swrError } = useSWR(POSTS_API, baseFetcher, {
|
|
26
|
+
const { data: response, error: swrError } = useSWR<PostsApiResponse>(POSTS_API, baseFetcher, {
|
|
22
27
|
revalidateOnFocus: false,
|
|
23
28
|
suspense,
|
|
24
29
|
});
|
|
@@ -6,6 +6,7 @@ import { usePosts } from '@/hooks/use_posts';
|
|
|
6
6
|
import { ArticlePage } from '@/components/article';
|
|
7
7
|
import { useBlogScrollReset } from '@/hooks/use_blog_scroll_pos_restoration';
|
|
8
8
|
import { useMiddlewareTransformedData } from '#/core/hooks/useMiddlewareTransData';
|
|
9
|
+
import { IPost } from '#/types/posts';
|
|
9
10
|
|
|
10
11
|
function TxtArticle() {
|
|
11
12
|
const { title } = useParams();
|
|
@@ -13,7 +14,9 @@ function TxtArticle() {
|
|
|
13
14
|
|
|
14
15
|
useBlogScrollReset();
|
|
15
16
|
|
|
16
|
-
const
|
|
17
|
+
const p = posts as IPost;
|
|
18
|
+
|
|
19
|
+
const transformedContent = useMiddlewareTransformedData('transformPostContent', p?.content);
|
|
17
20
|
|
|
18
21
|
if (!title) {
|
|
19
22
|
return <NotFound />;
|
|
@@ -27,7 +30,7 @@ function TxtArticle() {
|
|
|
27
30
|
return null;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
|
-
const date =
|
|
33
|
+
const date = p.createdAt ? p.createdAt.split('T')[0] : '';
|
|
31
34
|
|
|
32
35
|
return (
|
|
33
36
|
<ArticlePage title={title} date={date}>
|
package/src/blog/utils/index.ts
CHANGED
|
@@ -2,33 +2,38 @@ import { API_ENDPOINT } from '@/constants/routes';
|
|
|
2
2
|
|
|
3
3
|
import { getStableDeviceId } from './fingerprints';
|
|
4
4
|
|
|
5
|
-
type
|
|
5
|
+
type RequestInit = globalThis.RequestInit;
|
|
6
|
+
|
|
7
|
+
type Fetcher = <T>(resource: string, init?: RequestInit) => Promise<T>;
|
|
6
8
|
|
|
7
9
|
export const floatNumberToPercentageString = (num: number): string => {
|
|
8
10
|
return `${num * 100}%`;
|
|
9
11
|
};
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
// 2. 显式声明为 Fetcher 类型,init 默认值改为 RequestInit
|
|
14
|
+
export const baseFetcher: Fetcher = async (resource, init = {}) => {
|
|
12
15
|
const headers = new Headers(init.headers || {});
|
|
13
16
|
const fp = await getStableDeviceId();
|
|
14
17
|
headers.set('X-Device-Fingerprint', fp.id);
|
|
15
|
-
|
|
18
|
+
|
|
19
|
+
const response = await fetch(resource, {
|
|
16
20
|
...init,
|
|
17
21
|
headers,
|
|
18
22
|
mode: 'cors',
|
|
19
|
-
}).then(res => {
|
|
20
|
-
if (!res.ok) {
|
|
21
|
-
throw new Error('An error occurred while fetching the data.');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return res.json();
|
|
25
23
|
});
|
|
24
|
+
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error('An error occurred while fetching the data.');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return response.json();
|
|
26
30
|
};
|
|
27
31
|
|
|
32
|
+
// 3. 简化 withBBApi 类型定义,确保参数类型一致
|
|
28
33
|
export const withBBApi =
|
|
29
34
|
(fetcher: Fetcher) =>
|
|
30
35
|
(apiEndPoint: string): Fetcher =>
|
|
31
|
-
async (resource
|
|
36
|
+
async (resource, init = {}) =>
|
|
32
37
|
fetcher(`${apiEndPoint}/${resource}`, { ...init, mode: 'cors' });
|
|
33
38
|
|
|
34
39
|
export const cfApiFetcher = withBBApi(baseFetcher)(API_ENDPOINT);
|
|
@@ -9,6 +9,7 @@ import { useStreaming } from '../../hooks/use_streaming';
|
|
|
9
9
|
import { useScrollBtnVisibility } from './useScrollBtnVisibility';
|
|
10
10
|
|
|
11
11
|
declare global {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
12
13
|
namespace JSX {
|
|
13
14
|
interface IntrinsicElements {
|
|
14
15
|
'bb-msg-history': React.DetailedHTMLProps<
|
|
@@ -39,7 +40,7 @@ const Streaming = () => {
|
|
|
39
40
|
|
|
40
41
|
useEffect(() => {
|
|
41
42
|
const el = bbMsgHistoryRef.current;
|
|
42
|
-
let timer:
|
|
43
|
+
let timer: ReturnType<typeof setTimeout>;
|
|
43
44
|
if (!isLoading && el) {
|
|
44
45
|
// 检查自定义元素是否已定义并升级
|
|
45
46
|
if (el.scrollToBottom) {
|
package/src/plugins/xwy/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { IHostContext } from '#/types/hostApi';
|
|
|
2
2
|
import { IPlugin } from '#/types/plugin';
|
|
3
3
|
import { HookPoint } from '#/types/slots';
|
|
4
4
|
|
|
5
|
+
import { HookPointTypeMap, Transformer } from './types';
|
|
5
6
|
import { SpecialTitle } from './components/article';
|
|
6
7
|
import { XwyLogo } from './components/logo';
|
|
7
8
|
import { FontRules, LOADING_CLASS } from './const';
|
|
@@ -43,7 +44,9 @@ class XwyPlugin implements IPlugin {
|
|
|
43
44
|
ctx.api.registerSlot('articleTitle', SpecialTitle, this.id);
|
|
44
45
|
};
|
|
45
46
|
|
|
46
|
-
private trasformerMap:
|
|
47
|
+
private trasformerMap: {
|
|
48
|
+
[K in Extract<HookPoint, keyof HookPointTypeMap>]?: Array<Transformer<K>>;
|
|
49
|
+
} = {
|
|
47
50
|
transformTitleList: [pinTitle, transformTitleList],
|
|
48
51
|
transformBreadcrumbPath: [transformBreadcrumbPaths],
|
|
49
52
|
transformPostContent: [transformPostContent],
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { PathObj } from '@bbki.ng/ui';
|
|
2
|
+
|
|
3
|
+
import { TitleListItem } from '#/types/posts';
|
|
4
|
+
|
|
1
5
|
export interface FontConfig {
|
|
2
6
|
name: string;
|
|
3
7
|
src: string;
|
|
@@ -15,3 +19,17 @@ export interface FontRule {
|
|
|
15
19
|
extraCls?: string;
|
|
16
20
|
variant?: 'default' | 'special';
|
|
17
21
|
}
|
|
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/tsconfig.json
CHANGED