diff --git a/web/.ministarrc.js b/web/.ministarrc.js
index ee2f50c8..927cffaa 100644
--- a/web/.ministarrc.js
+++ b/web/.ministarrc.js
@@ -18,6 +18,14 @@ module.exports = {
),
dest: path.resolve(__dirname, `./dist/plugins/${pluginName}/assets/`),
},
+ {
+ src: path.resolve(
+ __dirname,
+ `./plugins/${pluginName}`,
+ './docs/**/*'
+ ),
+ dest: path.resolve(__dirname, `./dist/plugins/${pluginName}/docs/`),
+ },
{
src: path.resolve(
__dirname,
diff --git a/web/plugins/com.msgbyte.miaolang/README.md b/web/plugins/com.msgbyte.miaolang/README.md
new file mode 100644
index 00000000..83ce9788
--- /dev/null
+++ b/web/plugins/com.msgbyte.miaolang/README.md
@@ -0,0 +1,11 @@
+## 喵语翻译
+
+允许用户将自然语言转换为加密后的喵语
+
+在任意聊天款的右侧添加喵语翻译
+
+
+
+在此输入的任意内容都会被转换为加密后的喵语言,只有安装了相同插件的用户才能翻译
+
+
diff --git a/web/plugins/com.msgbyte.miaolang/docs/output.png b/web/plugins/com.msgbyte.miaolang/docs/output.png
new file mode 100644
index 00000000..beb16e14
Binary files /dev/null and b/web/plugins/com.msgbyte.miaolang/docs/output.png differ
diff --git a/web/plugins/com.msgbyte.miaolang/docs/send.png b/web/plugins/com.msgbyte.miaolang/docs/send.png
new file mode 100644
index 00000000..a1eec82a
Binary files /dev/null and b/web/plugins/com.msgbyte.miaolang/docs/send.png differ
diff --git a/web/plugins/com.msgbyte.miaolang/manifest.json b/web/plugins/com.msgbyte.miaolang/manifest.json
index 9c9d9b2c..9d2e1f48 100644
--- a/web/plugins/com.msgbyte.miaolang/manifest.json
+++ b/web/plugins/com.msgbyte.miaolang/manifest.json
@@ -5,5 +5,6 @@
"version": "0.0.0",
"author": "msgbyte",
"description": "为聊天提供喵语言对话功能",
+ "documentUrl": "/plugins/com.msgbyte.miaolang/README.md",
"requireRestart": true
}
diff --git a/web/registry.json b/web/registry.json
index ec91653b..92a13bd2 100644
--- a/web/registry.json
+++ b/web/registry.json
@@ -6,6 +6,7 @@
"version": "0.0.0",
"author": "msgbyte",
"description": "为聊天提供喵语言对话功能",
+ "documentUrl": "/plugins/com.msgbyte.miaolang/README.md",
"requireRestart": true
},
{
diff --git a/web/src/components/ErrorBoundary.tsx b/web/src/components/ErrorBoundary.tsx
index 8a4ad8a0..8e2bb424 100644
--- a/web/src/components/ErrorBoundary.tsx
+++ b/web/src/components/ErrorBoundary.tsx
@@ -1,3 +1,56 @@
-import { Alert } from 'antd';
+import React from 'react';
+import { t } from 'tailchat-shared';
+import { Problem } from './Problem';
-export const ErrorBoundary = Alert.ErrorBoundary;
+interface ErrorBoundaryProps {
+ message?: React.ReactNode;
+ description?: string;
+}
+
+export class ErrorBoundary extends React.Component<
+ ErrorBoundaryProps,
+ {
+ error?: Error | null;
+ info: {
+ componentStack?: string;
+ };
+ }
+> {
+ state = {
+ error: undefined,
+ info: {
+ componentStack: '',
+ },
+ };
+
+ componentDidCatch(error: Error | null, info: any) {
+ this.setState({ error, info });
+ }
+
+ render() {
+ const { message, description, children } = this.props;
+ const { error, info } = this.state;
+ const componentStack =
+ info && info.componentStack ? info.componentStack : null;
+ const errorMessage =
+ typeof message === 'undefined' ? (error || '').toString() : message;
+ const errorDescription =
+ typeof description === 'undefined' ? componentStack : description;
+ if (error) {
+ return (
+
+
+ {t('页面出现了一些问题')}
+ {errorMessage}
+ >
+ }
+ />
+
+ );
+ }
+
+ return children;
+ }
+}
diff --git a/web/src/components/Markdown.less b/web/src/components/Markdown.less
index 19849981..a93469bf 100644
--- a/web/src/components/Markdown.less
+++ b/web/src/components/Markdown.less
@@ -15,4 +15,8 @@
code {
@apply px-2 py-1 bg-black bg-opacity-20 rounded;
}
+
+ p {
+ @apply my-2;
+ }
}
diff --git a/web/src/components/Markdown.tsx b/web/src/components/Markdown.tsx
index 192d63f3..d0a6b8f6 100644
--- a/web/src/components/Markdown.tsx
+++ b/web/src/components/Markdown.tsx
@@ -1,3 +1,4 @@
+import { markAbsoluteUrl } from '@/utils/url-helper';
import React, { useCallback } from 'react';
import { isValidStr } from 'tailchat-shared';
import { Loadable } from './Loadable';
@@ -17,7 +18,7 @@ export const Markdown: React.FC<{
return url;
}
- return new URL(url, baseUrl).href;
+ return new URL(url, markAbsoluteUrl(baseUrl)).href;
},
[baseUrl]
);
diff --git a/web/src/components/Modal.tsx b/web/src/components/Modal.tsx
index fadc3ae2..198fe736 100644
--- a/web/src/components/Modal.tsx
+++ b/web/src/components/Modal.tsx
@@ -11,9 +11,10 @@ import { Icon } from '@/components/Icon';
import { CSSTransition } from 'react-transition-group';
import clsx from 'clsx';
import { useIsMobile } from '@/hooks/useIsMobile';
+import { stopPropagation } from '@/utils/dom-helper';
+import { ErrorBoundary } from './ErrorBoundary';
import './Modal.less';
-import { stopPropagation } from '@/utils/dom-helper';
const transitionEndListener = (node: HTMLElement, done: () => void) =>
node.addEventListener('transitionend', done, false);
@@ -101,7 +102,8 @@ export const Modal: React.FC = React.memo((props) => {
onClick={closeModal}
/>
)}
- {props.children}
+
+ {props.children}
diff --git a/web/src/plugin/PluginStore/DocumentView/DocumentMarkdownRender.tsx b/web/src/plugin/PluginStore/DocumentView/DocumentMarkdownRender.tsx
index d264fedc..0a36b661 100644
--- a/web/src/plugin/PluginStore/DocumentView/DocumentMarkdownRender.tsx
+++ b/web/src/plugin/PluginStore/DocumentView/DocumentMarkdownRender.tsx
@@ -24,7 +24,7 @@ export const DocumentMarkdownRender: React.FC<{ url: string }> = React.memo(
return ;
}
- return ;
+ return ;
}
);
DocumentMarkdownRender.displayName = 'DocumentMarkdownRender';
diff --git a/web/src/utils/__tests__/url-helper.spec.ts b/web/src/utils/__tests__/url-helper.spec.ts
new file mode 100644
index 00000000..a3765703
--- /dev/null
+++ b/web/src/utils/__tests__/url-helper.spec.ts
@@ -0,0 +1,14 @@
+import { markAbsoluteUrl } from '../url-helper';
+
+describe('markAbsoluteUrl', () => {
+ test.each([
+ ['bar', 'https://www.example.com/foo/bar'],
+ ['./bar', 'https://www.example.com/foo/bar'],
+ ['../bar', 'https://www.example.com/bar'],
+ ['/bar', 'https://www.example.com/bar'],
+ ['https://www.baidu.com', 'https://www.baidu.com/'],
+ ['https://www.baidu.com/search', 'https://www.baidu.com/search'],
+ ])('%s', (input, output) => {
+ expect(markAbsoluteUrl(input)).toBe(output);
+ });
+});
diff --git a/web/src/utils/url-helper.ts b/web/src/utils/url-helper.ts
new file mode 100644
index 00000000..9de60d10
--- /dev/null
+++ b/web/src/utils/url-helper.ts
@@ -0,0 +1,8 @@
+/**
+ * 根据输入url返回绝对url
+ * @param relativeUrl 相对或绝对url
+ * @returns 绝对url
+ */
+export function markAbsoluteUrl(relativeUrl: string): string {
+ return new URL(relativeUrl, location.href).href;
+}
diff --git a/web/test/setup.js b/web/test/setup.js
index 81851bfd..e2bde2e1 100644
--- a/web/test/setup.js
+++ b/web/test/setup.js
@@ -19,3 +19,7 @@ console.error = (...args) => {
originalError.call(console, ...args);
};
+
+// Mock location
+delete window.location;
+window.location = new URL('https://www.example.com/foo/index');