@bbki.ng/site 1.8.4 → 1.8.6

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.6
4
+
5
+ ## 1.8.5
6
+
3
7
  ## 1.8.4
4
8
 
5
9
  ## 1.8.3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbki.ng/site",
3
- "version": "1.8.4",
3
+ "version": "1.8.6",
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.3",
20
+ "@bbki.ng/components": "workspace:2.6.5",
21
21
  "@supabase/supabase-js": "^1.35.4",
22
22
  "classnames": "2.3.1",
23
23
  "react": "^18.0.0",
@@ -3,6 +3,7 @@ import { Tags, Article } from "@bbki.ng/components";
3
3
  import { ROUTES } from "@/constants";
4
4
  import classNames from "classnames";
5
5
  import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
6
+ import { useSafeArticleLoading } from "@/hooks/use_safe_loading";
6
7
 
7
8
  export type ArticlePageProps = {
8
9
  tags?: string[];
@@ -13,26 +14,9 @@ export type ArticlePageProps = {
13
14
  children: ReactElement;
14
15
  };
15
16
 
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
-
33
17
  export const ArticlePage = (props: ArticlePageProps) => {
34
18
  const { tags: tagNames, title, description, headless } = props;
35
- const loading = useSafeArticleLoading(0.2);
19
+ const loading = useSafeArticleLoading(0.2, 5);
36
20
  const tags = tagNames
37
21
  ? tagNames.map((t) => ({ children: t, to: `${ROUTES.TAGS}/${t}` }))
38
22
  : [];
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { LinkList } from "@bbki.ng/components";
3
+ import { BlurCover } from "@bbki.ng/components";
3
4
  import { DelayFadeIn } from "@/components/DelayFadeIn/DelayFadeIn";
4
5
 
5
6
  export { DisabledText, SmallDisabledText } from "./disabled_text";
@@ -30,10 +31,9 @@ export { MySuspense } from "./my_suspense";
30
31
 
31
32
  export const CenterLinkList = (props: any) => {
32
33
  return (
33
- <div className="flex justify-center">
34
- <DelayFadeIn delay={200}>
35
- <LinkList {...props} />
36
- </DelayFadeIn>
34
+ <div className="flex justify-center relative p-16">
35
+ <LinkList {...props} />
36
+ <BlurCover status={props.loading ? "show" : "silent"} />
37
37
  </div>
38
38
  );
39
39
  };
@@ -1,25 +1,47 @@
1
1
  import { ArticlePage, ArticlePageProps } from "@/components/article";
2
- import React, { memo } from "react";
2
+ import React, { useCallback, useEffect } from "react";
3
3
  import { threeColWrapper } from "@/components/with_wrapper";
4
4
  import { useParams } from "react-router-dom";
5
5
  import { usePluginOutput } from "@/components/plugin/hooks/usePluginOutput";
6
6
  import { PluginManager } from "@/plugin/PluginManager";
7
+ import { PluginConfig } from "@extism/extism";
8
+ import { PluginEvent } from "@/plugin/PluginEvent";
7
9
 
8
10
  type PluginContentPageProps = Omit<ArticlePageProps, "children">;
9
11
 
10
12
  const ContentPage = (props: PluginContentPageProps) => {
11
13
  const { pluginRoute } = useParams();
12
14
 
13
- if (!pluginRoute || !PluginManager.instance) {
14
- return null;
15
- }
15
+ const [c, setC] = React.useState<string>("");
16
16
 
17
- const plugin = PluginManager.instance.getPluginByRoute(pluginRoute);
18
- if (!plugin) {
19
- return null;
20
- }
17
+ const onInstall = useCallback((plugin: PluginConfig) => {
18
+ if (plugin.route !== pluginRoute) {
19
+ return;
20
+ }
21
+
22
+ PluginManager.instance.run(plugin.id).then((result) => {
23
+ setC(result);
24
+ });
25
+ }, []);
26
+
27
+ useEffect(() => {
28
+ PluginManager.addEventListener<PluginConfig>(
29
+ PluginEvent.INSTALL,
30
+ onInstall
31
+ );
32
+
33
+ return () => {
34
+ PluginManager.removeEventListener<PluginConfig>(
35
+ PluginEvent.INSTALL,
36
+ onInstall
37
+ );
38
+ };
39
+ }, []);
40
+
41
+ const plugin = PluginManager.instance?.getPluginByRoute(pluginRoute || "");
42
+
43
+ const content = usePluginOutput(plugin?.config.id) || c;
21
44
 
22
- const content = usePluginOutput(plugin.config.id);
23
45
  return (
24
46
  <ArticlePage {...props} title={plugin?.config.route || ""}>
25
47
  <div dangerouslySetInnerHTML={{ __html: content }} />
@@ -2,12 +2,22 @@ import { threeColWrapper } from "@/components/with_wrapper";
2
2
  import { CenterLinkList } from "@/components";
3
3
  import React, { useContext } from "react";
4
4
  import { GlobalRoutesContext } from "@/context/global_routes_provider";
5
+ import { useSafeArticleLoading } from "@/hooks/use_safe_loading";
5
6
 
6
7
  const PluginRoutesContent = () => {
7
8
  const globalRouteCtx = useContext(GlobalRoutesContext);
8
9
  const routes = globalRouteCtx.globalRoutes;
9
10
 
10
- return <CenterLinkList className="select-none" links={routes} title="" />;
11
+ const isLoading = useSafeArticleLoading(0.2, 3);
12
+
13
+ return (
14
+ <CenterLinkList
15
+ className="select-none"
16
+ links={routes}
17
+ title=""
18
+ loading={isLoading}
19
+ />
20
+ );
11
21
  };
12
22
 
13
23
  export const PluginRoutes = threeColWrapper(PluginRoutesContent);
@@ -1,7 +1,7 @@
1
1
  import { PluginManager } from "@/plugin/PluginManager";
2
2
  import { useEffect, useState } from "react";
3
3
 
4
- export const usePluginOutput = (pluginId: number): string => {
4
+ export const usePluginOutput = (pluginId?: number): string => {
5
5
  const [output, setOutput] = useState<string>("");
6
6
 
7
7
  useEffect(() => {
@@ -0,0 +1,29 @@
1
+ import React, { useContext, useEffect } from "react";
2
+ import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
3
+
4
+ export const useSafeArticleLoading = (safeSec: number, timeOutSec: number) => {
5
+ const { isLoading, isFontLoading } = useContext(GlobalLoadingContext);
6
+ const [isArticleLoading, setIsArticleLoading] = React.useState(true);
7
+ const [isTimeout, setIsTimeout] = React.useState(false);
8
+
9
+ useEffect(() => {
10
+ const id = setTimeout(() => {
11
+ setIsArticleLoading(false);
12
+ }, safeSec * 1000);
13
+
14
+ const timeoutId = setTimeout(() => {
15
+ setIsTimeout(true);
16
+ }, timeOutSec * 1000);
17
+
18
+ return () => {
19
+ clearTimeout(id);
20
+ clearTimeout(timeoutId);
21
+ };
22
+ }, []);
23
+
24
+ if (isTimeout) {
25
+ return false;
26
+ }
27
+
28
+ return isLoading || isFontLoading || isArticleLoading;
29
+ };
@@ -6,6 +6,7 @@ import { CenterLinkList } from "@/components";
6
6
  import { useAuthed } from "@/hooks/use_authed";
7
7
  import { useFile2Post } from "@/hooks/use_file_to_post";
8
8
  import { DelayFadeIn } from "@/components/DelayFadeIn/DelayFadeIn";
9
+ import { useSafeArticleLoading } from "@/hooks/use_safe_loading";
9
10
 
10
11
  type TxtProps = {
11
12
  title?: string;
@@ -15,6 +16,8 @@ type TxtProps = {
15
16
  const Posts = (props: TxtProps) => {
16
17
  const { titleList, isLoading, isError } = usePosts();
17
18
 
19
+ const isGlobalLoading = useSafeArticleLoading(0.2, 5);
20
+
18
21
  if (isLoading) {
19
22
  return null;
20
23
  }
@@ -25,7 +28,12 @@ const Posts = (props: TxtProps) => {
25
28
 
26
29
  const links = [...titleList, ...ArticleList];
27
30
 
28
- return <CenterLinkList links={props.articleList || links} />;
31
+ return (
32
+ <CenterLinkList
33
+ links={props.articleList || links}
34
+ loading={isGlobalLoading}
35
+ />
36
+ );
29
37
  };
30
38
 
31
39
  export default (props: TxtProps) => {
@@ -0,0 +1,5 @@
1
+ export enum PluginEvent {
2
+ INIT = "init",
3
+ INSTALL = "installed",
4
+ UNINSTALL = "uninstalled",
5
+ }
@@ -1,6 +1,7 @@
1
- import { Plugin, PluginConfig, PluginInputFieldType } from "./Plugin";
1
+ import { Plugin, PluginConfig } from "./Plugin";
2
2
  import { Dependencies } from "@/plugin/Dependencies";
3
3
  import { PluginManagerPayload } from "@/plugin/PluginManagerPayload";
4
+ import { PluginEvent } from "@/plugin/PluginEvent";
4
5
 
5
6
  export class PluginManager {
6
7
  private readonly dependencies: Dependencies;
@@ -46,6 +47,22 @@ export class PluginManager {
46
47
 
47
48
  static instance: PluginManager;
48
49
 
50
+ static dispatchEvent<T>(evt: PluginEvent, data: T) {
51
+ window.dispatchEvent(new CustomEvent(evt, { detail: data }));
52
+ }
53
+
54
+ static addEventListener<T>(evt: PluginEvent, cb: (data: T) => void) {
55
+ window.addEventListener(evt, (e) => {
56
+ cb((e as CustomEvent<T>).detail);
57
+ });
58
+ }
59
+
60
+ static removeEventListener<T>(evt: PluginEvent, cb: (data: T) => void) {
61
+ window.removeEventListener(evt, (e) => {
62
+ cb((e as CustomEvent<T>).detail);
63
+ });
64
+ }
65
+
49
66
  static async init(dependencies: Dependencies) {
50
67
  if (PluginManager.instance) {
51
68
  return;
@@ -56,7 +73,8 @@ export class PluginManager {
56
73
  await PluginManager.instance.fetchPluginConfig();
57
74
  await PluginManager.instance.restoreInstalledPlugins();
58
75
  dependencies.loading(false);
59
- dependencies.toast("Plugin manager initialized");
76
+ // dependencies.toast("Plugin manager initialized");
77
+ PluginManager.dispatchEvent<null>(PluginEvent.INIT, null);
60
78
 
61
79
  // @ts-ignore
62
80
  // expose plugin manager to window for debugging
@@ -78,6 +96,9 @@ export class PluginManager {
78
96
  this.dependencies.toast("Plugin installed");
79
97
  }
80
98
 
99
+ // dispatch event
100
+ PluginManager.dispatchEvent<PluginConfig>(PluginEvent.INSTALL, config);
101
+
81
102
  this.saveInfo();
82
103
  }
83
104
 
@@ -93,6 +114,9 @@ export class PluginManager {
93
114
  this.plugins.delete(id);
94
115
  this.dependencies.toast("Plugin uninstalled");
95
116
 
117
+ // dispatch event
118
+ PluginManager.dispatchEvent<PluginConfig>(PluginEvent.UNINSTALL, plugin);
119
+
96
120
  this.saveInfo();
97
121
  }
98
122