@bbki.ng/site 5.4.21 → 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 +22 -0
- package/index.html +12 -19
- package/package.json +5 -8
- package/src/blog/app.tsx +32 -44
- package/src/blog/components/article/index.tsx +8 -17
- package/src/blog/components/index.tsx +0 -12
- 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 +16 -16
- 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 +3 -20
- 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/aspect_ratio_box/index.tsx +0 -29
- 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/components/video_player/index.tsx +0 -82
- package/src/blog/global/mdx.d.ts +0 -9
- 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 -8
- 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 -31
- 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/pages/upload/index.tsx +0 -39
- 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,105 +0,0 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
ReactNode,
|
|
3
|
-
useContext,
|
|
4
|
-
useEffect,
|
|
5
|
-
useRef,
|
|
6
|
-
useState,
|
|
7
|
-
} from "react";
|
|
8
|
-
import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
|
|
9
|
-
import { BlinkDot, Button, ButtonType } from "@bbki.ng/components";
|
|
10
|
-
import { faces, hearts, ReactionEmojiPair, sadFaces } from "./emojis";
|
|
11
|
-
import { ShareBtn } from "../share/share-btn";
|
|
12
|
-
|
|
13
|
-
declare global {
|
|
14
|
-
namespace JSX {
|
|
15
|
-
interface IntrinsicElements {
|
|
16
|
-
"open-heart": React.DetailedHTMLProps<
|
|
17
|
-
React.HTMLAttributes<HTMLElement> & {
|
|
18
|
-
href?: string;
|
|
19
|
-
emoji?: string;
|
|
20
|
-
ariaDisabled?: boolean;
|
|
21
|
-
onClick?: React.MouseEventHandler<HTMLElement>;
|
|
22
|
-
},
|
|
23
|
-
HTMLElement
|
|
24
|
-
>;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const useHeartSent = (val: string) => {
|
|
30
|
-
const [sent, setSent] = useState(false);
|
|
31
|
-
const { setIsLoading } = useContext(GlobalLoadingContext);
|
|
32
|
-
|
|
33
|
-
const handleSent = (evt: Event) => {
|
|
34
|
-
const targetVal = (evt.target as HTMLElement).getAttribute("emoji");
|
|
35
|
-
|
|
36
|
-
if (targetVal == val) setSent(true);
|
|
37
|
-
setIsLoading(false);
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
addEventListener("open-heart", handleSent);
|
|
42
|
-
|
|
43
|
-
return () => {
|
|
44
|
-
removeEventListener("open-heart", handleSent);
|
|
45
|
-
};
|
|
46
|
-
}, []);
|
|
47
|
-
|
|
48
|
-
return sent;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export const OpenHeartReaction = (props: {
|
|
52
|
-
title: string;
|
|
53
|
-
emojiPair: ReactionEmojiPair;
|
|
54
|
-
}) => {
|
|
55
|
-
const { title, emojiPair = hearts } = props;
|
|
56
|
-
const sent = useHeartSent(emojiPair.val);
|
|
57
|
-
|
|
58
|
-
const { setIsLoading } = useContext(GlobalLoadingContext);
|
|
59
|
-
|
|
60
|
-
const ohRef = useRef<HTMLElement>(null);
|
|
61
|
-
|
|
62
|
-
const pressed = () => ohRef.current?.getAttribute("aria-pressed");
|
|
63
|
-
|
|
64
|
-
const handleHeartClick = () => {
|
|
65
|
-
if (sent || pressed()) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
setIsLoading(true);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<open-heart
|
|
74
|
-
ref={ohRef}
|
|
75
|
-
href={`https://oh.bbki.ng/?id=${title}`}
|
|
76
|
-
emoji={emojiPair.val}
|
|
77
|
-
>
|
|
78
|
-
<Button
|
|
79
|
-
size="small"
|
|
80
|
-
type={ButtonType.GHOST}
|
|
81
|
-
className="text-gray-400 hover:text-gray-600 transition-colors ease-in duration-200"
|
|
82
|
-
onClick={handleHeartClick}
|
|
83
|
-
>
|
|
84
|
-
{sent || pressed() ? emojiPair.on : emojiPair.off}
|
|
85
|
-
</Button>
|
|
86
|
-
</open-heart>
|
|
87
|
-
);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export const Reaction = (props: { title: string; url: string }) => {
|
|
91
|
-
return (
|
|
92
|
-
<div className="flex items-center">
|
|
93
|
-
<OpenHeartReaction title={props.title} emojiPair={hearts} />
|
|
94
|
-
<OpenHeartReaction title={props.title} emojiPair={faces} />
|
|
95
|
-
<OpenHeartReaction title={props.title} emojiPair={sadFaces} />
|
|
96
|
-
|
|
97
|
-
<ShareBtn
|
|
98
|
-
shareInfo={{
|
|
99
|
-
title: props.title,
|
|
100
|
-
url: props.url,
|
|
101
|
-
}}
|
|
102
|
-
/>
|
|
103
|
-
</div>
|
|
104
|
-
);
|
|
105
|
-
};
|
|
@@ -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,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,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,8 +0,0 @@
|
|
|
1
|
-
import { useSupabaseSession } from "@/hooks/use_supa_session";
|
|
2
|
-
import { apiFetcher, withToken } from "@/utils";
|
|
3
|
-
import { useCallback } from "react";
|
|
4
|
-
|
|
5
|
-
export const useAuthedFetcher = () => {
|
|
6
|
-
const { access_token: token } = useSupabaseSession() || {};
|
|
7
|
-
return useCallback(withToken(apiFetcher)(token), [token]);
|
|
8
|
-
};
|
|
@@ -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
|
-
};
|