@bbki.ng/site 1.7.15 → 1.8.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/index.html +2 -2
- package/package.json +7 -4
- package/public/now.wasm +0 -0
- package/src/{app.tsx → blog/app.tsx} +18 -11
- package/src/{articles → blog/articles}/celebration.mdx +0 -1
- package/src/{articles → blog/articles}/cousin.mdx +1 -1
- package/src/{articles → blog/articles}/leaves.mdx +1 -1
- package/src/{articles → blog/articles}/liqiu.mdx +0 -1
- package/src/{articles → blog/articles}/men-without-women.mdx +3 -3
- package/src/{articles → blog/articles}/movie-day.mdx +2 -2
- package/src/{articles → blog/articles}/projects.mdx +0 -1
- package/src/{articles → blog/articles}/quote.mdx +0 -1
- package/src/{articles → blog/articles}/red-gun.mdx +1 -1
- package/src/{articles → blog/articles}/rice-noodle.mdx +1 -1
- package/src/{articles → blog/articles}/spring-cooldown.mdx +1 -0
- package/src/{articles → blog/articles}/spring-rain.mdx +1 -0
- package/src/{articles → blog/articles}/woke-up.mdx +1 -1
- package/src/{components → blog/components}/Footer.tsx +1 -1
- package/src/{components → blog/components}/ImageUploader.tsx +1 -1
- package/src/{components → blog/components}/Img_ctx_menu/index.tsx +1 -1
- package/src/{components → blog/components}/Spinner.tsx +1 -1
- package/src/{components → blog/components}/app_ctx_menu/index.tsx +3 -1
- package/src/{components → blog/components}/article/index.tsx +1 -1
- package/src/blog/components/plugin/PluginContentPage.tsx +30 -0
- package/src/blog/components/plugin/PluginDrawer.tsx +39 -0
- package/src/blog/components/plugin/PluginInit.tsx +50 -0
- package/src/blog/components/plugin/PluginInputForm.tsx +117 -0
- package/src/blog/components/plugin/PluginMenuItem.tsx +67 -0
- package/src/blog/components/plugin/PluginRoutes.tsx +13 -0
- package/src/blog/components/plugin/PluginsMenuItem.tsx +45 -0
- package/src/blog/components/plugin/hooks/useDependencies.ts +63 -0
- package/src/blog/components/plugin/hooks/usePluginOutput.tsx +17 -0
- package/src/blog/context/bbcontext.tsx +14 -0
- package/src/blog/context/global_routes_provider.tsx +38 -0
- package/src/blog/demo/PluginDemo.ts +24 -0
- package/src/{hooks → blog/hooks}/useLoadingIndicator.ts +1 -1
- package/src/{hooks → blog/hooks}/use_file_to_post.ts +1 -1
- package/src/{hooks → blog/hooks}/use_posts.ts +1 -1
- package/src/{hooks → blog/hooks}/use_projects.ts +1 -1
- package/src/{main.tsx → blog/index.tsx} +13 -13
- package/src/{main.css → blog/main.css} +10 -0
- package/src/{pages → blog/pages}/cover/index.tsx +8 -6
- package/src/{pages → blog/pages}/extensions/txt/article.tsx +1 -1
- package/src/{pages → blog/pages}/login/index.tsx +1 -1
- package/src/blog/plugin/Dependencies.ts +10 -0
- package/src/blog/plugin/HostFuncAdapter.ts +28 -0
- package/src/blog/plugin/Plugin.ts +122 -0
- package/src/blog/plugin/PluginManager.ts +153 -0
- package/src/blog/plugin/PluginManagerPayload.ts +3 -0
- package/src/index.tsx +4 -0
- package/tsconfig.json +1 -1
- package/vite.config.js +5 -2
- /package/src/{__test__ → blog/__test__}/utils/index.test.ts +0 -0
- /package/src/{articles → blog/articles}/anti-logic.mdx +0 -0
- /package/src/{articles → blog/articles}/bbking-manual.mdx +0 -0
- /package/src/{articles → blog/articles}/black-river.mdx +0 -0
- /package/src/{articles → blog/articles}/cloth.mdx +0 -0
- /package/src/{articles → blog/articles}/cooking.mdx +0 -0
- /package/src/{articles → blog/articles}/cooldown.mdx +0 -0
- /package/src/{articles → blog/articles}/fall.mdx +0 -0
- /package/src/{articles → blog/articles}/img.mdx +0 -0
- /package/src/{articles → blog/articles}/index.ts +0 -0
- /package/src/{articles → blog/articles}/loading.mdx +0 -0
- /package/src/{articles → blog/articles}/love.mdx +0 -0
- /package/src/{articles → blog/articles}/major-cold.mdx +0 -0
- /package/src/{articles → blog/articles}/marshroom.mdx +0 -0
- /package/src/{articles → blog/articles}/moment.mdx +0 -0
- /package/src/{articles → blog/articles}/now.mdx +0 -0
- /package/src/{articles → blog/articles}/photos.mdx +0 -0
- /package/src/{articles → blog/articles}/pseudo-spring.mdx +0 -0
- /package/src/{articles → blog/articles}/travel.mdx +0 -0
- /package/src/{articles → blog/articles}/warming-up.mdx +0 -0
- /package/src/{articles → blog/articles}/web-burnning.mdx +0 -0
- /package/src/{articles → blog/articles}/xwy-and-snowing.mdx +0 -0
- /package/src/{articles → blog/articles}/xwy.mdx +0 -0
- /package/src/{components → blog/components}/Auth.tsx +0 -0
- /package/src/{components → blog/components}/DelayFadeIn/DelayFadeIn.tsx +0 -0
- /package/src/{components → blog/components}/Logger.tsx +0 -0
- /package/src/{components → blog/components}/Pochacco/Pochacco.tsx +0 -0
- /package/src/{components → blog/components}/Pochacco/idle.tsx +0 -0
- /package/src/{components → blog/components}/Pochacco/watch.tsx +0 -0
- /package/src/{components → blog/components}/app_ctx_menu/LoginMenuItem.tsx +0 -0
- /package/src/{components → blog/components}/app_ctx_menu/VersionMenuItem.tsx +0 -0
- /package/src/{components → blog/components}/app_ctx_menu/ViewSourceMenuItem.tsx +0 -0
- /package/src/{components → blog/components}/article_ctx_menu/index.tsx +0 -0
- /package/src/{components → blog/components}/aspect_ratio_box/index.tsx +0 -0
- /package/src/{components → blog/components}/blur_cover/index.tsx +0 -0
- /package/src/{components → blog/components}/book_list/index.tsx +0 -0
- /package/src/{components → blog/components}/comment/index.tsx +0 -0
- /package/src/{components → blog/components}/comment/use_cusdis_event.ts +0 -0
- /package/src/{components → blog/components}/corner_prompt_box/index.tsx +0 -0
- /package/src/{components → blog/components}/disabled_text/index.tsx +0 -0
- /package/src/{components → blog/components}/effect-layer/EffectContextProvider.tsx +0 -0
- /package/src/{components → blog/components}/effect-layer/EffectLayer.tsx +0 -0
- /package/src/{components → blog/components}/effect-layer/effects/grain.frag +0 -0
- /package/src/{components → blog/components}/effect-layer/hooks/useRender.ts +0 -0
- /package/src/{components → blog/components}/effect-layer/hooks/useResolution.ts +0 -0
- /package/src/{components → blog/components}/effect-layer/main.frag +0 -0
- /package/src/{components → blog/components}/effect-layer/shader.vert +0 -0
- /package/src/{components → blog/components}/effect-layer/shapes/circle.frag +0 -0
- /package/src/{components → blog/components}/effect-layer/shapes/heart.frag +0 -0
- /package/src/{components → blog/components}/effect-layer/shapes/spiral.frag +0 -0
- /package/src/{components → blog/components}/effect-layer/uniforms.ts +0 -0
- /package/src/{components → blog/components}/fade_out_cover/index.tsx +0 -0
- /package/src/{components → blog/components}/footer/footer_links.ts +0 -0
- /package/src/{components → blog/components}/footer/index.tsx +0 -0
- /package/src/{components → blog/components}/hotkey_nav/index.tsx +0 -0
- /package/src/{components → blog/components}/img_list/index.tsx +0 -0
- /package/src/{components → blog/components}/index.tsx +0 -0
- /package/src/{components → blog/components}/movie_list/index.tsx +0 -0
- /package/src/{components → blog/components}/my_suspense.tsx +0 -0
- /package/src/{components → blog/components}/progress_bar/index.tsx +0 -0
- /package/src/{components → blog/components}/reload_prompt/index.tsx +0 -0
- /package/src/{components → blog/components}/stickers/index.tsx +0 -0
- /package/src/{components → blog/components}/table_skeleton/index.tsx +0 -0
- /package/src/{components → blog/components}/tags/index.tsx +0 -0
- /package/src/{components → blog/components}/video_player/index.tsx +0 -0
- /package/src/{components → blog/components}/with_wrapper/index.tsx +0 -0
- /package/src/{constants → blog/constants}/cusdis.ts +0 -0
- /package/src/{constants → blog/constants}/index.ts +0 -0
- /package/src/{constants → blog/constants}/photo_projects.ts +0 -0
- /package/src/{constants → blog/constants}/photos.ts +0 -0
- /package/src/{constants → blog/constants}/routes.ts +0 -0
- /package/src/{constants → blog/constants}/video_logs.ts +0 -0
- /package/src/{global_loading_state_provider.tsx → blog/context/global_loading_state_provider.tsx} +0 -0
- /package/src/{demo → blog/demo}/DemoBox.tsx +0 -0
- /package/src/{demo → blog/demo}/DemoMenu.tsx +0 -0
- /package/src/{demo → blog/demo}/ImgDemo.tsx +0 -0
- /package/src/{demo → blog/demo}/SpinnerDemo.tsx +0 -0
- /package/src/{demo → blog/demo}/Xwy.tsx +0 -0
- /package/src/{global → blog/global}/mdx.d.ts +0 -0
- /package/src/{hooks → blog/hooks}/index.ts +0 -0
- /package/src/{hooks → blog/hooks}/useScrollToTop.ts +0 -0
- /package/src/{hooks → blog/hooks}/useTransitionCls.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_authed.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_authed_fetcher.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_del_img.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_delete_post.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_font_loading.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_img_loading.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_mouse_position.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_pathname.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_paths.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_post.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_role.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_route_name.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_supa_session.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_text_plain_file.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_uploader.ts +0 -0
- /package/src/{hooks → blog/hooks}/use_video_controls.ts +0 -0
- /package/src/{pages → blog/pages}/bot/index.tsx +0 -0
- /package/src/{pages → blog/pages}/extensions/png/consts.ts +0 -0
- /package/src/{pages → blog/pages}/extensions/png/index.tsx +0 -0
- /package/src/{pages → blog/pages}/extensions/png/png_projects.tsx +0 -0
- /package/src/{pages → blog/pages}/extensions/txt/consts.ts +0 -0
- /package/src/{pages → blog/pages}/extensions/txt/index.tsx +0 -0
- /package/src/{pages → blog/pages}/index.tsx +0 -0
- /package/src/{pages → blog/pages}/now/index.tsx +0 -0
- /package/src/{pages → blog/pages}/tags/index.tsx +0 -0
- /package/src/{pages → blog/pages}/tags/tag_result.tsx +0 -0
- /package/src/{pages → blog/pages}/upload/index.tsx +0 -0
- /package/src/{swr.tsx → blog/swr.tsx} +0 -0
- /package/src/{types → blog/types}/articles.ts +0 -0
- /package/src/{types → blog/types}/color.ts +0 -0
- /package/src/{types → blog/types}/cusdis.ts +0 -0
- /package/src/{types → blog/types}/font.ts +0 -0
- /package/src/{types → blog/types}/glsl.d.ts +0 -0
- /package/src/{types → blog/types}/oss.ts +0 -0
- /package/src/{types → blog/types}/path.ts +0 -0
- /package/src/{types → blog/types}/photo.ts +0 -0
- /package/src/{types → blog/types}/supabase.ts +0 -0
- /package/src/{types → blog/types}/upload.ts +0 -0
- /package/src/{utils → blog/utils}/index.ts +0 -0
- /package/src/{utils → blog/utils}/tags.ts +0 -0
package/CHANGELOG.md
CHANGED
package/index.html
CHANGED
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
</head>
|
|
41
41
|
|
|
42
42
|
<body class="h-full m-0 flex flex-col font-mono">
|
|
43
|
-
<div id="
|
|
44
|
-
<script type="module" src="/src/
|
|
43
|
+
<div id="blog" class="flex-grow noto-serif"></div>
|
|
44
|
+
<script type="module" src="/src/index.tsx"></script>
|
|
45
45
|
<script type="module">
|
|
46
46
|
// Import the functions you need from the SDKs you need
|
|
47
47
|
import { initializeApp } from "https://www.gstatic.com/firebasejs/10.12.3/firebase-app.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bbki.ng/site",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "code behind bbki.ng",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"url": "git+https://github.com/bbbottle/bbki.ng.git"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@
|
|
19
|
+
"@extism/extism": "2.0.0-rc11",
|
|
20
|
+
"@bbki.ng/components": "workspace:2.6.0",
|
|
20
21
|
"@supabase/supabase-js": "^1.35.4",
|
|
21
22
|
"classnames": "2.3.1",
|
|
22
23
|
"react": "^18.0.0",
|
|
@@ -25,10 +26,11 @@
|
|
|
25
26
|
"react-hotkeys-hook": "^3.4.3",
|
|
26
27
|
"react-router-dom": "6",
|
|
27
28
|
"sonner": "1.4.0",
|
|
28
|
-
"swr": "^2.2.5"
|
|
29
|
+
"swr": "^2.2.5",
|
|
30
|
+
"vaul": "1.1.2"
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
31
|
-
"@bbki.ng/stylebase": "workspace:0.4.
|
|
33
|
+
"@bbki.ng/stylebase": "workspace:0.4.7",
|
|
32
34
|
"@mdx-js/mdx": "2.0.0-next.9",
|
|
33
35
|
"@mdx-js/react": "^1.6.22",
|
|
34
36
|
"@mdx-js/rollup": "3.0.0",
|
|
@@ -58,6 +60,7 @@
|
|
|
58
60
|
"ts-jest": "^27.1.1",
|
|
59
61
|
"typescript": "^4.5.4",
|
|
60
62
|
"vite": "5.0.0",
|
|
63
|
+
"vite-plugin-cross-origin-isolation": "0.1.6",
|
|
61
64
|
"vite-plugin-glsl": "1.2.1",
|
|
62
65
|
"vite-plugin-mdx": "^3.5.8",
|
|
63
66
|
"vite-plugin-pwa": "0.19",
|
package/public/now.wasm
ADDED
|
Binary file
|
|
@@ -16,16 +16,16 @@ import Txt from "@/pages/extensions/txt";
|
|
|
16
16
|
import { usePaths } from "@/hooks";
|
|
17
17
|
import { Login } from "@/pages/login";
|
|
18
18
|
import { SWR } from "@/swr";
|
|
19
|
-
import {
|
|
20
|
-
GlobalLoadingContext,
|
|
21
|
-
GlobalLoadingStateProvider,
|
|
22
|
-
} from "@/global_loading_state_provider";
|
|
19
|
+
import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
|
|
23
20
|
import { UploadPage } from "@/pages/upload";
|
|
24
21
|
import { AppCtxMenu } from "@/components/app_ctx_menu";
|
|
25
22
|
import { Pochacco, PochaccoPose } from "@/components/Pochacco/Pochacco";
|
|
26
23
|
import { Role, useRole } from "@/hooks/use_role";
|
|
27
|
-
import { EffectContextProvider } from "@/components/effect-layer/EffectContextProvider";
|
|
28
24
|
import { BotRedirect } from "@/pages/bot";
|
|
25
|
+
import { PluginInit } from "@/components/plugin/PluginInit";
|
|
26
|
+
import { BBContext } from "@/context/bbcontext";
|
|
27
|
+
import { PluginContentPage } from "@/components/plugin/PluginContentPage";
|
|
28
|
+
import { PluginRoutes } from "@/components/plugin/PluginRoutes";
|
|
29
29
|
|
|
30
30
|
const Layout = () => {
|
|
31
31
|
const { isLoading, isFontLoading } = useContext(GlobalLoadingContext);
|
|
@@ -65,9 +65,10 @@ const CoverInMidCol = threeColWrapper(Cover);
|
|
|
65
65
|
export const App = () => {
|
|
66
66
|
return (
|
|
67
67
|
<SWR>
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
{/*<EffectContextProvider>*/}
|
|
69
|
+
<HotKeyNav>
|
|
70
|
+
<BBContext>
|
|
71
|
+
<PluginInit>
|
|
71
72
|
<Routes>
|
|
72
73
|
<Route path="/" element={<Layout />}>
|
|
73
74
|
<Route index element={<CoverInMidCol />} />
|
|
@@ -85,12 +86,18 @@ export const App = () => {
|
|
|
85
86
|
<Route path="now" element={<NowInMidCol />} />
|
|
86
87
|
<Route path="login" element={<LoginInMidCol />} />
|
|
87
88
|
<Route path="upload" element={<UploadPage />} />
|
|
89
|
+
<Route path="/plugins" element={<PluginRoutes />} />
|
|
90
|
+
<Route
|
|
91
|
+
path="/plugins/:pluginRoute"
|
|
92
|
+
element={<PluginContentPage />}
|
|
93
|
+
/>
|
|
88
94
|
</Route>
|
|
89
95
|
<Route path="*" element={<NotFound />} />
|
|
90
96
|
</Routes>
|
|
91
|
-
</
|
|
92
|
-
</
|
|
93
|
-
</
|
|
97
|
+
</PluginInit>
|
|
98
|
+
</BBContext>
|
|
99
|
+
</HotKeyNav>
|
|
100
|
+
{/*</EffectContextProvider>*/}
|
|
94
101
|
</SWR>
|
|
95
102
|
);
|
|
96
103
|
};
|
|
@@ -8,9 +8,9 @@ tags:
|
|
|
8
8
|
|
|
9
9
|
《没有女人的男人们》是村上春树的短篇小说集,书本介绍写的是:「村上返回原点之作,《东京奇谭集》之后时隔九年又一短篇小说集」。「返回原点」也多少有点像在说自己,时隔三年又回到之前离开的城市。一天刚好看完。
|
|
10
10
|
|
|
11
|
-
| 上午
|
|
12
|
-
|
|
13
|
-
| 驾驶我的车 <br /> 昨天
|
|
11
|
+
| 上午 | 下午 | 晚上 |
|
|
12
|
+
| :--------------------- | :----------------------------------- | :----------- |
|
|
13
|
+
| 驾驶我的车 <br /> 昨天 | 独立器官 <br /> 山鲁左德 <br /> 木野 | 恋爱的萨姆沙 |
|
|
14
14
|
|
|
15
15
|
故事中的男人们,有人妻子过世,有人想满世界流浪,有人是坚定的不婚主义,有人被戴上有颜色的帽子……男男女女,来来去去。短篇小说比起电影好像更任性一点,结局戛然而止也让人也觉得情理之中,根据交代过的信息想象一下男女主接下来的境遇也是一件很有意思的事情。我最喜欢的两篇是《山鲁佐德》和《木野》。前者作为一个故事,故事中又穿插了女主讲述的故事,很有层次感,也很容易被带入女主的玄妙变态、虚实莫辨的回忆或者说是想象中。甚至阅读完都不太想深究她和男主到底是什么关系。此外文中有一段关于胡子的描述,觉得挺好玩,感觉也可以尝试一下:
|
|
16
16
|
|
|
@@ -8,8 +8,8 @@ tags:
|
|
|
8
8
|
|
|
9
9
|
**一天计划**,用一天时间在同一个地点做同一件事情。比如写一天代码、看一天书。个人电影节也是「一天计划」的一部分。从之前标记想看的电影清单中随机挑选出五部电影,用一天时间看完。
|
|
10
10
|
|
|
11
|
-
| 上午
|
|
12
|
-
|
|
11
|
+
| 上午 | 下午 | 晚上 |
|
|
12
|
+
| :--------------------- | :--------------------------- | :------- |
|
|
13
13
|
| 花火 <br /> 数电影的人 | 不能说的游戏 <br /> 蜂蜜之地 | 尽情游戏 |
|
|
14
14
|
|
|
15
15
|
《花火》整部电影都很沉默冷静,甚至连剧中的枪响也是。可能是浓烈的情感需要大面积的留白去稀释,主角台词不多,却好像什么都已说尽。《数电影的人》是一部记录片,介绍了一群修复电影胶片的人,为电影延续生命。他们有枯燥的工作,有来自同事间互相鼓励和安慰。有意义危机,也有使命感和成就感。我更羡慕的是他们的工作周期,能花很长很长的一段时间慢慢把事情做好,也紧迫也从容。《不能说的游戏》讲述小女孩被熟人性侵后,整个人生受到的影响。电影配乐很欢快,大部分剪辑也是,但看似轻松欢快的节奏,却能让人感受到背后的压抑与主角内心困兽般的反应。这部电影,比起犯人,我更讨厌女主的母亲。《蜂蜜之地》是一部很美的记录片,贫瘠的土地,满眼只能看到岩石灌木和沙砾。相依为命的母女,贪婪的邻居。能够看到一种截然不同的生活方式,已经很心满意足。《尽情游戏》则是一部轻松的喜剧,可能包含了对战争的反思,我更愿意就把它当成一部普通的喜剧。最后其实还有一部德国电影《奇迹》,已经无法看下去,就像很久没有运动,跑完三公里已经到了极限,无法跑完最后一圈。
|
|
@@ -2,7 +2,7 @@ import React, { useContext } from "react";
|
|
|
2
2
|
import { Link, Tag } from "@bbki.ng/components";
|
|
3
3
|
import { useLocation } from "react-router-dom";
|
|
4
4
|
import { usePaths } from "@/hooks";
|
|
5
|
-
import { GlobalLoadingContext } from "@/global_loading_state_provider";
|
|
5
|
+
import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
|
|
6
6
|
|
|
7
7
|
export const Footer = () => {
|
|
8
8
|
const location = useLocation();
|
|
@@ -2,7 +2,7 @@ import React, { useContext } from "react";
|
|
|
2
2
|
import { DropImage } from "@bbki.ng/components";
|
|
3
3
|
import { useUploader } from "@/hooks/use_uploader";
|
|
4
4
|
import { ImageUploaderProps } from "@/types/upload";
|
|
5
|
-
import { GlobalLoadingContext } from "@/global_loading_state_provider";
|
|
5
|
+
import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
|
|
6
6
|
import { Auth } from "@/components/Auth";
|
|
7
7
|
import { Role } from "@/hooks/use_role";
|
|
8
8
|
import { useParams } from "react-router-dom";
|
|
@@ -13,7 +13,7 @@ import { confirm } from "@/utils";
|
|
|
13
13
|
import { ContextMenuSeparator } from "@bbki.ng/components";
|
|
14
14
|
import { useDelImg } from "@/hooks/use_del_img";
|
|
15
15
|
import { toast } from "sonner";
|
|
16
|
-
import { GlobalLoadingContext } from "@/global_loading_state_provider";
|
|
16
|
+
import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
|
|
17
17
|
|
|
18
18
|
export const ImgCtxMenu = (props: {
|
|
19
19
|
children: ReactElement;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useContext, useEffect } from "react";
|
|
2
|
-
import { GlobalLoadingContext } from "@/global_loading_state_provider";
|
|
2
|
+
import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
|
|
3
3
|
|
|
4
4
|
export const Spinner = (props: { disableDotIndicator?: boolean }) => {
|
|
5
5
|
const { disableDotIndicator } = props;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { LoginMenuItem } from "@/components/app_ctx_menu/LoginMenuItem";
|
|
11
11
|
import { VersionMenuItem } from "@/components/app_ctx_menu/VersionMenuItem";
|
|
12
12
|
import { ViewSourceMenuItem } from "@/components/app_ctx_menu/ViewSourceMenuItem";
|
|
13
|
+
import { PluginsMenuItem } from "@/components/plugin/PluginsMenuItem";
|
|
13
14
|
|
|
14
15
|
export const AppCtxMenu = (props: { children: ReactElement }) => {
|
|
15
16
|
return (
|
|
@@ -17,9 +18,10 @@ export const AppCtxMenu = (props: { children: ReactElement }) => {
|
|
|
17
18
|
<ContextMenuTrigger>{props.children}</ContextMenuTrigger>
|
|
18
19
|
<ContextMenuContent className="w-256">
|
|
19
20
|
<LoginMenuItem />
|
|
20
|
-
<ContextMenuSeparator />
|
|
21
21
|
<VersionMenuItem />
|
|
22
22
|
<ViewSourceMenuItem />
|
|
23
|
+
<ContextMenuSeparator />
|
|
24
|
+
<PluginsMenuItem />
|
|
23
25
|
</ContextMenuContent>
|
|
24
26
|
</ContextMenu>
|
|
25
27
|
);
|
|
@@ -4,7 +4,7 @@ import { ROUTES } from "@/constants";
|
|
|
4
4
|
import { DelayFadeIn } from "@/components/DelayFadeIn/DelayFadeIn";
|
|
5
5
|
import classNames from "classnames";
|
|
6
6
|
|
|
7
|
-
type ArticlePageProps = {
|
|
7
|
+
export type ArticlePageProps = {
|
|
8
8
|
tags?: string[];
|
|
9
9
|
title: string;
|
|
10
10
|
description?: any;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ArticlePage, ArticlePageProps } from "@/components/article";
|
|
2
|
+
import React, { memo } from "react";
|
|
3
|
+
import { threeColWrapper } from "@/components/with_wrapper";
|
|
4
|
+
import { useParams } from "react-router-dom";
|
|
5
|
+
import { usePluginOutput } from "@/components/plugin/hooks/usePluginOutput";
|
|
6
|
+
import { PluginManager } from "@/plugin/PluginManager";
|
|
7
|
+
|
|
8
|
+
type PluginContentPageProps = Omit<ArticlePageProps, "children">;
|
|
9
|
+
|
|
10
|
+
const ContentPage = (props: PluginContentPageProps) => {
|
|
11
|
+
const { pluginRoute } = useParams();
|
|
12
|
+
|
|
13
|
+
if (!pluginRoute || !PluginManager.instance) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const plugin = PluginManager.instance.getPluginByRoute(pluginRoute);
|
|
18
|
+
if (!plugin) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const content = usePluginOutput(plugin.config.id);
|
|
23
|
+
return (
|
|
24
|
+
<ArticlePage {...props} title={plugin?.config.route || ""}>
|
|
25
|
+
<div dangerouslySetInnerHTML={{ __html: content }} />
|
|
26
|
+
</ArticlePage>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const PluginContentPage = threeColWrapper(ContentPage);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { DialogProps, Drawer } from "vaul";
|
|
2
|
+
import React, { ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
type PluginDrawerProps = {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
title?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
} & Pick<DialogProps, "open"> &
|
|
9
|
+
Pick<DialogProps, "onOpenChange">;
|
|
10
|
+
|
|
11
|
+
export const PluginDrawer = (props: PluginDrawerProps) => {
|
|
12
|
+
const { children, title, description, open, onOpenChange } = props;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Drawer.Root
|
|
16
|
+
direction="bottom"
|
|
17
|
+
open={open}
|
|
18
|
+
onOpenChange={onOpenChange}
|
|
19
|
+
modal={false}
|
|
20
|
+
>
|
|
21
|
+
<Drawer.Portal>
|
|
22
|
+
<Drawer.Content className="bg-gray-100 flex flex-col {/*rounded-t-[10px]*/} mt-24 h-fit fixed bottom-0 left-0 right-0 outline-none border-t border-gray-200">
|
|
23
|
+
<div className="p-4 bg-white {/*rounded-t-[10px]*/} flex-1">
|
|
24
|
+
<div className="mx-auto w-12 h-1.5 flex-shrink-0 rounded-full bg-gray-300 mb-8" />
|
|
25
|
+
<div className="max-w-md mx-auto my-32 p-16">
|
|
26
|
+
<Drawer.Title className="font-medium mb-2 text-zinc-900">
|
|
27
|
+
{title}
|
|
28
|
+
</Drawer.Title>
|
|
29
|
+
<Drawer.Description className="text-zinc-600 mb-2">
|
|
30
|
+
{description}
|
|
31
|
+
</Drawer.Description>
|
|
32
|
+
{children}
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</Drawer.Content>
|
|
36
|
+
</Drawer.Portal>
|
|
37
|
+
</Drawer.Root>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React, { useCallback, useEffect } from "react";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
import { PluginInputForm } from "@/components/plugin/PluginInputForm";
|
|
4
|
+
import { useDependencies } from "@/components/plugin/hooks/useDependencies";
|
|
5
|
+
import { PluginManager } from "@/plugin/PluginManager";
|
|
6
|
+
|
|
7
|
+
export const PluginInit = (props: { children: ReactNode }) => {
|
|
8
|
+
const {
|
|
9
|
+
isPluginFormInputOpen,
|
|
10
|
+
setPluginFormInputOpen,
|
|
11
|
+
pluginInputFormConf,
|
|
12
|
+
formDataResolver,
|
|
13
|
+
|
|
14
|
+
...dep
|
|
15
|
+
} = useDependencies();
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
PluginManager.init(dep).then();
|
|
19
|
+
}, []);
|
|
20
|
+
|
|
21
|
+
const onSubmit = useCallback(
|
|
22
|
+
(formData: string) => {
|
|
23
|
+
formDataResolver(formData);
|
|
24
|
+
setPluginFormInputOpen(false);
|
|
25
|
+
},
|
|
26
|
+
[formDataResolver]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const onOpenChange = useCallback(
|
|
30
|
+
(o: boolean) => {
|
|
31
|
+
setPluginFormInputOpen(o);
|
|
32
|
+
if (!o) {
|
|
33
|
+
formDataResolver("");
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
[formDataResolver]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<>
|
|
41
|
+
{props.children}
|
|
42
|
+
<PluginInputForm
|
|
43
|
+
open={isPluginFormInputOpen}
|
|
44
|
+
onOpenChange={onOpenChange}
|
|
45
|
+
input={pluginInputFormConf}
|
|
46
|
+
onSubmit={onSubmit}
|
|
47
|
+
/>
|
|
48
|
+
</>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { PluginInput, PluginInputFieldType } from "@/plugin/Plugin";
|
|
3
|
+
import {
|
|
4
|
+
z,
|
|
5
|
+
zodResolver,
|
|
6
|
+
useForm,
|
|
7
|
+
Form,
|
|
8
|
+
FormField,
|
|
9
|
+
FormItem,
|
|
10
|
+
FormLabel,
|
|
11
|
+
Input,
|
|
12
|
+
Button,
|
|
13
|
+
ButtonType,
|
|
14
|
+
FormControl,
|
|
15
|
+
} from "@bbki.ng/components";
|
|
16
|
+
import { PluginDrawer } from "@/components/plugin/PluginDrawer";
|
|
17
|
+
import { DialogProps } from "vaul";
|
|
18
|
+
|
|
19
|
+
type PluginInputFormProps = {
|
|
20
|
+
input: PluginInput;
|
|
21
|
+
onSubmit: (input: string) => void;
|
|
22
|
+
} & Pick<DialogProps, "open"> &
|
|
23
|
+
Pick<DialogProps, "onOpenChange">;
|
|
24
|
+
|
|
25
|
+
const getPluginInputSchema = (input: PluginInput) => {
|
|
26
|
+
const obj: any = {};
|
|
27
|
+
const typeMap = {
|
|
28
|
+
[PluginInputFieldType.String]: z.string().default(""),
|
|
29
|
+
[PluginInputFieldType.Number]: z.number().default(0),
|
|
30
|
+
[PluginInputFieldType.Boolean]: z.boolean().default(false),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
input.forEach((item) => {
|
|
34
|
+
obj[item.name] = typeMap[item.type];
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return z.object(obj);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const getInputDefaultValue = (type: PluginInputFieldType) => {
|
|
41
|
+
switch (type) {
|
|
42
|
+
case PluginInputFieldType.String:
|
|
43
|
+
return "";
|
|
44
|
+
case PluginInputFieldType.Number:
|
|
45
|
+
return 0;
|
|
46
|
+
case PluginInputFieldType.Boolean:
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const getPluginDefaultInput = (input: PluginInput) => {
|
|
52
|
+
const obj: any = {};
|
|
53
|
+
input.forEach((item) => {
|
|
54
|
+
obj[item.name] = getInputDefaultValue(item.type);
|
|
55
|
+
});
|
|
56
|
+
return obj;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const getInputType = (type: PluginInputFieldType) => {
|
|
60
|
+
switch (type) {
|
|
61
|
+
case PluginInputFieldType.String:
|
|
62
|
+
return "text";
|
|
63
|
+
case PluginInputFieldType.Number:
|
|
64
|
+
return "number";
|
|
65
|
+
case PluginInputFieldType.Boolean:
|
|
66
|
+
return "checkbox";
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const PluginInputForm = (props: PluginInputFormProps) => {
|
|
71
|
+
const { input, onSubmit, open, onOpenChange } = props;
|
|
72
|
+
const schema = getPluginInputSchema(input);
|
|
73
|
+
const form = useForm<z.infer<typeof schema>>({
|
|
74
|
+
resolver: zodResolver(schema),
|
|
75
|
+
values: getPluginDefaultInput(input),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const ok = (data: z.infer<typeof schema>) => {
|
|
79
|
+
onSubmit(JSON.stringify(data));
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<PluginDrawer open={open} onOpenChange={onOpenChange}>
|
|
84
|
+
<Form {...form}>
|
|
85
|
+
<form onSubmit={form.handleSubmit(ok)}>
|
|
86
|
+
{input.map((item) => {
|
|
87
|
+
return (
|
|
88
|
+
<FormField
|
|
89
|
+
key={item.name}
|
|
90
|
+
control={form.control}
|
|
91
|
+
render={({ field }) => {
|
|
92
|
+
return (
|
|
93
|
+
<FormItem>
|
|
94
|
+
<FormLabel>{item.name}</FormLabel>
|
|
95
|
+
<FormControl>
|
|
96
|
+
<Input type={getInputType(item.type)} {...field} />
|
|
97
|
+
</FormControl>
|
|
98
|
+
</FormItem>
|
|
99
|
+
);
|
|
100
|
+
}}
|
|
101
|
+
name={item.name}
|
|
102
|
+
/>
|
|
103
|
+
);
|
|
104
|
+
})}
|
|
105
|
+
<Button
|
|
106
|
+
className="mt-16"
|
|
107
|
+
onClick={() => {}}
|
|
108
|
+
btnType="submit"
|
|
109
|
+
type={ButtonType.PRIMARY}
|
|
110
|
+
>
|
|
111
|
+
Ok
|
|
112
|
+
</Button>
|
|
113
|
+
</form>
|
|
114
|
+
</Form>
|
|
115
|
+
</PluginDrawer>
|
|
116
|
+
);
|
|
117
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
ContextMenuItem,
|
|
4
|
+
ContextMenuSub,
|
|
5
|
+
ContextMenuSubContent,
|
|
6
|
+
ContextMenuSubTrigger,
|
|
7
|
+
} from "@bbki.ng/components";
|
|
8
|
+
import { PluginConfig, PluginStatus } from "@/plugin/Plugin";
|
|
9
|
+
|
|
10
|
+
type PluginMenuItemProps = {
|
|
11
|
+
plugin: PluginConfig;
|
|
12
|
+
onUninstall: (plugin: PluginConfig) => void;
|
|
13
|
+
onInstall: (plugin: PluginConfig) => void;
|
|
14
|
+
onStop: (plugin: PluginConfig) => void;
|
|
15
|
+
onRun: (plugin: PluginConfig) => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const PluginMenuItem = (props: PluginMenuItemProps) => {
|
|
19
|
+
const { plugin, onUninstall, onStop, onRun, onInstall } = props;
|
|
20
|
+
return (
|
|
21
|
+
<ContextMenuSub>
|
|
22
|
+
<ContextMenuSubTrigger inset>
|
|
23
|
+
{plugin.name} v{plugin.version}
|
|
24
|
+
</ContextMenuSubTrigger>
|
|
25
|
+
<ContextMenuSubContent className="w-48">
|
|
26
|
+
{plugin.status !== PluginStatus.Available && (
|
|
27
|
+
<ContextMenuItem
|
|
28
|
+
onClick={() => {
|
|
29
|
+
onUninstall(plugin);
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
uninstall
|
|
33
|
+
</ContextMenuItem>
|
|
34
|
+
)}
|
|
35
|
+
{plugin.status === PluginStatus.Available && (
|
|
36
|
+
<ContextMenuItem
|
|
37
|
+
onClick={() => {
|
|
38
|
+
onInstall(plugin);
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
install
|
|
42
|
+
</ContextMenuItem>
|
|
43
|
+
)}
|
|
44
|
+
{plugin.status === PluginStatus.Running && (
|
|
45
|
+
<ContextMenuItem
|
|
46
|
+
onClick={() => {
|
|
47
|
+
onStop(plugin);
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
stop
|
|
51
|
+
</ContextMenuItem>
|
|
52
|
+
)}
|
|
53
|
+
{(plugin.status === PluginStatus.Installed ||
|
|
54
|
+
plugin.status === PluginStatus.Stopped) &&
|
|
55
|
+
!plugin.route && (
|
|
56
|
+
<ContextMenuItem
|
|
57
|
+
onClick={() => {
|
|
58
|
+
onRun(plugin);
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
run
|
|
62
|
+
</ContextMenuItem>
|
|
63
|
+
)}
|
|
64
|
+
</ContextMenuSubContent>
|
|
65
|
+
</ContextMenuSub>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { threeColWrapper } from "@/components/with_wrapper";
|
|
2
|
+
import { CenterLinkList } from "@/components";
|
|
3
|
+
import React, { useContext } from "react";
|
|
4
|
+
import { GlobalRoutesContext } from "@/context/global_routes_provider";
|
|
5
|
+
|
|
6
|
+
const PluginRoutesContent = () => {
|
|
7
|
+
const globalRouteCtx = useContext(GlobalRoutesContext);
|
|
8
|
+
const routes = globalRouteCtx.globalRoutes;
|
|
9
|
+
|
|
10
|
+
return <CenterLinkList className="select-none" links={routes} title="" />;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const PluginRoutes = threeColWrapper(PluginRoutesContent);
|