@bbki.ng/site 1.7.16 → 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 +2 -0
- package/index.html +2 -2
- package/package.json +6 -3
- 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,7 +26,8 @@
|
|
|
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
33
|
"@bbki.ng/stylebase": "workspace:0.4.7",
|
|
@@ -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);
|