Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
431 changes: 431 additions & 0 deletions web/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"dev": "next dev",
"build": "next build && npm run build:widget",
"build:widget": "node widget-build.js",
"dev:widget": "node widget-build.js --watch",
"start": "next start",
"lint": "next lint"
},
Expand Down
2 changes: 1 addition & 1 deletion web/public/koala-chat-widget.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions web/public/koala-chat-widget.js.map

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions web/samples/widget.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KoalaWiki Chat Widget 测试</title>
<style>
body {
font-family: 'Arial', sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
h1 {
color: #333;
border-bottom: 1px solid #eee;
padding-bottom: 10px;
}
.content {
margin-top: 20px;
}
</style>
</head>
<body>
<h1>KoalaWiki Chat Widget 测试页面</h1>

<div class="content">
<p>这是一个简单的测试页面,展示了 KoalaWiki 聊天悬浮球组件的基本用法。</p>
<p>右下角应该会出现聊天悬浮球按钮。</p>
</div>

<script src="../public/koala-chat-widget.js"></script>

<script>
KoalaChatWidget.init({
appId: 'app_mcpx2xlc_udcn5c',
title: 'AI 助手',
apiUrl: 'https://opendeep.wiki',
theme: 'light'
});
</script>
</body>
</html>
83 changes: 68 additions & 15 deletions web/widget-build.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
/**
* esbuild 配置文件
* 用于打包 widget 代码并压缩内联 CSS
* esbuild 统一构建脚本
* 支持普通构建和监视模式
*
* 使用方式:
* - node widget-build.js # 普通构建模式
* - node widget-build.js --watch # 监视模式
*/

const esbuild = require('esbuild');
const fs = require('fs');
const path = require('path');

// 检查是否为监视模式
const isWatchMode = process.argv.includes('--watch');

// CSS 压缩函数
function minifyCSS(css) {
return css
Expand Down Expand Up @@ -41,24 +48,70 @@ const cssMinifierPlugin = {
}
};

// 打包配置
async function build() {
// 构建配置
const buildOptions = {
entryPoints: ['widget/index.ts'],
bundle: true,
minify: true,
sourcemap: true,
platform: 'browser',
outfile: 'public/koala-chat-widget.js',
plugins: [cssMinifierPlugin],
};

// 监视模式
async function watchBuild() {
try {
const result = await esbuild.build({
entryPoints: ['widget/index.ts'],
bundle: true,
minify: true,
sourcemap: true,
platform: 'browser',
outfile: 'public/koala-chat-widget.js',
plugins: [cssMinifierPlugin],
const ctx = await esbuild.context({
...buildOptions,
plugins: [
...buildOptions.plugins,
{
name: 'watch-plugin',
setup(build) {
build.onEnd(result => {
if (result.errors.length > 0) {
console.error('❌ Build failed:', result.errors);
} else {
const timestamp = new Date().toLocaleTimeString();
console.log(`🔄 [${timestamp}] File change detected, rebuild successful`);
}
});
},
},
],
});

console.log('✅ Widget 构建成功');
// 启动监视模式
await ctx.watch();

console.log('👀 Watching widget files for changes...');
console.log('✅ Initial build complete');
console.log('📝 Changes to files in widget/ directory will trigger automatic rebuild');
console.log('💡 Press Ctrl+C to stop watching');

// 保持进程运行
await new Promise(() => {}); // 永不解决的 Promise
} catch (error) {
console.error('❌ Widget watch mode failed to start:', error);
process.exit(1);
}
}

// 单次构建
async function singleBuild() {
try {
await esbuild.build(buildOptions);
console.log('✅ Widget build successful');
} catch (error) {
console.error('❌ Widget 构建失败:', error);
console.error('❌ Widget build failed:', error);
process.exit(1);
}
}

build();
// 根据模式执行不同的构建函数
if (isWatchMode) {
watchBuild();
} else {
singleBuild();
}
17 changes: 10 additions & 7 deletions web/widget/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
* <script src="https://your-domain.com/koala-chat-widget.js"></script>
* <script>
* KoalaChatWidget.init({
* appId: 'your-app-id',
* organizationName: 'your-org',
* repositoryName: 'your-repo',
* title: '我的 AI 助手',
* expandIcon: 'base64-icon-data',
* closeIcon: 'base64-icon-data',
* apiUrl: 'https://your-api-domain.com'
* appId: 'your-app-id', // 必填:应用ID,用于验证域名
* apiUrl: 'https://opendeep.wiki', // 必填:API服务器地址
*
* // 以下参数都是可选的
* title: '我的 AI 助手', // 可选:标题(可能被验证接口返回的配置覆盖)
* theme: 'light', // 可选:主题 'light'|'dark'
*
* // UI自定义
* expandIcon: null, // 可选:展开图标
* closeIcon: null, // 可选:关闭图标
* });
* </script>
*/
Expand Down
18 changes: 18 additions & 0 deletions web/widget/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface KoalaChatWidgetConfig {
tooltipDuration?: number;
tooltipRepeatDelay?: number;
onError?: (errorMessage: string) => void;
onValidationFailed?: (domain: string) => void;
}

/**
Expand All @@ -30,6 +31,23 @@ export interface KoalaChatWidgetAPI {
toggle(): void;
}

export interface ValidationResponse {
isValid: boolean;
reason?: string;
appConfig?: {
appId: string;
name?: string;
isEnabled: boolean;
organizationName: string;
repositoryName: string;
allowedDomains: string[];
enableDomainValidation: boolean;
description?: string;
createdAt?: Date;
updatedAt?: Date;
};
}

// 声明全局Window接口扩展
declare global {
interface Window {
Expand Down