@bbki.ng/site 5.4.22 → 5.4.24
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 +16 -0
- package/index.html +12 -19
- package/package.json +5 -8
- package/src/blog/app.tsx +21 -33
- package/src/blog/components/article/index.tsx +8 -17
- package/src/blog/components/index.tsx +0 -6
- package/src/blog/components/share/share-btn.tsx +5 -8
- package/src/blog/constants/index.ts +1 -16
- package/src/blog/constants/routes.ts +12 -22
- package/src/blog/context/bbcontext.tsx +7 -7
- package/src/blog/hooks/index.ts +3 -18
- package/src/blog/hooks/use_dynamic_logo.tsx +6 -11
- package/src/blog/hooks/use_posts.ts +19 -10
- package/src/blog/hooks/use_role.ts +9 -14
- package/src/blog/hooks/use_streaming.ts +2 -2
- package/src/blog/index.tsx +5 -11
- package/src/blog/pages/cover/index.tsx +0 -1
- package/src/blog/pages/extensions/txt/article.tsx +7 -21
- package/src/blog/pages/extensions/txt/index.tsx +2 -17
- package/src/blog/pages/login/index.tsx +18 -42
- package/src/blog/swr.tsx +4 -7
- package/src/blog/utils/index.ts +9 -172
- package/vite.config.js +2 -1
- package/src/blog/articles/anti-logic.mdx +0 -61
- package/src/blog/articles/bbking-manual.mdx +0 -7
- package/src/blog/articles/black-river.mdx +0 -8
- package/src/blog/articles/celebration.mdx +0 -21
- package/src/blog/articles/cloth.mdx +0 -11
- package/src/blog/articles/cooking.mdx +0 -7
- package/src/blog/articles/cooldown.mdx +0 -12
- package/src/blog/articles/cousin.mdx +0 -15
- package/src/blog/articles/fall.mdx +0 -8
- package/src/blog/articles/img.mdx +0 -104
- package/src/blog/articles/leaves.mdx +0 -7
- package/src/blog/articles/liqiu.mdx +0 -7
- package/src/blog/articles/loading.mdx +0 -144
- package/src/blog/articles/love.mdx +0 -19
- package/src/blog/articles/major-cold.mdx +0 -14
- package/src/blog/articles/marshroom.mdx +0 -17
- package/src/blog/articles/men-without-women.mdx +0 -19
- package/src/blog/articles/moment.mdx +0 -9
- package/src/blog/articles/movie-day.mdx +0 -15
- package/src/blog/articles/photos.mdx +0 -13
- package/src/blog/articles/projects.mdx +0 -8
- package/src/blog/articles/pseudo-spring.mdx +0 -7
- package/src/blog/articles/quote.mdx +0 -26
- package/src/blog/articles/red-gun.mdx +0 -19
- package/src/blog/articles/rice-noodle.mdx +0 -21
- package/src/blog/articles/spring-cooldown.mdx +0 -8
- package/src/blog/articles/spring-rain.mdx +0 -10
- package/src/blog/articles/travel.mdx +0 -22
- package/src/blog/articles/warming-up.mdx +0 -10
- package/src/blog/articles/web-burnning.mdx +0 -10
- package/src/blog/articles/woke-up.mdx +0 -7
- package/src/blog/articles/xwy-and-snowing.mdx +0 -13
- package/src/blog/articles/xwy.mdx +0 -9
- package/src/blog/components/ImageUploader.tsx +0 -55
- package/src/blog/components/Img_ctx_menu/index.tsx +0 -67
- package/src/blog/components/Logger.tsx +0 -9
- package/src/blog/components/Pochacco/Pochacco.tsx +0 -29
- package/src/blog/components/Pochacco/idle.tsx +0 -31
- package/src/blog/components/Pochacco/watch.tsx +0 -28
- package/src/blog/components/Version.tsx +0 -14
- package/src/blog/components/app_ctx_menu/LoginMenuItem.tsx +0 -72
- package/src/blog/components/app_ctx_menu/PostMenuItem.tsx +0 -22
- package/src/blog/components/app_ctx_menu/VersionMenuItem.tsx +0 -13
- package/src/blog/components/app_ctx_menu/ViewSourceMenuItem.tsx +0 -34
- package/src/blog/components/app_ctx_menu/index.tsx +0 -35
- package/src/blog/components/article_ctx_menu/index.tsx +0 -58
- package/src/blog/components/blur_cover/index.tsx +0 -28
- package/src/blog/components/hotkey_nav/index.tsx +0 -51
- package/src/blog/components/progress_bar/index.tsx +0 -31
- package/src/blog/components/reaction/emojis.tsx +0 -143
- package/src/blog/components/reaction/oh_reaction.tsx +0 -105
- package/src/blog/components/reload_prompt/index.tsx +0 -51
- package/src/blog/components/tags/index.tsx +0 -52
- package/src/blog/hooks/useLoadingIndicator.ts +0 -12
- package/src/blog/hooks/useScrollToTop.ts +0 -24
- package/src/blog/hooks/useTransitionCls.ts +0 -36
- package/src/blog/hooks/use_authed.ts +0 -7
- package/src/blog/hooks/use_authed_fetcher.ts +0 -9
- package/src/blog/hooks/use_authed_string_post.ts +0 -42
- package/src/blog/hooks/use_clipboard_content.ts +0 -21
- package/src/blog/hooks/use_clipboard_to_post.ts +0 -48
- package/src/blog/hooks/use_del_img.ts +0 -22
- package/src/blog/hooks/use_delete_post.ts +0 -22
- package/src/blog/hooks/use_file_to_post.ts +0 -38
- package/src/blog/hooks/use_img_loading.ts +0 -16
- package/src/blog/hooks/use_post.ts +0 -26
- package/src/blog/hooks/use_projects.ts +0 -67
- package/src/blog/hooks/use_route_name.ts +0 -7
- package/src/blog/hooks/use_shared_string_to_post.ts +0 -23
- package/src/blog/hooks/use_supa_session.ts +0 -32
- package/src/blog/hooks/use_text_plain_file.ts +0 -36
- package/src/blog/hooks/use_uploader.ts +0 -34
- package/src/blog/hooks/use_video_controls.ts +0 -71
- package/src/blog/types/supabase.ts +0 -12
- package/src/blog/types/upload.ts +0 -16
- package/src/blog/utils/tags.ts +0 -21
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
import { toast } from "sonner";
|
|
3
|
-
|
|
4
|
-
// @ts-ignore
|
|
5
|
-
import { useRegisterSW } from "virtual:pwa-register/react";
|
|
6
|
-
|
|
7
|
-
export const ReloadPrompt = () => {
|
|
8
|
-
const {
|
|
9
|
-
needRefresh: [needRefresh, setNeedRefresh],
|
|
10
|
-
updateServiceWorker,
|
|
11
|
-
} = useRegisterSW({
|
|
12
|
-
onRegisterError(error: any) {
|
|
13
|
-
console.log("SW registration error", error);
|
|
14
|
-
},
|
|
15
|
-
onRegisteredSW(swScriptUrl: string, r: ServiceWorkerRegistration) {
|
|
16
|
-
console.log("SW registered: ", swScriptUrl, r);
|
|
17
|
-
},
|
|
18
|
-
onOfflineReady() {
|
|
19
|
-
console.log("App is offline-ready");
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
if (needRefresh) {
|
|
25
|
-
toast("", {
|
|
26
|
-
description: "发现新版本,是否更新?",
|
|
27
|
-
duration: 10000,
|
|
28
|
-
position: "bottom-right",
|
|
29
|
-
actionButtonStyle: {
|
|
30
|
-
backgroundColor: "#fff",
|
|
31
|
-
color: "rgb(37,99,235)",
|
|
32
|
-
},
|
|
33
|
-
action: {
|
|
34
|
-
label: "是",
|
|
35
|
-
onClick: () => {
|
|
36
|
-
updateServiceWorker(false).then(() => {
|
|
37
|
-
// @ts-ignore
|
|
38
|
-
toast("", {
|
|
39
|
-
description: `已更新`,
|
|
40
|
-
position: "bottom-right",
|
|
41
|
-
});
|
|
42
|
-
setNeedRefresh(false);
|
|
43
|
-
});
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
}, [needRefresh]);
|
|
49
|
-
|
|
50
|
-
return null;
|
|
51
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import classnames from "classnames";
|
|
3
|
-
import { List, Tag, Link, TitledList } from "@bbki.ng/components";
|
|
4
|
-
import { ROUTES } from "@/constants";
|
|
5
|
-
|
|
6
|
-
type MyTag =
|
|
7
|
-
| {
|
|
8
|
-
path: string;
|
|
9
|
-
name: string;
|
|
10
|
-
}
|
|
11
|
-
| string;
|
|
12
|
-
|
|
13
|
-
type Tags = {
|
|
14
|
-
tags: MyTag[];
|
|
15
|
-
className?: string;
|
|
16
|
-
inline?: boolean;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const Tags = (props: Tags) => {
|
|
20
|
-
const { inline, className, tags } = props;
|
|
21
|
-
|
|
22
|
-
const renderTag = (tag: MyTag) => {
|
|
23
|
-
const TagComp = inline ? Tag : Link;
|
|
24
|
-
if (typeof tag === "string") {
|
|
25
|
-
return <TagComp to={`${ROUTES.TAGS}/${tag}`}>{tag}</TagComp>;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return <TagComp to={tag.path}>{tag.name}</TagComp>;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
if (inline) {
|
|
32
|
-
return (
|
|
33
|
-
<>
|
|
34
|
-
<List
|
|
35
|
-
items={tags}
|
|
36
|
-
itemRenderer={renderTag}
|
|
37
|
-
horizontal={inline}
|
|
38
|
-
className={classnames(className, "inline-flex", "flex-wrap")}
|
|
39
|
-
/>
|
|
40
|
-
</>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
return (
|
|
44
|
-
<TitledList
|
|
45
|
-
title={"标签"}
|
|
46
|
-
items={tags}
|
|
47
|
-
itemRenderer={renderTag}
|
|
48
|
-
horizontal={inline}
|
|
49
|
-
className={className}
|
|
50
|
-
/>
|
|
51
|
-
);
|
|
52
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
|
|
2
|
-
import { useContext } from "react";
|
|
3
|
-
|
|
4
|
-
export const useLoadingIndicator = () => {
|
|
5
|
-
const globalCtx = useContext(GlobalLoadingContext);
|
|
6
|
-
|
|
7
|
-
return {
|
|
8
|
-
setVisibility: globalCtx.setIsLoading,
|
|
9
|
-
isVisible: globalCtx.isLoading,
|
|
10
|
-
isFontLoading: globalCtx.isFontLoading,
|
|
11
|
-
};
|
|
12
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { useLocation } from "react-router-dom";
|
|
2
|
-
import { useEffect } from "react";
|
|
3
|
-
|
|
4
|
-
export const useScrollToTop = (excludePath = "") => {
|
|
5
|
-
const { pathname } = useLocation();
|
|
6
|
-
|
|
7
|
-
const resetScroll = () => {
|
|
8
|
-
if (excludePath && pathname.includes(excludePath)) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
setTimeout(() => {
|
|
12
|
-
window.scrollTo(0, 0);
|
|
13
|
-
}, 0);
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
window.addEventListener("popstate", resetScroll);
|
|
18
|
-
return () => {
|
|
19
|
-
window.removeEventListener("popstate", resetScroll);
|
|
20
|
-
};
|
|
21
|
-
}, []);
|
|
22
|
-
|
|
23
|
-
useEffect(resetScroll, [pathname]);
|
|
24
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import React, { useEffect } from "react";
|
|
2
|
-
import classnames from "classnames";
|
|
3
|
-
|
|
4
|
-
interface TransOption {
|
|
5
|
-
originCls?: string;
|
|
6
|
-
opacity?: boolean;
|
|
7
|
-
offset?: boolean;
|
|
8
|
-
blur?: boolean;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const defaultOpt = {
|
|
12
|
-
originCls: "",
|
|
13
|
-
opacity: true,
|
|
14
|
-
offset: true,
|
|
15
|
-
blur: true,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const useTransitionCls = (options: TransOption = defaultOpt) => {
|
|
19
|
-
const [visible, setVisible] = React.useState(false);
|
|
20
|
-
const { originCls, opacity, offset, blur } = options;
|
|
21
|
-
|
|
22
|
-
const cls = classnames(originCls, "transition-all", "duration-500", {
|
|
23
|
-
"blur-xs": !visible && blur,
|
|
24
|
-
"blur-none": visible && blur,
|
|
25
|
-
"translate-y-0": visible && offset,
|
|
26
|
-
"translate-y-8": !visible && offset,
|
|
27
|
-
"opacity-10": !visible && opacity,
|
|
28
|
-
"opacity-100": visible && opacity,
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
setVisible(true);
|
|
33
|
-
}, []);
|
|
34
|
-
|
|
35
|
-
return cls;
|
|
36
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { useSupabaseSession } from '@/hooks/use_supa_session';
|
|
2
|
-
import { apiFetcher, withToken } from '@/utils';
|
|
3
|
-
import { useCallback, useMemo } from 'react';
|
|
4
|
-
|
|
5
|
-
export const useAuthedFetcher = () => {
|
|
6
|
-
const { access_token: token } = useSupabaseSession() || {};
|
|
7
|
-
const fetcherWithToken = useMemo(() => withToken(apiFetcher), []);
|
|
8
|
-
return useCallback(fetcherWithToken(token), [token, fetcherWithToken]);
|
|
9
|
-
};
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import {useSWRConfig} from "swr";
|
|
2
|
-
import {useAuthed} from "@/hooks/use_authed";
|
|
3
|
-
import {useContext} from "react";
|
|
4
|
-
import {GlobalLoadingContext} from "@/context/global_loading_state_provider";
|
|
5
|
-
import {usePost} from "@/hooks/use_post";
|
|
6
|
-
import {splitPost} from "@/utils";
|
|
7
|
-
import {API} from "@/constants/routes";
|
|
8
|
-
|
|
9
|
-
export const useAuthedStringPost = () => {
|
|
10
|
-
const { mutate } = useSWRConfig();
|
|
11
|
-
|
|
12
|
-
const isKing = useAuthed();
|
|
13
|
-
|
|
14
|
-
const { setIsLoading } = useContext(GlobalLoadingContext);
|
|
15
|
-
|
|
16
|
-
const post = usePost();
|
|
17
|
-
|
|
18
|
-
return (content: string) => {
|
|
19
|
-
if (!content) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (!isKing) {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const postObj = splitPost(content);
|
|
28
|
-
if (!postObj?.content || !postObj?.title) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
setIsLoading(true);
|
|
33
|
-
|
|
34
|
-
post(postObj.title, postObj.content)
|
|
35
|
-
.then((r) => {
|
|
36
|
-
mutate(API.POSTS).then();
|
|
37
|
-
})
|
|
38
|
-
.finally(() => {
|
|
39
|
-
setIsLoading(false);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
|
|
3
|
-
export const useClipboardContent = () => {
|
|
4
|
-
const [clipboardContent, setClipboardContent] = React.useState<string | null>(null);
|
|
5
|
-
|
|
6
|
-
React.useEffect(() => {
|
|
7
|
-
const handlePaste = (event: ClipboardEvent) => {
|
|
8
|
-
if (event.clipboardData) {
|
|
9
|
-
setClipboardContent(event.clipboardData.getData('text/plain'));
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
document.addEventListener('paste', handlePaste);
|
|
14
|
-
|
|
15
|
-
return () => {
|
|
16
|
-
document.removeEventListener('paste', handlePaste);
|
|
17
|
-
};
|
|
18
|
-
}, []);
|
|
19
|
-
|
|
20
|
-
return clipboardContent;
|
|
21
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import {useClipboardContent} from "@/hooks/use_clipboard_content";
|
|
2
|
-
import {useSWRConfig} from "swr";
|
|
3
|
-
import {useContext, useEffect} from "react";
|
|
4
|
-
import {GlobalLoadingContext} from "@/context/global_loading_state_provider";
|
|
5
|
-
import {usePost} from "@/hooks/use_post";
|
|
6
|
-
import {API} from "@/constants/routes";
|
|
7
|
-
import {useAuthed} from "@/hooks/use_authed";
|
|
8
|
-
import {toast} from "sonner";
|
|
9
|
-
|
|
10
|
-
export const useClipboardToPost = () => {
|
|
11
|
-
const clipboardContent = useClipboardContent();
|
|
12
|
-
|
|
13
|
-
const { mutate } = useSWRConfig();
|
|
14
|
-
|
|
15
|
-
const { setIsLoading } = useContext(GlobalLoadingContext);
|
|
16
|
-
|
|
17
|
-
const post = usePost();
|
|
18
|
-
|
|
19
|
-
const firstLine = clipboardContent ? clipboardContent.split("\n")[0] : "";
|
|
20
|
-
const title = firstLine ? firstLine.trim() : "";
|
|
21
|
-
|
|
22
|
-
const restContent = clipboardContent ? clipboardContent.slice(title.length).trim() : "";
|
|
23
|
-
|
|
24
|
-
const isKing = useAuthed();
|
|
25
|
-
|
|
26
|
-
useEffect(() => {
|
|
27
|
-
if (!isKing || !restContent || !title) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
setIsLoading(true);
|
|
32
|
-
|
|
33
|
-
post(title, restContent)
|
|
34
|
-
.then((r) => {
|
|
35
|
-
mutate(API.POSTS).then(() => {
|
|
36
|
-
toast("", {
|
|
37
|
-
description: `已更新`,
|
|
38
|
-
position: "bottom-right",
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
})
|
|
42
|
-
.finally(() => {
|
|
43
|
-
setIsLoading(false);
|
|
44
|
-
});
|
|
45
|
-
}, [title, restContent]);
|
|
46
|
-
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { useAuthedFetcher } from "@/hooks/use_authed_fetcher";
|
|
2
|
-
import { useCallback } from "react";
|
|
3
|
-
import { API } from "@/constants/routes";
|
|
4
|
-
|
|
5
|
-
export const useDelImg = () => {
|
|
6
|
-
const authedFetcher = useAuthedFetcher();
|
|
7
|
-
|
|
8
|
-
const req = useCallback(
|
|
9
|
-
async (url: string, { arg }: { arg: { id: number } }) => {
|
|
10
|
-
return authedFetcher(url, {
|
|
11
|
-
method: "POST",
|
|
12
|
-
body: JSON.stringify(arg),
|
|
13
|
-
});
|
|
14
|
-
},
|
|
15
|
-
[authedFetcher]
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
return useCallback(
|
|
19
|
-
(id: number) => req(API.REMOVE_IMG, { arg: { id } }),
|
|
20
|
-
[req]
|
|
21
|
-
);
|
|
22
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { useAuthedFetcher } from "@/hooks/use_authed_fetcher";
|
|
2
|
-
import { useCallback } from "react";
|
|
3
|
-
import { API } from "@/constants/routes";
|
|
4
|
-
|
|
5
|
-
export const useDelPost = () => {
|
|
6
|
-
const authedFetcher = useAuthedFetcher();
|
|
7
|
-
|
|
8
|
-
const req = useCallback(
|
|
9
|
-
async (url: string, { arg }: { arg: { title: string } }) => {
|
|
10
|
-
return authedFetcher(url, {
|
|
11
|
-
method: "POST",
|
|
12
|
-
body: JSON.stringify(arg),
|
|
13
|
-
});
|
|
14
|
-
},
|
|
15
|
-
[authedFetcher]
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
return useCallback(
|
|
19
|
-
(title: string) => req(API.REMOVE_POST, { arg: { title } }),
|
|
20
|
-
[req]
|
|
21
|
-
);
|
|
22
|
-
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { useTextPlainFile } from "@/hooks/use_text_plain_file";
|
|
2
|
-
import { useContext, useEffect } from "react";
|
|
3
|
-
import { usePost } from "@/hooks/use_post";
|
|
4
|
-
import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
|
|
5
|
-
import { useAuthedFetcher } from "@/hooks/use_authed_fetcher";
|
|
6
|
-
import { preload, useSWRConfig } from "swr";
|
|
7
|
-
import { API } from "@/constants/routes";
|
|
8
|
-
|
|
9
|
-
export type fileReader = (f: File) => void;
|
|
10
|
-
export const useFile2Post = (): fileReader => {
|
|
11
|
-
const { content, title, reader } = useTextPlainFile();
|
|
12
|
-
|
|
13
|
-
const { mutate } = useSWRConfig();
|
|
14
|
-
|
|
15
|
-
const { setIsLoading } = useContext(GlobalLoadingContext);
|
|
16
|
-
|
|
17
|
-
const post = usePost();
|
|
18
|
-
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
if (!content || !title) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
setIsLoading(true);
|
|
25
|
-
|
|
26
|
-
post(title, content)
|
|
27
|
-
.then((r) => {
|
|
28
|
-
mutate(API.POSTS).then();
|
|
29
|
-
})
|
|
30
|
-
.finally(() => {
|
|
31
|
-
setIsLoading(false);
|
|
32
|
-
});
|
|
33
|
-
}, [title, content]);
|
|
34
|
-
|
|
35
|
-
return (f: File) => {
|
|
36
|
-
reader(f);
|
|
37
|
-
};
|
|
38
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
|
|
3
|
-
export const useImgLoading = (src: string) => {
|
|
4
|
-
const [loading, setLoading] = useState(true);
|
|
5
|
-
useEffect(() => {
|
|
6
|
-
let img = new Image();
|
|
7
|
-
img.src = src;
|
|
8
|
-
img.onload = () => {
|
|
9
|
-
setLoading(false);
|
|
10
|
-
};
|
|
11
|
-
return () => {
|
|
12
|
-
img.src = "";
|
|
13
|
-
};
|
|
14
|
-
}, []);
|
|
15
|
-
return loading;
|
|
16
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { useCallback } from "react";
|
|
2
|
-
import { API } from "@/constants/routes";
|
|
3
|
-
import { useAuthedFetcher } from "@/hooks/use_authed_fetcher";
|
|
4
|
-
|
|
5
|
-
export const usePost = () => {
|
|
6
|
-
const authedFetcher = useAuthedFetcher();
|
|
7
|
-
|
|
8
|
-
const req = useCallback(
|
|
9
|
-
async (
|
|
10
|
-
url: string,
|
|
11
|
-
{ arg }: { arg: { title: string; content: string } }
|
|
12
|
-
) => {
|
|
13
|
-
return authedFetcher(url, {
|
|
14
|
-
method: "POST",
|
|
15
|
-
body: JSON.stringify(arg),
|
|
16
|
-
});
|
|
17
|
-
},
|
|
18
|
-
[authedFetcher]
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
return useCallback(
|
|
22
|
-
(title: string, content: string) =>
|
|
23
|
-
req(API.POST, { arg: { title, content } }),
|
|
24
|
-
[req]
|
|
25
|
-
);
|
|
26
|
-
};
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import useSWR, { useSWRConfig } from "swr";
|
|
2
|
-
import { API } from "@/constants/routes";
|
|
3
|
-
import { useCallback, useContext, useEffect } from "react";
|
|
4
|
-
import { Photo } from "@/types/photo";
|
|
5
|
-
import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
|
|
6
|
-
|
|
7
|
-
export const useProjects = (name: string = "", suspense?: boolean) => {
|
|
8
|
-
const URL = `${API.PROJECTS}${name ? "/" : ""}${name}`;
|
|
9
|
-
|
|
10
|
-
const { data, error } = useSWR(URL, {
|
|
11
|
-
revalidateOnFocus: false,
|
|
12
|
-
suspense,
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
let isLoading = !data && !error;
|
|
16
|
-
|
|
17
|
-
const { setIsLoading } = useContext(GlobalLoadingContext);
|
|
18
|
-
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
setIsLoading(isLoading);
|
|
21
|
-
}, [isLoading]);
|
|
22
|
-
|
|
23
|
-
const { mutate, cache } = useSWRConfig();
|
|
24
|
-
|
|
25
|
-
const getCachedProjects = (n: string) => {
|
|
26
|
-
if (!n) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
return cache
|
|
30
|
-
.get("projects")
|
|
31
|
-
?.data.find((p: { name: string }) => p.name === n);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const refresh = useCallback(() => {
|
|
35
|
-
return mutate(URL);
|
|
36
|
-
}, [URL]);
|
|
37
|
-
|
|
38
|
-
const addLocalPhotoImmediately = useCallback(
|
|
39
|
-
(photo: Photo) => {
|
|
40
|
-
if (!name) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!data || error) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return mutate(
|
|
49
|
-
URL,
|
|
50
|
-
{
|
|
51
|
-
...data,
|
|
52
|
-
images: [photo, ...data.images],
|
|
53
|
-
},
|
|
54
|
-
false
|
|
55
|
-
);
|
|
56
|
-
},
|
|
57
|
-
[data, error]
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
refresh,
|
|
62
|
-
addLocalPhotoImmediately,
|
|
63
|
-
projects: data || getCachedProjects(name),
|
|
64
|
-
isError: error,
|
|
65
|
-
isLoading: !data && !error,
|
|
66
|
-
};
|
|
67
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
import { useAuthedStringPost } from '@/hooks/use_authed_string_post';
|
|
3
|
-
|
|
4
|
-
export const useSharedStringToPost = () => {
|
|
5
|
-
const post = useAuthedStringPost();
|
|
6
|
-
|
|
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);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
window.addEventListener('message', handleSharedString);
|
|
18
|
-
|
|
19
|
-
return () => {
|
|
20
|
-
window.removeEventListener('message', handleSharedString);
|
|
21
|
-
};
|
|
22
|
-
}, [post]);
|
|
23
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
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
|
-
|
|
6
|
-
export const useSupabaseSession = (): BBKingSession | null => {
|
|
7
|
-
const supabase = useMemo(() => createClient(SUPABASE.URL, SUPABASE.ANNO), []);
|
|
8
|
-
|
|
9
|
-
const extendSess = (sess: Session | null) => {
|
|
10
|
-
if (!sess) {
|
|
11
|
-
return sess;
|
|
12
|
-
}
|
|
13
|
-
return {
|
|
14
|
-
...sess,
|
|
15
|
-
isKing: sess.user?.id === SUPABASE.BB_KING_ID,
|
|
16
|
-
isQueen: sess.user?.id === SUPABASE.BB_QUEEN_ID,
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const [session, setSession] = useState(extendSess(supabase.auth.session()));
|
|
21
|
-
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
const { data: subscription } = supabase.auth.onAuthStateChange((event, session) => {
|
|
24
|
-
if (event === 'SIGNED_IN') {
|
|
25
|
-
setSession(extendSess(session));
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
return () => subscription?.unsubscribe();
|
|
29
|
-
}, [supabase]);
|
|
30
|
-
|
|
31
|
-
return session;
|
|
32
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
|
|
3
|
-
export type Result = {
|
|
4
|
-
content: string;
|
|
5
|
-
title: string;
|
|
6
|
-
reader: (f: File) => void;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const useTextPlainFile = (): Result => {
|
|
10
|
-
const [content, setContent] = useState("");
|
|
11
|
-
const [file, setFile] = useState<File | null>(null);
|
|
12
|
-
|
|
13
|
-
const reader = new FileReader();
|
|
14
|
-
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
if (file != null) {
|
|
17
|
-
reader.readAsText(file, "utf-8");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
reader.onload = function () {
|
|
21
|
-
setContent(reader.result as string);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
return () => {
|
|
25
|
-
reader.onload = null;
|
|
26
|
-
};
|
|
27
|
-
}, [file]);
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
content,
|
|
31
|
-
title: file?.name ?? "",
|
|
32
|
-
reader: (f: File) => {
|
|
33
|
-
setFile(f);
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { useCallback } from "react";
|
|
2
|
-
import { useSupabaseSession } from "@/hooks/use_supa_session";
|
|
3
|
-
import { apiFetcher, getImageFileSize, withToken } from "@/utils";
|
|
4
|
-
import { Photo } from "@/types/photo";
|
|
5
|
-
import { API } from "@/constants/routes";
|
|
6
|
-
import { UploadResult } from "@/types/oss";
|
|
7
|
-
|
|
8
|
-
export const useUploader = () => {
|
|
9
|
-
const { access_token: token } = useSupabaseSession() || {};
|
|
10
|
-
const authedApiFetcher = withToken(apiFetcher)(token);
|
|
11
|
-
|
|
12
|
-
return useCallback(
|
|
13
|
-
async (pid: string, projectName: string, file: File): Promise<Photo> => {
|
|
14
|
-
const { width, height } = await getImageFileSize(file);
|
|
15
|
-
|
|
16
|
-
const url = `${API.UPLOAD_IMG}?pid=${pid}&fileName=${file.name}&projectName=${projectName}&width=${width}&height=${height}`;
|
|
17
|
-
|
|
18
|
-
const result = (await authedApiFetcher(url, {
|
|
19
|
-
method: "POST",
|
|
20
|
-
headers: {
|
|
21
|
-
"Content-Type": "application/octet-stream",
|
|
22
|
-
},
|
|
23
|
-
body: file,
|
|
24
|
-
})) as UploadResult;
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
width,
|
|
28
|
-
height,
|
|
29
|
-
src: result.url,
|
|
30
|
-
};
|
|
31
|
-
},
|
|
32
|
-
[token]
|
|
33
|
-
);
|
|
34
|
-
};
|