@bbki.ng/site 5.4.20 → 5.4.22
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 +4 -4
- package/src/blog/app.tsx +13 -18
- package/src/blog/components/index.tsx +9 -19
- package/src/blog/hooks/use_authed_fetcher.ts +5 -4
- package/src/blog/hooks/use_shared_string_to_post.ts +17 -17
- package/src/blog/hooks/use_streaming.ts +16 -16
- package/src/blog/hooks/use_supa_session.ts +9 -8
- package/src/blog/pages/extensions/txt/article.tsx +13 -33
- package/src/blog/pages/extensions/txt/index.tsx +11 -17
- package/src/blog/articles/index.ts +0 -46
- package/src/blog/components/aspect_ratio_box/index.tsx +0 -29
- package/src/blog/components/img_list/index.tsx +0 -43
- package/src/blog/components/stickers/index.tsx +0 -46
- package/src/blog/components/table_skeleton/index.tsx +0 -40
- package/src/blog/components/video_player/index.tsx +0 -82
- package/src/blog/global/mdx.d.ts +0 -9
- package/src/blog/pages/extensions/txt/consts.ts +0 -8
- package/src/blog/pages/tags/index.tsx +0 -28
- package/src/blog/pages/tags/tag_result.tsx +0 -19
- package/src/blog/pages/upload/index.tsx +0 -39
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @bbki.ng/site
|
|
2
2
|
|
|
3
|
+
## 5.4.22
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f40a245: bug fix
|
|
8
|
+
|
|
9
|
+
## 5.4.21
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 625ea77: remove mdx articles
|
|
14
|
+
- Updated dependencies [625ea77]
|
|
15
|
+
- @bbki.ng/components@5.2.12
|
|
16
|
+
|
|
3
17
|
## 5.4.20
|
|
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.4.
|
|
3
|
+
"version": "5.4.22",
|
|
4
4
|
"description": "code behind bbki.ng",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"react-router-dom": "6",
|
|
19
19
|
"sonner": "1.4.0",
|
|
20
20
|
"swr": "^2.2.5",
|
|
21
|
-
"@bbki.ng/components": "5.2.
|
|
21
|
+
"@bbki.ng/components": "5.2.12"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@eslint/compat": "^1.0.0",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"vite-plugin-mdx": "^3.5.8",
|
|
61
61
|
"vite-plugin-pwa": "0.19",
|
|
62
62
|
"workbox-window": "^6.3.0",
|
|
63
|
-
"@bbki.ng/config": "1.0.
|
|
64
|
-
"@bbki.ng/stylebase": "3.1.
|
|
63
|
+
"@bbki.ng/config": "1.0.4",
|
|
64
|
+
"@bbki.ng/stylebase": "3.1.5"
|
|
65
65
|
},
|
|
66
66
|
"author": "bbbottle",
|
|
67
67
|
"license": "MIT",
|
package/src/blog/app.tsx
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import React, { useContext } from 'react';
|
|
1
|
+
import React, { useContext, useMemo } from 'react';
|
|
2
2
|
import { Outlet, Route, Routes } from 'react-router-dom';
|
|
3
3
|
import { Nav, NotFound, Page } from '@bbki.ng/components';
|
|
4
4
|
import { HotKeyNav } from './components';
|
|
5
5
|
import { Cover, Streaming } from './pages';
|
|
6
6
|
|
|
7
7
|
import ArticlePage from '@/pages/extensions/txt/article';
|
|
8
|
-
import Tags from '@/pages/tags';
|
|
9
|
-
import TagsResult from '@/pages/tags/tag_result';
|
|
10
8
|
import Txt from '@/pages/extensions/txt';
|
|
11
9
|
|
|
12
10
|
import { usePaths } from '@/hooks';
|
|
@@ -22,31 +20,31 @@ import { ThreeColLayout, ErrorBoundary } from '@bbki.ng/components';
|
|
|
22
20
|
import { useDynamicLogo } from './hooks/use_dynamic_logo';
|
|
23
21
|
|
|
24
22
|
const Layout = () => {
|
|
23
|
+
const paths = usePaths();
|
|
25
24
|
const { isLoading } = useContext(GlobalLoadingContext);
|
|
26
25
|
const logo = useDynamicLogo();
|
|
26
|
+
|
|
27
|
+
const middleRenderer = useMemo(() => {
|
|
28
|
+
return () => (
|
|
29
|
+
<ErrorBoundary>
|
|
30
|
+
<Outlet />
|
|
31
|
+
</ErrorBoundary>
|
|
32
|
+
);
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
27
35
|
return (
|
|
28
36
|
<Page
|
|
29
37
|
nav={
|
|
30
38
|
<AppCtxMenu>
|
|
31
39
|
<Nav
|
|
32
|
-
paths={
|
|
40
|
+
paths={paths}
|
|
33
41
|
className="gradient-blur-cover select-none"
|
|
34
42
|
loading={isLoading}
|
|
35
43
|
customLogo={logo}
|
|
36
44
|
/>
|
|
37
45
|
</AppCtxMenu>
|
|
38
46
|
}
|
|
39
|
-
main={
|
|
40
|
-
<ThreeColLayout
|
|
41
|
-
middleRenderer={() => {
|
|
42
|
-
return (
|
|
43
|
-
<ErrorBoundary>
|
|
44
|
-
<Outlet />
|
|
45
|
-
</ErrorBoundary>
|
|
46
|
-
);
|
|
47
|
-
}}
|
|
48
|
-
/>
|
|
49
|
-
}
|
|
47
|
+
main={<ThreeColLayout middleRenderer={middleRenderer} />}
|
|
50
48
|
/>
|
|
51
49
|
);
|
|
52
50
|
};
|
|
@@ -69,9 +67,6 @@ export const App = () => {
|
|
|
69
67
|
<Route path=":title" element={<ArticlePage />} />
|
|
70
68
|
</Route>
|
|
71
69
|
|
|
72
|
-
<Route path="tags" element={<Tags />} />
|
|
73
|
-
<Route path="tags/:tag" element={<TagsResult />} />
|
|
74
|
-
|
|
75
70
|
<Route path="bot" element={<BotRedirect />} />
|
|
76
71
|
<Route path="login" element={<Login />} />
|
|
77
72
|
<Route path="now" element={<Streaming />} />
|
|
@@ -1,32 +1,22 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { LinkList } from
|
|
3
|
-
import { BlurCover } from
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { LinkList } from '@bbki.ng/components';
|
|
3
|
+
import { BlurCover } from '@bbki.ng/components';
|
|
4
4
|
|
|
5
|
-
export {
|
|
5
|
+
export { withArticleWrapper } from './with_wrapper';
|
|
6
6
|
|
|
7
|
-
export {
|
|
7
|
+
export { HotKeyNav } from './hotkey_nav';
|
|
8
8
|
|
|
9
|
-
export {
|
|
9
|
+
export { BlurCover } from './blur_cover';
|
|
10
10
|
|
|
11
|
-
export {
|
|
11
|
+
export { ReloadPrompt } from './reload_prompt';
|
|
12
12
|
|
|
13
|
-
export {
|
|
14
|
-
|
|
15
|
-
export { BlurCover } from "./blur_cover";
|
|
16
|
-
|
|
17
|
-
export { ReloadPrompt } from "./reload_prompt";
|
|
18
|
-
|
|
19
|
-
export { Stickers } from "./stickers";
|
|
20
|
-
|
|
21
|
-
export { Tags } from "./tags";
|
|
22
|
-
|
|
23
|
-
export { MySuspense } from "./my_suspense";
|
|
13
|
+
export { MySuspense } from './my_suspense';
|
|
24
14
|
|
|
25
15
|
export const CenterLinkList = (props: any) => {
|
|
26
16
|
return (
|
|
27
17
|
<div className="flex justify-center relative p-16 h-full">
|
|
28
18
|
<LinkList {...props} />
|
|
29
|
-
<BlurCover status={props.loading ?
|
|
19
|
+
<BlurCover status={props.loading ? 'show' : 'silent'} />
|
|
30
20
|
</div>
|
|
31
21
|
);
|
|
32
22
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { useSupabaseSession } from
|
|
2
|
-
import { apiFetcher, withToken } from
|
|
3
|
-
import { useCallback } from
|
|
1
|
+
import { useSupabaseSession } from '@/hooks/use_supa_session';
|
|
2
|
+
import { apiFetcher, withToken } from '@/utils';
|
|
3
|
+
import { useCallback, useMemo } from 'react';
|
|
4
4
|
|
|
5
5
|
export const useAuthedFetcher = () => {
|
|
6
6
|
const { access_token: token } = useSupabaseSession() || {};
|
|
7
|
-
|
|
7
|
+
const fetcherWithToken = useMemo(() => withToken(apiFetcher), []);
|
|
8
|
+
return useCallback(fetcherWithToken(token), [token, fetcherWithToken]);
|
|
8
9
|
};
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import {useEffect} from
|
|
2
|
-
import {useAuthedStringPost} from
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useAuthedStringPost } from '@/hooks/use_authed_string_post';
|
|
3
3
|
|
|
4
4
|
export const useSharedStringToPost = () => {
|
|
5
|
-
|
|
5
|
+
const post = useAuthedStringPost();
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
}
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const handleSharedString = (event: MessageEvent) => {
|
|
9
|
+
if (event.data && typeof event.data === 'string') {
|
|
10
|
+
const content = event.data;
|
|
11
|
+
if (content) {
|
|
12
|
+
post(content);
|
|
15
13
|
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
window.addEventListener('message', handleSharedString);
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
19
|
+
return () => {
|
|
20
|
+
window.removeEventListener('message', handleSharedString);
|
|
21
|
+
};
|
|
22
|
+
}, [post]);
|
|
23
|
+
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import useSWR from
|
|
2
|
-
import useSWRInfinite from
|
|
3
|
-
import { baseFetcher, withBBApi } from
|
|
4
|
-
import { API_CF_ENDPOINT } from
|
|
5
|
-
import { useContext, useEffect, useState, useCallback } from
|
|
6
|
-
import { GlobalLoadingContext } from
|
|
1
|
+
import useSWR from 'swr';
|
|
2
|
+
import useSWRInfinite from 'swr/infinite';
|
|
3
|
+
import { baseFetcher, withBBApi } from '@/utils';
|
|
4
|
+
import { API_CF_ENDPOINT } from '@/constants/routes';
|
|
5
|
+
import { useContext, useEffect, useState, useCallback } from 'react';
|
|
6
|
+
import { GlobalLoadingContext } from '@/context/global_loading_state_provider';
|
|
7
7
|
|
|
8
8
|
// In dev, use /api prefix to leverage Vite proxy to localhost:8787
|
|
9
|
-
const isProd = typeof window !==
|
|
10
|
-
const API_BASE = !isProd ?
|
|
9
|
+
const isProd = typeof window !== 'undefined' && /^https:\/\/bbki.ng/.test(window.location.href);
|
|
10
|
+
const API_BASE = !isProd ? '/api' : API_CF_ENDPOINT;
|
|
11
11
|
|
|
12
12
|
export type StreamingItem = {
|
|
13
13
|
id: string;
|
|
@@ -38,13 +38,13 @@ function buildStreamingUrl(params: StreamingQueryParams = {}): string {
|
|
|
38
38
|
const url = new URL(`${API_BASE}/streaming`, !isProd ? window.location.origin : undefined);
|
|
39
39
|
|
|
40
40
|
if (params.before) {
|
|
41
|
-
url.searchParams.set(
|
|
41
|
+
url.searchParams.set('before', params.before);
|
|
42
42
|
}
|
|
43
43
|
if (params.after) {
|
|
44
|
-
url.searchParams.set(
|
|
44
|
+
url.searchParams.set('after', params.after);
|
|
45
45
|
}
|
|
46
46
|
if (params.offset) {
|
|
47
|
-
url.searchParams.set(
|
|
47
|
+
url.searchParams.set('offset', params.offset.toString());
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
return !isProd ? url.pathname + url.search : url.toString();
|
|
@@ -61,11 +61,11 @@ async function fetchStreaming(params: StreamingQueryParams = {}): Promise<Stream
|
|
|
61
61
|
|
|
62
62
|
// SWR key generator for streaming queries
|
|
63
63
|
const getStreamingKey = (params: StreamingQueryParams) => {
|
|
64
|
-
const parts = [
|
|
64
|
+
const parts = ['streaming'];
|
|
65
65
|
if (params.before) parts.push(`before=${params.before}`);
|
|
66
66
|
if (params.after) parts.push(`after=${params.after}`);
|
|
67
67
|
if (params.offset) parts.push(`offset=${params.offset}`);
|
|
68
|
-
return parts.join(
|
|
68
|
+
return parts.join('?');
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
interface UseStreamingOptions {
|
|
@@ -91,12 +91,12 @@ export function useStreaming(options: UseStreamingOptions = {}) {
|
|
|
91
91
|
|
|
92
92
|
const isLoading = !data && !error;
|
|
93
93
|
|
|
94
|
-
const [
|
|
94
|
+
const [, forceUpdate] = useState(0);
|
|
95
95
|
|
|
96
96
|
// make rerender when customElement defined
|
|
97
97
|
useEffect(() => {
|
|
98
|
-
customElements.whenDefined(
|
|
99
|
-
forceUpdate(
|
|
98
|
+
customElements.whenDefined('bb-msg-history').then(() => {
|
|
99
|
+
forceUpdate(prev => prev + 1);
|
|
100
100
|
});
|
|
101
101
|
}, []);
|
|
102
102
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { createClient, Session } from
|
|
2
|
-
import { SUPABASE } from
|
|
3
|
-
import { useEffect, useState } from
|
|
4
|
-
import { BBKingSession } from
|
|
1
|
+
import { createClient, Session } from '@supabase/supabase-js';
|
|
2
|
+
import { SUPABASE } from '@/constants';
|
|
3
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
4
|
+
import { BBKingSession } from '@/types/supabase';
|
|
5
5
|
|
|
6
6
|
export const useSupabaseSession = (): BBKingSession | null => {
|
|
7
|
-
const supabase = createClient(SUPABASE.URL, SUPABASE.ANNO);
|
|
7
|
+
const supabase = useMemo(() => createClient(SUPABASE.URL, SUPABASE.ANNO), []);
|
|
8
8
|
|
|
9
9
|
const extendSess = (sess: Session | null) => {
|
|
10
10
|
if (!sess) {
|
|
@@ -20,12 +20,13 @@ export const useSupabaseSession = (): BBKingSession | null => {
|
|
|
20
20
|
const [session, setSession] = useState(extendSess(supabase.auth.session()));
|
|
21
21
|
|
|
22
22
|
useEffect(() => {
|
|
23
|
-
supabase.auth.onAuthStateChange((event, session) => {
|
|
24
|
-
if (event ===
|
|
23
|
+
const { data: subscription } = supabase.auth.onAuthStateChange((event, session) => {
|
|
24
|
+
if (event === 'SIGNED_IN') {
|
|
25
25
|
setSession(extendSess(session));
|
|
26
26
|
}
|
|
27
27
|
});
|
|
28
|
-
|
|
28
|
+
return () => subscription?.unsubscribe();
|
|
29
|
+
}, [supabase]);
|
|
29
30
|
|
|
30
31
|
return session;
|
|
31
32
|
};
|
|
@@ -1,31 +1,15 @@
|
|
|
1
|
-
import React, { ReactElement, useContext, useEffect } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { useBlogScrollReset } from "@/hooks/use_blog_scroll_pos_restoration";
|
|
14
|
-
|
|
15
|
-
type TArticleMap = {
|
|
16
|
-
[key: string]: ReactElement;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const ArticleMap: TArticleMap = {};
|
|
20
|
-
|
|
21
|
-
MdxArticleList.forEach((article: unknown) => {
|
|
22
|
-
const { meta, default: component } = article as MdxArticle;
|
|
23
|
-
const dateStr = meta.created_at
|
|
24
|
-
? meta.created_at.toISOString().split("T")[0]
|
|
25
|
-
: "";
|
|
26
|
-
const Article = withArticleWrapper(component);
|
|
27
|
-
ArticleMap[meta.title] = <Article {...meta} date={dateStr} />;
|
|
28
|
-
});
|
|
1
|
+
import React, { ReactElement, useContext, useEffect } from 'react';
|
|
2
|
+
import { withArticleWrapper } from '@/components';
|
|
3
|
+
import { MdxArticle } from '@/types/articles';
|
|
4
|
+
import { NotFound, DropZone } from '@bbki.ng/components';
|
|
5
|
+
import { useLocation, useParams } from 'react-router-dom';
|
|
6
|
+
import { usePosts } from '@/hooks/use_posts';
|
|
7
|
+
import { ArticlePage } from '@/components/article';
|
|
8
|
+
import { GlobalLoadingContext } from '@/context/global_loading_state_provider';
|
|
9
|
+
import { useFile2Post } from '@/hooks/use_file_to_post';
|
|
10
|
+
import { useAuthed } from '@/hooks/use_authed';
|
|
11
|
+
import { ArticleCtxMenu } from '@/components/article_ctx_menu';
|
|
12
|
+
import { useBlogScrollReset } from '@/hooks/use_blog_scroll_pos_restoration';
|
|
29
13
|
|
|
30
14
|
export default () => {
|
|
31
15
|
const { title } = useParams();
|
|
@@ -41,10 +25,6 @@ export default () => {
|
|
|
41
25
|
return <NotFound />;
|
|
42
26
|
}
|
|
43
27
|
|
|
44
|
-
if (ArticleMap[title]) {
|
|
45
|
-
return ArticleMap[title];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
28
|
if (isError) {
|
|
49
29
|
return <NotFound />;
|
|
50
30
|
}
|
|
@@ -53,7 +33,7 @@ export default () => {
|
|
|
53
33
|
return null;
|
|
54
34
|
}
|
|
55
35
|
|
|
56
|
-
const date = posts.created_at ? posts.created_at.split(
|
|
36
|
+
const date = posts.created_at ? posts.created_at.split('T')[0] : '';
|
|
57
37
|
|
|
58
38
|
return (
|
|
59
39
|
<DropZone onDrop={reader} disabled={!isKing}>
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
useBlogScroll,
|
|
12
|
-
useBlogScrollRestoration,
|
|
13
|
-
} from "@/hooks/use_blog_scroll_pos_restoration";
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { LinkProps, DropZone, Button } from '@bbki.ng/components';
|
|
3
|
+
import { usePosts } from '@/hooks/use_posts';
|
|
4
|
+
import { CenterLinkList } from '@/components';
|
|
5
|
+
import { useAuthed } from '@/hooks/use_authed';
|
|
6
|
+
import { useFile2Post } from '@/hooks/use_file_to_post';
|
|
7
|
+
import { useClipboardToPost } from '@/hooks/use_clipboard_to_post';
|
|
8
|
+
import { useLocation } from 'react-router-dom';
|
|
9
|
+
import { useBlogScroll, useBlogScrollRestoration } from '@/hooks/use_blog_scroll_pos_restoration';
|
|
14
10
|
|
|
15
11
|
type TxtProps = {
|
|
16
12
|
title?: string;
|
|
@@ -29,14 +25,12 @@ const Posts = (props: TxtProps) => {
|
|
|
29
25
|
}
|
|
30
26
|
|
|
31
27
|
if (isError) {
|
|
32
|
-
return <CenterLinkList links={props.articleList
|
|
28
|
+
return <CenterLinkList links={props.articleList} />;
|
|
33
29
|
}
|
|
34
30
|
|
|
35
|
-
const links = [...titleList, ...ArticleList];
|
|
36
|
-
|
|
37
31
|
return (
|
|
38
32
|
<CenterLinkList
|
|
39
|
-
links={props.articleList ||
|
|
33
|
+
links={props.articleList || titleList}
|
|
40
34
|
loading={isLoading}
|
|
41
35
|
footer={
|
|
42
36
|
<Button onClick={gotoTop} className="mt-128">
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import * as 回暖 from "./warming-up.mdx";
|
|
2
|
-
import * as 离开 from "./travel.mdx";
|
|
3
|
-
import * as 降温 from "./cooldown.mdx";
|
|
4
|
-
import * as 大雪 from "./fall.mdx";
|
|
5
|
-
import * as 大寒 from "./major-cold.mdx";
|
|
6
|
-
import * as 春雨 from "./spring-rain.mdx";
|
|
7
|
-
import * as 春寒 from "./spring-cooldown.mdx";
|
|
8
|
-
import * as 入夏 from "./web-burnning.mdx";
|
|
9
|
-
import * as 六月 from "./black-river.mdx";
|
|
10
|
-
import * as 立秋 from "./liqiu.mdx";
|
|
11
|
-
import * as 照片 from "./photos.mdx";
|
|
12
|
-
// import * as 小乌鸦 from "./xwy.mdx";
|
|
13
|
-
import * as 我要看雪 from "./xwy-and-snowing.mdx";
|
|
14
|
-
import * as 做饭 from "./cooking.mdx";
|
|
15
|
-
import * as 堂兄 from "./cousin.mdx";
|
|
16
|
-
import * as 红色的枪 from "./red-gun.mdx";
|
|
17
|
-
import * as 圆粉 from "./rice-noodle.mdx";
|
|
18
|
-
import * as 树叶 from "./leaves.mdx";
|
|
19
|
-
import * as 惊醒 from "./woke-up.mdx";
|
|
20
|
-
import * as 口蘑 from "./marshroom.mdx";
|
|
21
|
-
import * as 站一下 from "./moment.mdx";
|
|
22
|
-
import * as 干衣服 from "./cloth.mdx";
|
|
23
|
-
|
|
24
|
-
export const MdxArticleList = [
|
|
25
|
-
离开,
|
|
26
|
-
降温,
|
|
27
|
-
大雪,
|
|
28
|
-
大寒,
|
|
29
|
-
回暖,
|
|
30
|
-
春雨,
|
|
31
|
-
春寒,
|
|
32
|
-
入夏,
|
|
33
|
-
六月,
|
|
34
|
-
立秋,
|
|
35
|
-
照片,
|
|
36
|
-
// 小乌鸦,
|
|
37
|
-
做饭,
|
|
38
|
-
堂兄,
|
|
39
|
-
红色的枪,
|
|
40
|
-
圆粉,
|
|
41
|
-
树叶,
|
|
42
|
-
惊醒,
|
|
43
|
-
口蘑,
|
|
44
|
-
站一下,
|
|
45
|
-
干衣服,
|
|
46
|
-
];
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import classnames from "classnames";
|
|
2
|
-
import React from "react";
|
|
3
|
-
|
|
4
|
-
type aspectRatioBoxProps = {
|
|
5
|
-
width: number | string;
|
|
6
|
-
hwRatio: number;
|
|
7
|
-
className?: string;
|
|
8
|
-
children?: any;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export const AspectRatioBox = (props: aspectRatioBoxProps) => {
|
|
12
|
-
const { className, width, hwRatio, children } = props;
|
|
13
|
-
const innerStyle = {
|
|
14
|
-
width: "100%",
|
|
15
|
-
paddingTop: `${hwRatio * 100}%`,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<div
|
|
20
|
-
style={{ width, maxWidth: "100%" }}
|
|
21
|
-
className={classnames(className, "relative")}
|
|
22
|
-
>
|
|
23
|
-
<div style={innerStyle} />
|
|
24
|
-
{children && (
|
|
25
|
-
<div className="absolute top-0 bottom-0 left-0 right-0">{children}</div>
|
|
26
|
-
)}
|
|
27
|
-
</div>
|
|
28
|
-
);
|
|
29
|
-
};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import React, { FunctionComponent, ReactElement, ReactNode } from "react";
|
|
2
|
-
import classnames from "classnames";
|
|
3
|
-
import { Photo } from "@/types/photo";
|
|
4
|
-
import { Article, Img } from "@bbki.ng/components";
|
|
5
|
-
|
|
6
|
-
interface imgListProps {
|
|
7
|
-
className: string;
|
|
8
|
-
imgList: Photo[];
|
|
9
|
-
description?: any;
|
|
10
|
-
beforeListRenderer?: () => ReactNode;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const BaseImgList: FunctionComponent<imgListProps> = (props: imgListProps) => {
|
|
14
|
-
const { imgList, className, beforeListRenderer } = props;
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<div className={classnames("max-h-full no-scrollbar overflow-auto", className)}>
|
|
18
|
-
{beforeListRenderer && <>{beforeListRenderer()}</>}
|
|
19
|
-
{imgList.map((img, index) => {
|
|
20
|
-
const isLast = index === imgList.length - 1;
|
|
21
|
-
return (
|
|
22
|
-
<div key={img.src}>
|
|
23
|
-
<Img {...img} className={classnames({ "mb-256": !isLast })} />
|
|
24
|
-
</div>
|
|
25
|
-
);
|
|
26
|
-
})}
|
|
27
|
-
</div>
|
|
28
|
-
);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
interface TitledImageListProps extends imgListProps {
|
|
32
|
-
title: string | ReactElement;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const ImgList = (props: TitledImageListProps) => {
|
|
36
|
-
const { title, description, ...rest } = props;
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<Article title={title} description={description}>
|
|
40
|
-
<BaseImgList {...rest} />
|
|
41
|
-
</Article>
|
|
42
|
-
);
|
|
43
|
-
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Img } from "@bbki.ng/components";
|
|
3
|
-
import { NavLink, useLocation } from "react-router-dom";
|
|
4
|
-
|
|
5
|
-
export const Stickers = () => {
|
|
6
|
-
const { pathname } = useLocation();
|
|
7
|
-
|
|
8
|
-
if (pathname !== "/") {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return (
|
|
13
|
-
<div className="fixed bottom-128 md:bottom-256 right-16 z-10 md:right-64">
|
|
14
|
-
<NavLink to="projects">
|
|
15
|
-
<Img
|
|
16
|
-
size="large"
|
|
17
|
-
src="https://zjh-im-res.oss-cn-shenzhen.aliyuncs.com/image/stickers/sticker-water-delivery.jpg"
|
|
18
|
-
className="-rotate-[32.95deg] relative top-0 md:-top-64 left-64 md:left-[unset]"
|
|
19
|
-
width={126}
|
|
20
|
-
height={59}
|
|
21
|
-
renderedWidth={126}
|
|
22
|
-
/>
|
|
23
|
-
</NavLink>
|
|
24
|
-
<NavLink to="404">
|
|
25
|
-
<Img
|
|
26
|
-
size="large"
|
|
27
|
-
src="https://zjh-im-res.oss-cn-shenzhen.aliyuncs.com/image/stickers/sticker-lock.jpg"
|
|
28
|
-
className="rotate-[10.77deg] relative left-64 md:left-[unset]"
|
|
29
|
-
width={93}
|
|
30
|
-
height={50}
|
|
31
|
-
renderedWidth={93}
|
|
32
|
-
/>
|
|
33
|
-
</NavLink>
|
|
34
|
-
<NavLink to="blog">
|
|
35
|
-
<Img
|
|
36
|
-
size="large"
|
|
37
|
-
src="https://zjh-im-res.oss-cn-shenzhen.aliyuncs.com/image/stickers/bar-code.jpg"
|
|
38
|
-
className="-rotate-[13.37deg] relative top-64 left-64 md:left-[unset] md:right-256 md:top-128"
|
|
39
|
-
width={176}
|
|
40
|
-
height={60}
|
|
41
|
-
renderedWidth={176}
|
|
42
|
-
/>
|
|
43
|
-
</NavLink>
|
|
44
|
-
</div>
|
|
45
|
-
);
|
|
46
|
-
};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { Skeleton, SkeletonColor, Table } from "@bbki.ng/components";
|
|
2
|
-
import React from "react";
|
|
3
|
-
|
|
4
|
-
const CELL_STYLE = {
|
|
5
|
-
width: 100,
|
|
6
|
-
maxWidth: 100,
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const TableSkeleton = (props: {
|
|
10
|
-
headers?: string[];
|
|
11
|
-
cellStyle?: { width: number; maxWidth: number };
|
|
12
|
-
}) => {
|
|
13
|
-
const { headers, cellStyle = CELL_STYLE } = props;
|
|
14
|
-
const [name = "名字", status = "状态"] = headers || [];
|
|
15
|
-
const renderHeader = () => {
|
|
16
|
-
return (
|
|
17
|
-
<>
|
|
18
|
-
<Table.HCell style={cellStyle}>{name}</Table.HCell>
|
|
19
|
-
<Table.HCell style={cellStyle}>{status}</Table.HCell>
|
|
20
|
-
</>
|
|
21
|
-
);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const renderRow = () => {
|
|
25
|
-
return (
|
|
26
|
-
<>
|
|
27
|
-
<Table.Cell style={cellStyle}>
|
|
28
|
-
<Skeleton width={84} height={16} bgColor={SkeletonColor.BLUE} />
|
|
29
|
-
</Table.Cell>
|
|
30
|
-
<Table.Cell style={cellStyle}>
|
|
31
|
-
<Skeleton width={32} height={16} bgColor={SkeletonColor.GRAY} />
|
|
32
|
-
</Table.Cell>
|
|
33
|
-
</>
|
|
34
|
-
);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
return (
|
|
38
|
-
<Table rowCount={3} rowRenderer={renderRow} headerRenderer={renderHeader} />
|
|
39
|
-
);
|
|
40
|
-
};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import React, { ReactEventHandler, useEffect, useState } from "react";
|
|
2
|
-
import classnames from "classnames";
|
|
3
|
-
import { useVideoControls, useVideoEleHeight, useVideoProgress } from "@/hooks";
|
|
4
|
-
import { BlurCover, ProgressBar } from "@/components";
|
|
5
|
-
import { BgColors, TextColors } from "@/types/color";
|
|
6
|
-
import { AspectRatioBox } from "@/components/aspect_ratio_box";
|
|
7
|
-
|
|
8
|
-
const VIDEO_TAG_ASPECT_RATIO = 0.5624910522548318;
|
|
9
|
-
|
|
10
|
-
type videoPlayProps = {
|
|
11
|
-
src: string;
|
|
12
|
-
className?: string;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const VideoPlayer = (props: videoPlayProps) => {
|
|
16
|
-
const { src, className } = props;
|
|
17
|
-
const [hovered, setHovered] = useState(false);
|
|
18
|
-
const [showPlayer, setShowPlayer] = useState(false);
|
|
19
|
-
const { videoRef, toggle, isPlay } = useVideoControls();
|
|
20
|
-
const { progress, onTimeUpdate } = useVideoProgress();
|
|
21
|
-
const VideoHeight = useVideoEleHeight(videoRef);
|
|
22
|
-
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
if (!videoRef.current) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
videoRef.current.load();
|
|
28
|
-
}, []);
|
|
29
|
-
|
|
30
|
-
const onPlayerReady: ReactEventHandler = () => {
|
|
31
|
-
setShowPlayer(true);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const cls = classnames({ hidden: !showPlayer });
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<div
|
|
38
|
-
className={classnames(
|
|
39
|
-
"flex flex-col relative cursor-pointer",
|
|
40
|
-
className,
|
|
41
|
-
BgColors.LIGHT_GRAY
|
|
42
|
-
)}
|
|
43
|
-
onClick={async () => {
|
|
44
|
-
await toggle();
|
|
45
|
-
if (!isPlay) {
|
|
46
|
-
setHovered(false);
|
|
47
|
-
}
|
|
48
|
-
}}
|
|
49
|
-
onMouseEnter={() => {
|
|
50
|
-
setHovered(true);
|
|
51
|
-
}}
|
|
52
|
-
onMouseLeave={() => {
|
|
53
|
-
setHovered(false);
|
|
54
|
-
}}
|
|
55
|
-
>
|
|
56
|
-
<AspectRatioBox
|
|
57
|
-
width="100%"
|
|
58
|
-
hwRatio={VIDEO_TAG_ASPECT_RATIO}
|
|
59
|
-
className={BgColors.LIGHT_GRAY}
|
|
60
|
-
>
|
|
61
|
-
<video
|
|
62
|
-
playsInline
|
|
63
|
-
ref={videoRef}
|
|
64
|
-
src={src}
|
|
65
|
-
className={cls}
|
|
66
|
-
onTimeUpdate={onTimeUpdate}
|
|
67
|
-
onCanPlayThrough={onPlayerReady}
|
|
68
|
-
/>
|
|
69
|
-
</AspectRatioBox>
|
|
70
|
-
{hovered && showPlayer && (
|
|
71
|
-
<BlurCover
|
|
72
|
-
textColor={isPlay ? TextColors.RED : TextColors.BLUE}
|
|
73
|
-
height={VideoHeight}
|
|
74
|
-
visibleOnHover
|
|
75
|
-
>
|
|
76
|
-
{isPlay ? "pause" : "play"}
|
|
77
|
-
</BlurCover>
|
|
78
|
-
)}
|
|
79
|
-
{showPlayer && <ProgressBar progress={progress} />}
|
|
80
|
-
</div>
|
|
81
|
-
);
|
|
82
|
-
};
|
package/src/blog/global/mdx.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { getAllTags } from "@/utils/tags";
|
|
3
|
-
import { MdxArticleList } from "@/articles";
|
|
4
|
-
import { Tags } from "@/components";
|
|
5
|
-
import { ROUTES } from "@/constants";
|
|
6
|
-
|
|
7
|
-
type tag =
|
|
8
|
-
| {
|
|
9
|
-
path: string;
|
|
10
|
-
name: string;
|
|
11
|
-
}
|
|
12
|
-
| string;
|
|
13
|
-
|
|
14
|
-
export default (props: {
|
|
15
|
-
inline?: boolean;
|
|
16
|
-
className?: string;
|
|
17
|
-
withAll?: boolean;
|
|
18
|
-
}) => {
|
|
19
|
-
const tags = [...getAllTags(MdxArticleList)] as tag[];
|
|
20
|
-
|
|
21
|
-
if (props.withAll) {
|
|
22
|
-
tags.unshift({
|
|
23
|
-
path: ROUTES.CONTENT,
|
|
24
|
-
name: "全部",
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
return <Tags tags={tags} {...props} />;
|
|
28
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import Txt from "@/pages/extensions/txt";
|
|
3
|
-
import { getArticleListByTag } from "@/utils/tags";
|
|
4
|
-
import { MdxArticleList } from "@/articles";
|
|
5
|
-
import { useParams } from "react-router-dom";
|
|
6
|
-
import { Error as ErrorPanel } from "@bbki.ng/components";
|
|
7
|
-
|
|
8
|
-
export default () => {
|
|
9
|
-
const { tag } = useParams();
|
|
10
|
-
if (!tag) {
|
|
11
|
-
return <ErrorPanel error={new Error("missing tagName")} />;
|
|
12
|
-
}
|
|
13
|
-
return (
|
|
14
|
-
<Txt
|
|
15
|
-
title={`#${tag}`}
|
|
16
|
-
articleList={getArticleListByTag(MdxArticleList, tag)}
|
|
17
|
-
/>
|
|
18
|
-
);
|
|
19
|
-
};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import { ArticlePage } from "@/components/article";
|
|
3
|
-
import { threeColWrapper } from "@/components/with_wrapper";
|
|
4
|
-
import { ImageUploader } from "@/components/ImageUploader";
|
|
5
|
-
import { UploadResult } from "@/types/upload";
|
|
6
|
-
import { Button } from "@bbki.ng/components";
|
|
7
|
-
import { copyToClipboard } from "@/utils";
|
|
8
|
-
|
|
9
|
-
const Upload = () => {
|
|
10
|
-
const [source, setSource] = useState("");
|
|
11
|
-
const buildSource = (result: UploadResult) =>
|
|
12
|
-
`<Img
|
|
13
|
-
src="${result.src}"
|
|
14
|
-
height={${result.height}}
|
|
15
|
-
width={${result.width}}
|
|
16
|
-
renderedWidth={${result.width}}
|
|
17
|
-
removeBlurBgAfterLoad
|
|
18
|
-
/>`;
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<ArticlePage title="图片素材上传">
|
|
22
|
-
<>
|
|
23
|
-
<ImageUploader
|
|
24
|
-
onUploadSuccess={(res) => {
|
|
25
|
-
setSource(buildSource(res));
|
|
26
|
-
}}
|
|
27
|
-
/>
|
|
28
|
-
{source && <pre>{source}</pre>}
|
|
29
|
-
{source && (
|
|
30
|
-
<Button className="m-16" onClick={() => copyToClipboard(source)}>
|
|
31
|
-
复制代码
|
|
32
|
-
</Button>
|
|
33
|
-
)}
|
|
34
|
-
</>
|
|
35
|
-
</ArticlePage>
|
|
36
|
-
);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export const UploadPage = Upload;
|