@bbki.ng/site 1.8.2 → 1.8.4

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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # @bbki.ng/site
2
2
 
3
+ ## 1.8.4
4
+
5
+ ## 1.8.3
6
+
3
7
  ## 1.8.2
4
8
 
5
9
  ## 1.8.1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbki.ng/site",
3
- "version": "1.8.2",
3
+ "version": "1.8.4",
4
4
  "description": "code behind bbki.ng",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@extism/extism": "2.0.0-rc11",
20
- "@bbki.ng/components": "workspace:2.6.1",
20
+ "@bbki.ng/components": "workspace:2.6.3",
21
21
  "@supabase/supabase-js": "^1.35.4",
22
22
  "classnames": "2.3.1",
23
23
  "react": "^18.0.0",
package/src/blog/app.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import React, { useContext } from "react";
2
2
  import { Outlet, Route, Routes } from "react-router-dom";
3
- import { Nav, NotFound, Page, BlurCover } from "@bbki.ng/components";
3
+ import { Nav, NotFound, Page } from "@bbki.ng/components";
4
4
  import { HotKeyNav } from "./components";
5
5
  import { threeColWrapper } from "@/components/with_wrapper";
6
6
  import { Cover } from "./pages";
@@ -48,7 +48,6 @@ const Layout = () => {
48
48
  }
49
49
  main={<Outlet />}
50
50
  />
51
- <BlurCover status={isFontLoading ? "show" : "silent"} />
52
51
  </>
53
52
  );
54
53
  };
@@ -1,8 +1,8 @@
1
- import React, { ReactElement } from "react";
1
+ import React, { ReactElement, useContext, useEffect } from "react";
2
2
  import { Tags, Article } from "@bbki.ng/components";
3
3
  import { ROUTES } from "@/constants";
4
- import { DelayFadeIn } from "@/components/DelayFadeIn/DelayFadeIn";
5
4
  import classNames from "classnames";
5
+ import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
6
6
 
7
7
  export type ArticlePageProps = {
8
8
  tags?: string[];
@@ -13,8 +13,26 @@ export type ArticlePageProps = {
13
13
  children: ReactElement;
14
14
  };
15
15
 
16
+ const useSafeArticleLoading = (safeSec: number) => {
17
+ const { isLoading, isFontLoading } = useContext(GlobalLoadingContext);
18
+ const [isArticleLoading, setIsArticleLoading] = React.useState(true);
19
+
20
+ useEffect(() => {
21
+ const id = setTimeout(() => {
22
+ setIsArticleLoading(false);
23
+ }, safeSec * 1000);
24
+
25
+ return () => {
26
+ clearTimeout(id);
27
+ };
28
+ }, []);
29
+
30
+ return isLoading || isFontLoading || isArticleLoading;
31
+ };
32
+
16
33
  export const ArticlePage = (props: ArticlePageProps) => {
17
34
  const { tags: tagNames, title, description, headless } = props;
35
+ const loading = useSafeArticleLoading(0.2);
18
36
  const tags = tagNames
19
37
  ? tagNames.map((t) => ({ children: t, to: `${ROUTES.TAGS}/${t}` }))
20
38
  : [];
@@ -28,15 +46,16 @@ export const ArticlePage = (props: ArticlePageProps) => {
28
46
  });
29
47
 
30
48
  return (
31
- <DelayFadeIn delay={200}>
49
+ <>
32
50
  <Article
33
51
  title={title}
34
52
  description={description}
35
53
  className={props.className}
54
+ loading={loading}
36
55
  >
37
56
  <article className={articleCls}>{props.children}</article>
38
57
  </Article>
39
- {tagNames && <Tags tags={tags} />}
40
- </DelayFadeIn>
58
+ <span className="p-16">{tagNames && <Tags tags={tags} />}</span>
59
+ </>
41
60
  );
42
61
  };
@@ -3,6 +3,7 @@ import { ReactNode } from "react";
3
3
  import { PluginInputForm } from "@/components/plugin/PluginInputForm";
4
4
  import { useDependencies } from "@/components/plugin/hooks/useDependencies";
5
5
  import { PluginManager } from "@/plugin/PluginManager";
6
+ import PluginUI from "./pluginUI/PluginUI";
6
7
 
