@bbki.ng/site 1.2.23 → 1.4.0
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 +4 -0
- package/dev-dist/sw.js +1 -1
- package/package.json +3 -3
- package/src/app.tsx +8 -1
- package/src/components/app_ctx_menu/LoginMenuItem.tsx +31 -0
- package/src/components/app_ctx_menu/VersionMenuItem.tsx +13 -0
- package/src/components/app_ctx_menu/ViewSourceMenuItem.tsx +28 -0
- package/src/components/app_ctx_menu/index.tsx +26 -0
- package/src/components/article_ctx_menu/index.tsx +50 -0
- package/src/constants/routes.ts +1 -0
- package/src/demo/DemoMenu.tsx +66 -0
- package/src/hooks/use_delete_post.ts +22 -0
- package/src/main.tsx +1 -0
- package/src/pages/cover/index.tsx +1 -0
- package/src/pages/extensions/txt/article.tsx +4 -1
- package/src/pages/login/index.tsx +29 -14
- package/src/types/supabase.ts +1 -0
- package/src/utils/index.ts +17 -0
package/CHANGELOG.md
CHANGED
package/dev-dist/sw.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bbki.ng/site",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "code behind bbki.ng",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"url": "git+https://github.com/bbbottle/bbki.ng.git"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@bbki.ng/components": "workspace:2.
|
|
19
|
+
"@bbki.ng/components": "workspace:2.4.0",
|
|
20
20
|
"@supabase/supabase-js": "^1.30.6",
|
|
21
21
|
"classnames": "2.3.1",
|
|
22
22
|
"react": "^18.0.0",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"swr": "^2.2.5"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@bbki.ng/stylebase": "workspace:0.
|
|
31
|
+
"@bbki.ng/stylebase": "workspace:0.3.0",
|
|
32
32
|
"@mdx-js/mdx": "2.0.0-next.9",
|
|
33
33
|
"@mdx-js/react": "^1.6.22",
|
|
34
34
|
"@mdx-js/rollup": "3.0.0",
|
package/src/app.tsx
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
GlobalLoadingStateProvider,
|
|
22
22
|
} from "@/global_loading_state_provider";
|
|
23
23
|
import { UploadPage } from "@/pages/upload";
|
|
24
|
+
import { AppCtxMenu } from "@/components/app_ctx_menu";
|
|
24
25
|
|
|
25
26
|
const Layout = () => {
|
|
26
27
|
const { isLoading } = useContext(GlobalLoadingContext);
|
|
@@ -28,7 +29,13 @@ const Layout = () => {
|
|
|
28
29
|
<>
|
|
29
30
|
<Page
|
|
30
31
|
nav={
|
|
31
|
-
<
|
|
32
|
+
<AppCtxMenu>
|
|
33
|
+
<Nav
|
|
34
|
+
paths={usePaths()}
|
|
35
|
+
className="blur-cover select-none"
|
|
36
|
+
loading={isLoading}
|
|
37
|
+
/>
|
|
38
|
+
</AppCtxMenu>
|
|
32
39
|
}
|
|
33
40
|
main={<Outlet />}
|
|
34
41
|
/>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useAuthed } from "@/hooks/use_authed";
|
|
2
|
+
import { useSupabaseSession } from "@/hooks/use_supa_session";
|
|
3
|
+
import {
|
|
4
|
+
ContextMenuItem,
|
|
5
|
+
ContextMenuLabel,
|
|
6
|
+
ContextMenuShortcut,
|
|
7
|
+
Link,
|
|
8
|
+
} from "@bbki.ng/components";
|
|
9
|
+
import React from "react";
|
|
10
|
+
import { useNavigate } from "react-router-dom";
|
|
11
|
+
|
|
12
|
+
export const LoginMenuItem = () => {
|
|
13
|
+
const sess = useSupabaseSession();
|
|
14
|
+
const nav = useNavigate();
|
|
15
|
+
|
|
16
|
+
if (sess?.user != null) {
|
|
17
|
+
return <ContextMenuLabel inset>{sess?.user?.email ?? ""}</ContextMenuLabel>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<ContextMenuItem
|
|
22
|
+
onClick={() => {
|
|
23
|
+
nav("/login");
|
|
24
|
+
}}
|
|
25
|
+
inset
|
|
26
|
+
>
|
|
27
|
+
login
|
|
28
|
+
<ContextMenuShortcut>l</ContextMenuShortcut>
|
|
29
|
+
</ContextMenuItem>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ContextMenuItem, Tag } from "@bbki.ng/components";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
export const VersionMenuItem = () => {
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
const appVer = GLOBAL_BBKING_VERSION;
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<ContextMenuItem inset disabled>
|
|
10
|
+
v{appVer}
|
|
11
|
+
</ContextMenuItem>
|
|
12
|
+
);
|
|
13
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ContextMenuItem, ContextMenuShortcut } from "@bbki.ng/components";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { GITHUB_REPO_ADDRESS } from "@/constants";
|
|
4
|
+
|
|
5
|
+
export const ViewSourceMenuItem = () => {
|
|
6
|
+
return (
|
|
7
|
+
<ContextMenuItem
|
|
8
|
+
onClick={() => {
|
|
9
|
+
// open tagUrl in new tab
|
|
10
|
+
window.open(GITHUB_REPO_ADDRESS, "_blank");
|
|
11
|
+
}}
|
|
12
|
+
>
|
|
13
|
+
<svg
|
|
14
|
+
height="16"
|
|
15
|
+
aria-hidden="true"
|
|
16
|
+
viewBox="0 0 16 16"
|
|
17
|
+
version="1.1"
|
|
18
|
+
width="16"
|
|
19
|
+
data-view-component="true"
|
|
20
|
+
className="mr-8"
|
|
21
|
+
>
|
|
22
|
+
<path d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"></path>
|
|
23
|
+
</svg>
|
|
24
|
+
view source
|
|
25
|
+
<ContextMenuShortcut>s</ContextMenuShortcut>
|
|
26
|
+
</ContextMenuItem>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React, { ReactElement } from "react";
|
|
2
|
+
import {
|
|
3
|
+
ContextMenu,
|
|
4
|
+
ContextMenuContent,
|
|
5
|
+
ContextMenuTrigger,
|
|
6
|
+
ContextMenuSeparator,
|
|
7
|
+
ContextMenuShortcut,
|
|
8
|
+
ContextMenuItem,
|
|
9
|
+
} from "@bbki.ng/components";
|
|
10
|
+
import { LoginMenuItem } from "@/components/app_ctx_menu/LoginMenuItem";
|
|
11
|
+
import { VersionMenuItem } from "@/components/app_ctx_menu/VersionMenuItem";
|
|
12
|
+
import { ViewSourceMenuItem } from "@/components/app_ctx_menu/ViewSourceMenuItem";
|
|
13
|
+
|
|
14
|
+
export const AppCtxMenu = (props: { children: ReactElement }) => {
|
|
15
|
+
return (
|
|
16
|
+
<ContextMenu>
|
|
17
|
+
<ContextMenuTrigger>{props.children}</ContextMenuTrigger>
|
|
18
|
+
<ContextMenuContent className="w-256">
|
|
19
|
+
<LoginMenuItem />
|
|
20
|
+
<ContextMenuSeparator />
|
|
21
|
+
<VersionMenuItem />
|
|
22
|
+
<ViewSourceMenuItem />
|
|
23
|
+
</ContextMenuContent>
|
|
24
|
+
</ContextMenu>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React, { ReactElement, useCallback } from "react";
|
|
2
|
+
import { useAuthed } from "@/hooks/use_authed";
|
|
3
|
+
import {
|
|
4
|
+
ContextMenu,
|
|
5
|
+
ContextMenuContent,
|
|
6
|
+
ContextMenuTrigger,
|
|
7
|
+
ContextMenuItem,
|
|
8
|
+
} from "@bbki.ng/components";
|
|
9
|
+
import { useNavigate, useParams } from "react-router-dom";
|
|
10
|
+
import { useDelPost } from "@/hooks/use_delete_post";
|
|
11
|
+
import { toast } from "sonner";
|
|
12
|
+
import { confirm } from "@/utils";
|
|
13
|
+
|
|
14
|
+
export const ArticleCtxMenu = (props: { children: ReactElement }) => {
|
|
15
|
+
const auth = useAuthed();
|
|
16
|
+
const del = useDelPost();
|
|
17
|
+
const routeParams = useParams();
|
|
18
|
+
const nav = useNavigate();
|
|
19
|
+
const title = routeParams.title;
|
|
20
|
+
|
|
21
|
+
if (!auth) {
|
|
22
|
+
return props.children;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (title == null || title === "") {
|
|
26
|
+
return props.children;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const doDel = useCallback(() => {
|
|
30
|
+
del(title).then(() => {
|
|
31
|
+
toast.success("删除成功");
|
|
32
|
+
nav("/");
|
|
33
|
+
});
|
|
34
|
+
}, [title]);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<ContextMenu>
|
|
38
|
+
<ContextMenuTrigger>{props.children}</ContextMenuTrigger>
|
|
39
|
+
<ContextMenuContent className="w-128">
|
|
40
|
+
<ContextMenuItem
|
|
41
|
+
onClick={() => {
|
|
42
|
+
confirm("确认删除?", doDel);
|
|
43
|
+
}}
|
|
44
|
+
>
|
|
45
|
+
remove
|
|
46
|
+
</ContextMenuItem>
|
|
47
|
+
</ContextMenuContent>
|
|
48
|
+
</ContextMenu>
|
|
49
|
+
);
|
|
50
|
+
};
|
package/src/constants/routes.ts
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
ContextMenu,
|
|
4
|
+
ContextMenuCheckboxItem,
|
|
5
|
+
ContextMenuContent,
|
|
6
|
+
ContextMenuItem,
|
|
7
|
+
ContextMenuLabel,
|
|
8
|
+
ContextMenuRadioGroup,
|
|
9
|
+
ContextMenuRadioItem,
|
|
10
|
+
ContextMenuSeparator,
|
|
11
|
+
ContextMenuShortcut,
|
|
12
|
+
ContextMenuSub,
|
|
13
|
+
ContextMenuSubContent,
|
|
14
|
+
ContextMenuSubTrigger,
|
|
15
|
+
ContextMenuTrigger,
|
|
16
|
+
} from "@bbki.ng/components";
|
|
17
|
+
|
|
18
|
+
export function ContextMenuDemo() {
|
|
19
|
+
return (
|
|
20
|
+
<ContextMenu>
|
|
21
|
+
<ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
22
|
+
<ContextMenuContent className="w-256">
|
|
23
|
+
<ContextMenuItem inset>
|
|
24
|
+
Back
|
|
25
|
+
<ContextMenuShortcut>⌘[</ContextMenuShortcut>
|
|
26
|
+
</ContextMenuItem>
|
|
27
|
+
<ContextMenuItem inset disabled>
|
|
28
|
+
Forward
|
|
29
|
+
<ContextMenuShortcut>⌘]</ContextMenuShortcut>
|
|
30
|
+
</ContextMenuItem>
|
|
31
|
+
<ContextMenuItem inset>
|
|
32
|
+
Reload
|
|
33
|
+
<ContextMenuShortcut>⌘R</ContextMenuShortcut>
|
|
34
|
+
</ContextMenuItem>
|
|
35
|
+
<ContextMenuSub>
|
|
36
|
+
<ContextMenuSubTrigger inset>More Tools</ContextMenuSubTrigger>
|
|
37
|
+
<ContextMenuSubContent className="w-48">
|
|
38
|
+
<ContextMenuItem>
|
|
39
|
+
Save Page As...
|
|
40
|
+
<ContextMenuShortcut>⇧⌘S</ContextMenuShortcut>
|
|
41
|
+
</ContextMenuItem>
|
|
42
|
+
<ContextMenuItem>Create Shortcut...</ContextMenuItem>
|
|
43
|
+
<ContextMenuItem>Name Window...</ContextMenuItem>
|
|
44
|
+
<ContextMenuSeparator />
|
|
45
|
+
<ContextMenuItem>Developer Tools</ContextMenuItem>
|
|
46
|
+
</ContextMenuSubContent>
|
|
47
|
+
</ContextMenuSub>
|
|
48
|
+
<ContextMenuSeparator />
|
|
49
|
+
<ContextMenuCheckboxItem checked>
|
|
50
|
+
Show Bookmarks Bar
|
|
51
|
+
<ContextMenuShortcut>⌘⇧B</ContextMenuShortcut>
|
|
52
|
+
</ContextMenuCheckboxItem>
|
|
53
|
+
<ContextMenuCheckboxItem>Show Full URLs</ContextMenuCheckboxItem>
|
|
54
|
+
<ContextMenuSeparator />
|
|
55
|
+
<ContextMenuRadioGroup value="pedro">
|
|
56
|
+
<ContextMenuLabel inset>People</ContextMenuLabel>
|
|
57
|
+
<ContextMenuSeparator />
|
|
58
|
+
<ContextMenuRadioItem value="pedro">
|
|
59
|
+
Pedro Duarte
|
|
60
|
+
</ContextMenuRadioItem>
|
|
61
|
+
<ContextMenuRadioItem value="colm">Colm Tuite</ContextMenuRadioItem>
|
|
62
|
+
</ContextMenuRadioGroup>
|
|
63
|
+
</ContextMenuContent>
|
|
64
|
+
</ContextMenu>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
};
|
package/src/main.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import "@bbki.ng/components/style";
|
|
|
7
7
|
import App from "./app";
|
|
8
8
|
import "./main.css";
|
|
9
9
|
import Logger from "@/components/Logger";
|
|
10
|
+
import { AppCtxMenu } from "@/components/app_ctx_menu";
|
|
10
11
|
|
|
11
12
|
const container = document.getElementById("root") as Element;
|
|
12
13
|
const root = createRoot(container);
|
|
@@ -9,6 +9,7 @@ import { ArticlePage } from "@/components/article";
|
|
|
9
9
|
import { GlobalLoadingContext } from "@/global_loading_state_provider";
|
|
10
10
|
import { useFile2Post } from "@/hooks/use_file_to_post";
|
|
11
11
|
import { useAuthed } from "@/hooks/use_authed";
|
|
12
|
+
import { ArticleCtxMenu } from "@/components/article_ctx_menu";
|
|
12
13
|
|
|
13
14
|
type TArticleMap = {
|
|
14
15
|
[key: string]: ReactElement;
|
|
@@ -55,7 +56,9 @@ export default () => {
|
|
|
55
56
|
return (
|
|
56
57
|
<DropZone onDrop={reader} disabled={!isKing}>
|
|
57
58
|
<ArticlePage title={title}>
|
|
58
|
-
<
|
|
59
|
+
<ArticleCtxMenu>
|
|
60
|
+
<div dangerouslySetInnerHTML={{ __html: posts.content }} />
|
|
61
|
+
</ArticleCtxMenu>
|
|
59
62
|
</ArticlePage>
|
|
60
63
|
</DropZone>
|
|
61
64
|
);
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
1
|
+
import React, { useContext, useState } from "react";
|
|
2
2
|
import { Button, ButtonType } from "@bbki.ng/components";
|
|
3
3
|
import { OauthProvider } from "@/types/supabase";
|
|
4
4
|
import { supabase } from "@/constants";
|
|
5
5
|
import { ArticlePage } from "@/components/article";
|
|
6
6
|
import { useSupabaseSession } from "@/hooks/use_supa_session";
|
|
7
7
|
import { Navigate } from "react-router-dom";
|
|
8
|
+
import { GlobalLoadingContext } from "@/global_loading_state_provider";
|
|
8
9
|
|
|
9
10
|
export const Login = () => {
|
|
10
|
-
const
|
|
11
|
+
const { isLoading, setIsLoading } = useContext(GlobalLoadingContext);
|
|
11
12
|
|
|
12
13
|
const session = useSupabaseSession();
|
|
13
14
|
if (session) {
|
|
@@ -16,18 +17,32 @@ export const Login = () => {
|
|
|
16
17
|
|
|
17
18
|
return (
|
|
18
19
|
<ArticlePage title="第三方账号登录">
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
<>
|
|
21
|
+
<Button
|
|
22
|
+
type={isLoading ? ButtonType.DISABLED : ButtonType.PRIMARY}
|
|
23
|
+
className="ml-8"
|
|
24
|
+
onClick={async () => {
|
|
25
|
+
setIsLoading(true);
|
|
26
|
+
return supabase.auth.signIn({
|
|
27
|
+
provider: OauthProvider.GITHUB,
|
|
28
|
+
});
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
31
|
+
GitHub
|
|
32
|
+
</Button>
|
|
33
|
+
<Button
|
|
34
|
+
type={isLoading ? ButtonType.DISABLED : ButtonType.PRIMARY}
|
|
35
|
+
className="ml-8"
|
|
36
|
+
onClick={async () => {
|
|
37
|
+
setIsLoading(true);
|
|
38
|
+
return supabase.auth.signIn({
|
|
39
|
+
provider: OauthProvider.Spotify,
|
|
40
|
+
});
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
Spotify
|
|
44
|
+
</Button>
|
|
45
|
+
</>
|
|
31
46
|
</ArticlePage>
|
|
32
47
|
);
|
|
33
48
|
};
|
package/src/types/supabase.ts
CHANGED
package/src/utils/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { ossProcessType } from "@/types/oss";
|
|
|
3
3
|
import { API_ENDPOINT, OSS_ADDRESS } from "@/constants/routes";
|
|
4
4
|
import { DEFAULT_DELAY } from "@/constants";
|
|
5
5
|
import useSWR from "swr";
|
|
6
|
+
import { toast } from "sonner";
|
|
6
7
|
|
|
7
8
|
type Fetcher = (resource: string, init?: any) => Promise<any>;
|
|
8
9
|
|
|
@@ -153,3 +154,19 @@ export const getRandomInt = (min: number, max: number) => {
|
|
|
153
154
|
export const copyToClipboard = async (value: string) => {
|
|
154
155
|
await navigator.clipboard.writeText(value);
|
|
155
156
|
};
|
|
157
|
+
|
|
158
|
+
export const confirm = (message: string, exec: () => void) => {
|
|
159
|
+
toast("", {
|
|
160
|
+
description: message,
|
|
161
|
+
actionButtonStyle: {
|
|
162
|
+
backgroundColor: "#fff",
|
|
163
|
+
color: "rgb(37,99,235)",
|
|
164
|
+
},
|
|
165
|
+
action: {
|
|
166
|
+
label: "是",
|
|
167
|
+
onClick: () => {
|
|
168
|
+
exec();
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
};
|