优化
This commit is contained in:
1
apps/widget/.gitignore
vendored
Normal file
1
apps/widget/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
lib/
|
||||
3
apps/widget/.yarnrc
Normal file
3
apps/widget/.yarnrc
Normal file
@@ -0,0 +1,3 @@
|
||||
registry "https://registry.npmjs.org"
|
||||
version-tag-prefix "widget-v"
|
||||
version-git-message "widget-v%s"
|
||||
1
apps/widget/demo/.gitignore
vendored
Normal file
1
apps/widget/demo/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.parcel-cache/
|
||||
22
apps/widget/demo/index.html
Normal file
22
apps/widget/demo/index.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tailchat Widget Demo</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="module">
|
||||
import { createTailchatWidget } from '../lib/index.js';
|
||||
|
||||
createTailchatWidget({
|
||||
groupId: '611e4e18d3e846001bd0223a',
|
||||
panelId: '611e4e18d3e846001bd02239',
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
19
apps/widget/demo/package.json
Normal file
19
apps/widget/demo/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "tailchat-widget-demo",
|
||||
"version": "1.0.0",
|
||||
"source": "index.html",
|
||||
"main": "dist/index.js",
|
||||
"repository": "https://github.com/msgbyte/tailchat.git",
|
||||
"author": "moonrailgun <moonrailgun@gmail.com>",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "parcel serve index.html --no-cache"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"parcel": "^2.0.0"
|
||||
}
|
||||
}
|
||||
4535
apps/widget/demo/yarn.lock
Normal file
4535
apps/widget/demo/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
20
apps/widget/package.json
Normal file
20
apps/widget/package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "tailchat-widget",
|
||||
"version": "0.0.8",
|
||||
"main": "lib/index.js",
|
||||
"repository": "https://github.com/msgbyte/tailchat.git",
|
||||
"author": "moonrailgun <moonrailgun@gmail.com>",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/index.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"watch": "tsc --watch",
|
||||
"build": "tsc",
|
||||
"release": "yarn publish --patch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^4.8.2"
|
||||
}
|
||||
}
|
||||
136
apps/widget/src/index.ts
Normal file
136
apps/widget/src/index.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
export interface TailchatWidgetOptions {
|
||||
/**
|
||||
* @default https://nightly.paw.msgbyte.com/
|
||||
*/
|
||||
host?: string;
|
||||
groupId: string;
|
||||
panelId: string;
|
||||
widgetStyle?: Partial<CSSStyleDeclaration>;
|
||||
iconStyle?: Partial<CSSStyleDeclaration>;
|
||||
frameStyle?: Partial<CSSStyleDeclaration>;
|
||||
}
|
||||
|
||||
const defaultTailchatWidgetOptions: Partial<TailchatWidgetOptions> = {
|
||||
host: 'https://nightly.paw.msgbyte.com',
|
||||
};
|
||||
|
||||
const defaultWidgetStyle: Partial<CSSStyleDeclaration> = {
|
||||
position: 'absolute',
|
||||
right: '20px',
|
||||
bottom: '20px',
|
||||
};
|
||||
|
||||
const iconContainerSize = 48;
|
||||
const defaultIconContainerStyle: Partial<CSSStyleDeclaration> = {
|
||||
width: `${iconContainerSize}px`,
|
||||
height: `${iconContainerSize}px`,
|
||||
boxShadow: '0 1px 4px rgba(0, 0, 0, 0.2)',
|
||||
borderRadius: '50%',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
};
|
||||
|
||||
const defaultFrameStyle: Partial<CSSStyleDeclaration> = {
|
||||
width: '414px',
|
||||
height: '736px',
|
||||
border: '0',
|
||||
borderRadius: '3px',
|
||||
boxShadow: '0 1px 4px rgba(0, 0, 0, 0.2)',
|
||||
};
|
||||
|
||||
const iconSize = 32;
|
||||
const iconSvg = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="${iconSize}" height="${iconSize}" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M12 3C6.5 3 2 6.58 2 11a7.218 7.218 0 0 0 2.75 5.5c0 .6-.42 2.17-2.75 4.5c2.37-.11 4.64-1 6.47-2.5c1.14.33 2.34.5 3.53.5c5.5 0 10-3.58 10-8s-4.5-8-10-8m0 14c-4.42 0-8-2.69-8-6s3.58-6 8-6s8 2.69 8 6s-3.58 6-8 6m5-5v-2h-2v2h2m-4 0v-2h-2v2h2m-4 0v-2H7v2h2z" fill="currentColor"/></svg>`;
|
||||
const closeIconSvg = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="${iconSize}" height="${iconSize}" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" style="display: block;"><path d="M11 4h2v12l5.5-5.5l1.42 1.42L12 19.84l-7.92-7.92L5.5 10.5L11 16V4z" fill="currentColor"/></svg>`;
|
||||
|
||||
/**
|
||||
* 创建聊天小部件
|
||||
*/
|
||||
export function createTailchatWidget(_options: TailchatWidgetOptions) {
|
||||
const options = { ...defaultTailchatWidgetOptions, ..._options };
|
||||
|
||||
const url = `${options.host}/panel/group/${options.groupId}/${options.panelId}`;
|
||||
|
||||
// 容器
|
||||
const container = document.createElement('div');
|
||||
applyStyle(container, {
|
||||
...defaultWidgetStyle,
|
||||
..._options.widgetStyle,
|
||||
});
|
||||
|
||||
// 图标
|
||||
const iconContainer = document.createElement('div');
|
||||
applyStyle(iconContainer, {
|
||||
...defaultIconContainerStyle,
|
||||
..._options.iconStyle,
|
||||
});
|
||||
iconContainer.innerHTML = iconSvg;
|
||||
container.appendChild(iconContainer);
|
||||
|
||||
// Iframe 容器
|
||||
let frameContainer: HTMLDivElement | null = null;
|
||||
iconContainer.addEventListener('click', () => {
|
||||
// 展开iframe
|
||||
if (!frameContainer) {
|
||||
// 元素不存在
|
||||
|
||||
// 容器
|
||||
const _frameContainer = document.createElement('div');
|
||||
frameContainer = _frameContainer;
|
||||
|
||||
// Iframe
|
||||
const frameEl = document.createElement('iframe');
|
||||
frameEl.src = url;
|
||||
applyStyle(frameEl, {
|
||||
...defaultFrameStyle,
|
||||
..._options.frameStyle,
|
||||
});
|
||||
|
||||
// closeBtn
|
||||
const closeBtnEl = document.createElement('div');
|
||||
closeBtnEl.innerHTML = closeIconSvg;
|
||||
applyStyle(closeBtnEl, {
|
||||
position: 'absolute',
|
||||
right: '0',
|
||||
top: `-${iconSize}px`,
|
||||
backgroundColor: 'white',
|
||||
cursor: 'pointer',
|
||||
boxShadow: '0px -1px 4px rgba(0, 0, 0, 0.2)',
|
||||
borderRadius: '50% 50% 0 0',
|
||||
});
|
||||
closeBtnEl.addEventListener('click', () => {
|
||||
// 关闭操作
|
||||
iconContainer.style.display = 'flex';
|
||||
if (frameContainer) {
|
||||
frameContainer.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
_frameContainer.appendChild(frameEl);
|
||||
_frameContainer.appendChild(closeBtnEl);
|
||||
container.appendChild(_frameContainer);
|
||||
} else {
|
||||
// 已创建
|
||||
frameContainer.style.display = 'block';
|
||||
}
|
||||
|
||||
iconContainer.style.display = 'none';
|
||||
});
|
||||
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用样式到元素
|
||||
* @param el 元素
|
||||
* @param styles 样式
|
||||
*/
|
||||
function applyStyle(el: HTMLElement, styles: Partial<CSSStyleDeclaration>) {
|
||||
for (const key in styles) {
|
||||
const val = styles[key];
|
||||
if (typeof val === 'string') {
|
||||
el.style[key] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
apps/widget/tsconfig.json
Normal file
9
apps/widget/tsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES5",
|
||||
"declaration": true,
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"rootDir": "./src",
|
||||
"outDir": "lib"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user