7
8
  export const PluginInit = (props: { children: ReactNode }) => {
8
9
  const {
@@ -11,6 +12,8 @@ export const PluginInit = (props: { children: ReactNode }) => {
11
12
  pluginInputFormConf,
12
13
  formDataResolver,
13
14
 
15
+ pluginUIRef,
16
+
14
17
  ...dep
15
18
  } = useDependencies();
16
19
 
@@ -45,6 +48,9 @@ export const PluginInit = (props: { children: ReactNode }) => {
45
48
  input={pluginInputFormConf}
46
49
  onSubmit={onSubmit}
47
50
  />
51
+ <PluginUI
52
+ ref={pluginUIRef}
53
+ />
48
54
  </>
49
55
  );
50
56
  };
@@ -19,8 +19,11 @@ export const PluginMenuItem = (props: PluginMenuItemProps) => {
19
19
  const { plugin, onUninstall, onStop, onRun, onInstall } = props;
20
20
  return (
21
21
  <ContextMenuSub>
22
- <ContextMenuSubTrigger inset>
23
- {plugin.name} v{plugin.version}
22
+ <ContextMenuSubTrigger>
23
+ <div className="flex justify-between w-full mr-16">
24
+ <span>{plugin.name}</span>
25
+ <span>v{plugin.version}</span>
26
+ </div>
24
27
  </ContextMenuSubTrigger>
25
28
  <ContextMenuSubContent className="w-48">
26
29
  {plugin.status !== PluginStatus.Available && (
@@ -13,6 +13,10 @@ interface depHooksRes extends Dependencies {
13
13
  isPluginFormInputOpen: boolean;
14
14
  pluginInputFormConf: PluginInput;
15
15
  formDataResolver: inputResolve;
16
+ pluginUIRef: React.MutableRefObject<{
17
+ open: boolean;
18
+ setHtml: (html: string) => void;
19
+ } | null>
16
20
  }
17
21
 
18
22
  export const useDependencies = (): depHooksRes => {
@@ -25,6 +29,8 @@ export const useDependencies = (): depHooksRes => {
25
29
 
26
30
  const globalRouteCtx = useContext(GlobalRoutesContext);
27
31
 
32
+ const pluginUIRef = useRef<{ open: boolean; setHtml: (html: string) => void } | null>(null);
33
+
28
34
  return {
29
35
  callPlugin: (id, method) => {
30
36
  if (!PluginManager.instance) {
@@ -48,6 +54,12 @@ export const useDependencies = (): depHooksRes => {
48
54
  position: "bottom-right",
49
55
  });
50
56
  },
57
+ showUI: (html: string) => {
58
+ if (!pluginUIRef.current) {
59
+ return;
60
+ }
61
+ pluginUIRef.current.setHtml(html);
62
+ },
51
63
  showForm: async (input) => {
52
64
  setOpen(true);
53
65
  setInput(input);
@@ -55,6 +67,7 @@ export const useDependencies = (): depHooksRes => {
55
67
  resolveRef.current = resolve;
56
68
  });
57
69
  },
70
+ pluginUIRef,
58
71
  setPluginFormInputOpen: setOpen,
59
72
  isPluginFormInputOpen: open,
60
73
  pluginInputFormConf: input,
@@ -9,7 +9,7 @@ export const usePluginOutput = (pluginId: number): string => {
9
9
  return;
10
10
  }
11
11
  PluginManager.instance.run(pluginId).then((result) => {
12
- setOutput(result);
12
+ setOutput(result as string);
13
13
  });
14
14
  }, [pluginId]);
15
15
 
@@ -0,0 +1,34 @@
1
+ import React, { useRef, useImperativeHandle, forwardRef } from "react"
2
+ import { PluginDrawer } from "../PluginDrawer"
3
+
4
+ export type PluginUIProps = {
5
+ html?: string,
6
+ }
7
+
8
+ const PluginUI = (props: PluginUIProps, ref: React.ForwardedRef<{ setHtml: (html: string) => void }>) => {
9
+ const iframeRef = useRef<HTMLIFrameElement>(null);
10
+ const [open, setOpen] = React.useState(false);
11
+ const [html, setHtml] = React.useState(props.html);
12
+
13
+ useImperativeHandle(ref, () => ({
14
+ setHtml: (h) => {
15
+ setHtml(h);
16
+ setOpen(true);
17
+ },
18
+ }), []);
19
+
20
+ return (
21
+ <PluginDrawer
22
+ open={open}
23
+ onOpenChange={setOpen}
24
+ >
25
+ <iframe
26
+ sandbox="allow-scripts allow-same-origin"
27
+ ref={iframeRef}
28
+ srcDoc={html}
29
+ />
30
+ </PluginDrawer>
31
+ )
32
+ }
33
+
34
+ export default forwardRef(PluginUI)
@@ -3,7 +3,7 @@ import { changeFont } from "@/utils";
3
3
  import { FontType } from "@/types/font";
4
4
 
5
5
  export const useFontLoading = () => {
6
- const [isFontLoading, setIsFontLoading] = useState(false);
6
+ const [isFontLoading, setIsFontLoading] = useState(true);
7
7
 
8
8
  const handleFontLoading = () => {
9
9
  setIsFontLoading(true);
@@ -41,7 +41,6 @@ export default () => {
41
41
  }
42
42
 
43
43
  if (ArticleMap[title]) {
44
- setIsLoading(false);
45
44
  return ArticleMap[title];
46
45
  }
47
46
 
@@ -4,6 +4,7 @@ export interface Dependencies {
4
4
  toast: (content: string) => void;
5
5
  loading: (show: boolean) => void;
6
6
  showForm: (input: PluginInput) => Promise<string>;
7
+ showUI: (html: string) => void;
7
8
  addRoute: (name: string, to: string) => void;
8
9
  removeRoute: (name: string) => void;
9
10
  callPlugin: (id: number, method: string) => Promise<any>;
@@ -16,8 +16,10 @@ export type PluginConfig = {
16
16
  description: string;
17
17
  url: string;
18
18
  status: PluginStatus;
19
+
19
20
  inputs?: PluginInput;
20
21
  route?: string;
22
+ builtIn?: boolean;
21
23
  };
22
24
 
23
25
  export enum PluginInputFieldType {
@@ -83,7 +85,8 @@ export class Plugin {
83
85
  return JSON.parse(out.text());
84
86
  } catch (e) {
85
87
  this.config.status = PluginStatus.Stopped;
86
- return out.text();
88
+ this.dependencies.loading(false);
89
+ return out?.text();
87
90
  }
88
91
  }
89
92
 
@@ -33,6 +33,8 @@ export class PluginManager {
33
33
  }
34
34
 
35
35
  private async restoreInstalledPlugins() {
36
+ await Promise.all(this.listBuiltIn().map((p) => this.install(p.id)));
37
+
36
38
  if (!this._info) {
37
39
  return Promise.resolve();
38
40
  }
@@ -61,7 +63,7 @@ export class PluginManager {
61
63
  window.pm = PluginManager.instance;
62
64
  }
63
65
 
64
- public async install(id: number) {
66
+ public async install(id: number, showToast?: boolean) {
65
67
  const config = this.pluginConfigMap.get(id);
66
68
  if (!config) {
67
69
  this.dependencies.toast("Plugin not found");
@@ -71,7 +73,10 @@ export class PluginManager {
71
73
  const plugin = new Plugin(config, this.dependencies);
72
74
  await plugin.install();
73
75
  this.plugins.set(id, plugin);
74
- this.dependencies.toast("Plugin installed");
76
+
77
+ if (showToast) {
78
+ this.dependencies.toast("Plugin installed");
79
+ }
75
80
 
76
81
  this.saveInfo();
77
82
  }
@@ -96,7 +101,11 @@ export class PluginManager {
96
101
  }
97
102
 
98
103
  public listAvailable(): PluginConfig[] {
99
- return Array.from(this.pluginConfigMap.values());
104
+ return Array.from(this.pluginConfigMap.values()).filter((p) => !p.builtIn);
105
+ }
106
+
107
+ public listBuiltIn(): PluginConfig[] {
108
+ return Array.from(this.pluginConfigMap.values()).filter((p) => p.builtIn);
100
109
  }
101
110
 
102
111
  public getPlugin(id: number) {
@@ -148,6 +157,16 @@ export class PluginManager {
148
157
  route: "近况",
149
158
  });
150
159
 
160
+ // this.pluginConfigMap.set(2, {
161
+ // name: "core",
162
+ // id: 2,
163
+ // version: "1.0.0",
164
+ // description: "core",
165
+ // url: "https://zjh-im-res.oss-cn-shenzhen.aliyuncs.com/plugins/reactable.core.wasm",
166
+ // status: 0,
167
+ // builtIn: true,
168
+ // })
169
+
151
170
  return this.pluginConfigMap;
152
171
  }
153
172
  }