chore: move tailchat-website into tailchat
@ -0,0 +1,53 @@
|
|||||||
|
name: "Deployment Website"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- "./website/**"
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [16.x]
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: website
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
- name: Cache pnpm modules
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/.pnpm-store
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-
|
||||||
|
- uses: pnpm/action-setup@v2.0.1
|
||||||
|
with:
|
||||||
|
version: 6.0.2
|
||||||
|
run_install: true
|
||||||
|
- name: Install Packages
|
||||||
|
run: pnpm install
|
||||||
|
- name: Build page
|
||||||
|
run: pnpm build
|
||||||
|
# - name: Deploy to gh-pages
|
||||||
|
# uses: peaceiris/actions-gh-pages@v3
|
||||||
|
# with:
|
||||||
|
# github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
# publish_dir: ./website/build
|
||||||
|
- name: Deploy to Vercel
|
||||||
|
uses: amondnet/vercel-action@master
|
||||||
|
env:
|
||||||
|
VERSION: ${{ env.GITHUB_SHA }}
|
||||||
|
with:
|
||||||
|
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
||||||
|
vercel-org-id: ${{ secrets.ORG_ID}}
|
||||||
|
vercel-project-id: ${{ secrets.PROJECT_ID}}
|
||||||
|
working-directory: ./
|
||||||
|
vercel-args: '--prod'
|
@ -0,0 +1,55 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Language" content="zh-CN" />
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-container {
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-iframe {
|
||||||
|
width: 640px;
|
||||||
|
height: 360px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 966px) {
|
||||||
|
.video-iframe {
|
||||||
|
width: 360px;
|
||||||
|
height: 240px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
Tailchat Nightly
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<h3>
|
||||||
|
Tailchat 演示环境
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p>如果有任何反馈欢迎直接在本群组 @moonrailgun 或者发送邮件到 <a href="mailto:moonrailgun@gmail.com">moonrailgun@gmail.com</a></p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
官方文档: <a href="https://tailchat.msgbyte.com/">https://tailchat.msgbyte.com/</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
开源地址: <a href="https://github.com/msgbyte/tailchat">https://github.com/msgbyte/tailchat</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="video-container">
|
||||||
|
<h2>演示视频</h2>
|
||||||
|
<iframe class="video-iframe" src="https://player.bilibili.com/player.html?aid=340398093&bvid=BV1394y1Z76n&cid=568332564&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,20 @@
|
|||||||
|
# Dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# Production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.docusaurus
|
||||||
|
.cache-loader
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.DS_Store
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
@ -0,0 +1,2 @@
|
|||||||
|
# https://npmmirror.com/
|
||||||
|
registry = https://registry.npmmirror.com
|
@ -0,0 +1,3 @@
|
|||||||
|
# Tailchat Document
|
||||||
|
|
||||||
|
一个开放的即时通讯聊天应用
|
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
|
||||||
|
};
|
@ -0,0 +1,6 @@
|
|||||||
|
moonrailgun:
|
||||||
|
name: moonrailgun
|
||||||
|
title: Tailchat 开发者
|
||||||
|
url: https://github.com/moonrailgun
|
||||||
|
image_url: https://avatars.githubusercontent.com/u/6964737?v=4
|
||||||
|
email: moonrailgun@gmail.com
|
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 3
|
||||||
|
title: 架构
|
||||||
|
---
|
||||||
|
|
||||||
|
## 服务端架构
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 插件机制架构
|
||||||
|
|
||||||
|

|
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"label": "命令行终端",
|
||||||
|
"position": 30
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
title: 命令行工具 tailchat-cli
|
||||||
|
---
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -g tailchat-cli@latest # 安装与更新同一命令
|
||||||
|
```
|
||||||
|
|
||||||
|
安装成功后输入`tailchat` 后返回如下
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tailchat <command>
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
tailchat create [template] 创建 Tailchat 项目代码
|
||||||
|
tailchat connect 连接到 Tailchat 节点网络
|
||||||
|
tailchat declaration [source] Tailchat 插件类型声明
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--version Show version number [boolean]
|
||||||
|
-h, --help Show help [boolean]
|
||||||
|
```
|
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 100
|
||||||
|
title: 演示群组
|
||||||
|
---
|
||||||
|
|
||||||
|
这里有一些用于演示Tailchat功能的群组
|
||||||
|
|
||||||
|
- [Tailchat Nightly](https://nightly.paw.msgbyte.com/invite/8Jfm1dWb)
|
||||||
|
- [原神](https://nightly.paw.msgbyte.com/invite/GFFzfD5H)
|
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"label": "部署",
|
||||||
|
"position": 10
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
title: 安装docker环境
|
||||||
|
---
|
||||||
|
|
||||||
|
> 因为 `Tailchat` 的环境对于初学者来说有一些些复杂,因此提供了 `docker` 为主的一键环境搭建配置。但是对于`docker`不熟的同学来说可能`docker`本身也是一种复杂度。
|
||||||
|
|
||||||
|
> 因此为了方便大家可以快速搭建 `Tailchat`,提供了本文作为引导。对于 `docker` 有一定了解的同学可以跳过本篇
|
||||||
|
|
||||||
|
> 本文以 `linux centos` 为例,目标是方便大家直接在服务器上部署。对于想要在其他系统(`windows`, `mac`) 使用的同学可以参考官方文档进行`docker`的安装
|
||||||
|
|
||||||
|
## 安装docker与docker compose
|
||||||
|
|
||||||
|
官方文档: [https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 如果之前有安装过docker可以执行以下命令删除旧的
|
||||||
|
sudo yum remove docker \
|
||||||
|
docker-client \
|
||||||
|
docker-client-latest \
|
||||||
|
docker-common \
|
||||||
|
docker-latest \
|
||||||
|
docker-latest-logrotate \
|
||||||
|
docker-logrotate \
|
||||||
|
docker-engine
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo yum install -y yum-utils # yum-utils 提供了 yum-config-manager 命令
|
||||||
|
|
||||||
|
sudo yum-config-manager \
|
||||||
|
--add-repo \
|
||||||
|
https://download.docker.com/linux/centos/docker-ce.repo
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- 安装docker 与 docker-compose 插件 -->
|
||||||
|
```bash
|
||||||
|
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||||
|
```
|
||||||
|
|
||||||
|
*PS: `docker-compose-plugin`提供了`docker compose`命令,用法同`docker-compose`*
|
||||||
|
|
||||||
|
> 如果`docker ps`显示守护进程没有启动(Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?)的话可以执行以下命令启动: `sudo systemctl start docker`
|
||||||
|
|
||||||
|
## 单独安装 docker-compose
|
||||||
|
|
||||||
|
如果购买的服务器已经预装了docker, 想要单独安装docker-compose的话可以看本节内容:
|
||||||
|
|
||||||
|
官方文档: [https://docs.docker.com/compose/install/](https://docs.docker.com/compose/install/)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -SL https://github.com/docker/compose/releases/download/v2.4.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose # 下载二进制文件
|
||||||
|
sudo chmod +x /usr/local/bin/docker-compose # 给予执行权限
|
||||||
|
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose # 软链接到path, 可以直接调用
|
||||||
|
docker-compose --version # 该行命令返回版本号则成功安装
|
||||||
|
```
|
@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
title: 概述
|
||||||
|
---
|
||||||
|
|
||||||
|
`Tailchat` 是一款插件化易拓展的开源 IM 应用。可拓展架构赋予 `Tailchat` 无限可能性。
|
||||||
|
|
||||||
|
前端微内核架构 + 后端微服务架构 使得 `Tailchat` 能够驾驭任何定制化/私有化的场景
|
||||||
|
|
||||||
|
## 特性
|
||||||
|
|
||||||
|
- 完整的即时通讯基础能力
|
||||||
|
- 插件化架构的赋予的自由拓展能力
|
||||||
|
- 微服务架构赋予的水平拓展能力
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- 前端
|
||||||
|
- `React`
|
||||||
|
- `Redux`
|
||||||
|
- `MiniStar`
|
||||||
|
- `tailwindcss`
|
||||||
|
- `iconify`
|
||||||
|
- 后端
|
||||||
|
- `Nodejs`
|
||||||
|
- `Socket.io`
|
||||||
|
- `koa`
|
||||||
|
- `moleculer`
|
||||||
|
|
||||||
|
## 功能列表
|
||||||
|
|
||||||
|
- 用户管理
|
||||||
|
- 基于4位数字标识(战网like)的用户名系统
|
||||||
|
- 好友管理
|
||||||
|
- 聊天系统
|
||||||
|
- 私聊
|
||||||
|
- 群聊
|
||||||
|
- 富文本消息
|
||||||
|
- 图片
|
||||||
|
- 链接
|
||||||
|
- 提及(@)
|
||||||
|
- 代码
|
||||||
|
- 插件系统
|
||||||
|
- 前端插件系统(基于`ministar`的微内核架构)
|
||||||
|
- 自定义主题
|
||||||
|
- 自定义面板
|
||||||
|
- 自定义操作
|
||||||
|
- 消息内容转换
|
||||||
|
- ...
|
||||||
|
- 后端插件系统(基于`moleculer`的微服务架构)
|
||||||
|
- 开放平台
|
||||||
|
- Connect ID
|
||||||
|
- *(其他正在开发中)*
|
||||||
|
- 快速跳转
|
||||||
|
|
||||||
|
|
||||||
|
## 截图
|
||||||
|
|
||||||
|
#### 插件中心
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 各类主题
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### Github订阅机器人
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 开源协议
|
||||||
|
|
||||||
|
开源协议请主要参考以下文档:
|
||||||
|
|
||||||
|
[GNU General Public License 3.0](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"label": "视频会议",
|
||||||
|
"position": 60
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
title: 概述
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tailchat Meeting
|
||||||
|
|
||||||
|
视频会议模块是 `Tailchat` 系列的一套重要组成部分。提供能力如下:
|
||||||
|
- 语音通信
|
||||||
|
- 视频会话
|
||||||
|
- 屏幕共享
|
||||||
|
- 虚拟背景
|
||||||
|
- 文件传输
|
||||||
|
- 聊天记录
|
||||||
|
|
||||||
|
同时 `tailchat-meeting` 还可以作为独立单品存在,无需登录即可快速发起/加入会议
|
||||||
|
|
||||||
|
### 项目仓库
|
||||||
|
|
||||||
|
- 开源地址: [https://github.com/msgbyte/tailchat-meeting](https://github.com/msgbyte/tailchat-meeting)
|
||||||
|
- 开源协议: GPL-3.0
|
||||||
|
|
||||||
|
:::info 开源声明
|
||||||
|
本项目基于 [edumeet](https://github.com/edumeet/edumeet) 和 [mediasoup](https://github.com/versatica/mediasoup) 进行二次开发而来。
|
||||||
|
|
||||||
|
在此基础上进行了功能追加与SDK实现以及代码优化。如果想要找到开源协议更加宽松(MIT + ISC 协议)的实现可以看一下这两个项目
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
### 项目架构
|
||||||
|
|
||||||
|

|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 3
|
||||||
|
title: 插件部署
|
||||||
|
---
|
||||||
|
|
||||||
|
TODO
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 4
|
||||||
|
title: SDK
|
||||||
|
---
|
||||||
|
|
||||||
|
TODO
|
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"label": "插件列表",
|
||||||
|
"position": 20
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
title: 纯前端插件
|
||||||
|
---
|
||||||
|
|
||||||
|
### com.msgbyte.bbcode
|
||||||
|
|
||||||
|
`默认安装`
|
||||||
|
|
||||||
|
一个用于支持bbcode语法解释富文本消息的插件
|
||||||
|
|
||||||
|
### com.msgbyte.intro
|
||||||
|
|
||||||
|
`默认安装`
|
||||||
|
|
||||||
|
新人引导插件
|
||||||
|
|
||||||
|
### com.msgbyte.notify
|
||||||
|
|
||||||
|
`默认安装`
|
||||||
|
|
||||||
|
消息通知插件
|
||||||
|
|
||||||
|
### com.msgbyte.webview
|
||||||
|
|
||||||
|
`默认安装`
|
||||||
|
|
||||||
|
增加用户添加群组网页面板的能力。
|
||||||
|
|
||||||
|
### com.msgbyte.draw
|
||||||
|
|
||||||
|
允许用户发送自定义绘图
|
||||||
|
|
||||||
|
### com.msgbyte.genshin
|
||||||
|
|
||||||
|
原神工具箱
|
||||||
|
|
||||||
|
### com.msgbyte.miaolang
|
||||||
|
|
||||||
|
允许发送喵语,安装插件后的双方加密对话,未安装插件的人看到的是 "喵"
|
||||||
|
|
||||||
|
### com.msgbyte.openapi
|
||||||
|
|
||||||
|
`WIP`
|
||||||
|
|
||||||
|
开放平台管理插件
|
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
title: 自定义主题
|
||||||
|
---
|
||||||
|
|
||||||
|
### com.msgbyte.theme.genshin
|
||||||
|
|
||||||
|
原神主题
|
||||||
|
|
||||||
|
包含主题如下:
|
||||||
|
- 原神-胡桃
|
||||||
|
- 原神-琴
|
||||||
|
- 原神-安柏
|
||||||
|
- 原神-莫娜
|
||||||
|
- 原神-罗莎莉亚
|
||||||
|
|
||||||
|
### com.msgbyte.theme.miku
|
||||||
|
|
||||||
|
初音未来主题,支持亮色与暗色
|
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"label": "开发插件",
|
||||||
|
"position": 99
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"label": "API 接口",
|
||||||
|
"position": 99
|
||||||
|
}
|
@ -0,0 +1,249 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
title: "@capital/common"
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注册
|
||||||
|
|
||||||
|
### regGroupPanel
|
||||||
|
|
||||||
|
注册群组面板
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
regGroupPanel({
|
||||||
|
name: `com.msgbyte.webview/grouppanel`,
|
||||||
|
label: '网页面板',
|
||||||
|
provider: PLUGIN_NAME,
|
||||||
|
extraFormMeta: [{ type: 'text', name: 'url', label: '网址' }],
|
||||||
|
render: GroupWebPanelRender,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
参数类型: [PluginGroupPanel](#plugingrouppanel)
|
||||||
|
|
||||||
|
### regMessageInterpreter
|
||||||
|
|
||||||
|
注册消息解释器
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
regMessageInterpreter({
|
||||||
|
name: '喵语翻译',
|
||||||
|
explainMessage(message: string) {
|
||||||
|
// 喵语 -> 人话
|
||||||
|
if (!isMiao(message)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return decode(message);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
参数类型: [PluginMessageInterpreter](#pluginmessageinterpreter)
|
||||||
|
|
||||||
|
### regMessageRender
|
||||||
|
|
||||||
|
*注册多个仅生效最后一个*
|
||||||
|
|
||||||
|
注册消息渲染器, 输入消息文本返回渲染内容
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
regMessageRender((message) => {
|
||||||
|
return <BBCode plainText={message} />;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### regChatInputAction
|
||||||
|
|
||||||
|
注册聊天输入框操作
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
regChatInputAction({
|
||||||
|
label: '喵言喵语',
|
||||||
|
onClick: (actions) => {
|
||||||
|
openModal(createElement(SendMiaoModal, { actions }));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
参数类型: [ChatInputAction](#chatinputaction)
|
||||||
|
|
||||||
|
|
||||||
|
### regPluginColorScheme
|
||||||
|
|
||||||
|
注册插件配色方案/主题
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
regPluginColorScheme({
|
||||||
|
label: 'Miku 葱',
|
||||||
|
name: 'light+miku',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 工具函数
|
||||||
|
|
||||||
|
### useGroupPanelParams
|
||||||
|
|
||||||
|
在`hooks`中获取用户面板相关信息
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { useGroupPanelParams } from '@capital/common';
|
||||||
|
|
||||||
|
const { groupId, panelId } = useGroupPanelParams();
|
||||||
|
```
|
||||||
|
|
||||||
|
### openModal
|
||||||
|
|
||||||
|
打开一个模态框
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
openModal(
|
||||||
|
content: React.ReactNode,
|
||||||
|
props?: Pick<ModalProps, 'closable' | 'maskClosable'>
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
类型:
|
||||||
|
- [ModalProps](#modalprops)
|
||||||
|
|
||||||
|
|
||||||
|
### ModalWrapper
|
||||||
|
|
||||||
|
模态框包装器
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<ModalWrapper>
|
||||||
|
<div></div>
|
||||||
|
</ModalWrapper>
|
||||||
|
```
|
||||||
|
|
||||||
|
### useModalContext
|
||||||
|
|
||||||
|
获取模态框上下文
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const { closeModal } = useModalContext();
|
||||||
|
```
|
||||||
|
|
||||||
|
### getGlobalState
|
||||||
|
|
||||||
|
获取全局 `Redux` 状态上下文
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const state = getGlobalState();
|
||||||
|
```
|
||||||
|
|
||||||
|
### getCachedUserInfo
|
||||||
|
|
||||||
|
获取用户信息, 缓存版本
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const info = getCachedUserInfo(userId);
|
||||||
|
```
|
||||||
|
|
||||||
|
### getCachedConverseInfo
|
||||||
|
|
||||||
|
获取会话信息
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const info = getCachedConverseInfo(converseId);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 类型
|
||||||
|
|
||||||
|
### PluginGroupPanel
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PluginGroupPanel {
|
||||||
|
/**
|
||||||
|
* 面板唯一标识
|
||||||
|
* @example com.msgbyte.webview/grouppanel
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 面板显示名
|
||||||
|
*/
|
||||||
|
label: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件提供者, 用于引导没有安装插件的用户安装插件
|
||||||
|
*/
|
||||||
|
provider: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 额外的表单数据, 用于创建面板时使用
|
||||||
|
*/
|
||||||
|
extraFormMeta: FastFormFieldMeta[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 该面板如何渲染
|
||||||
|
*/
|
||||||
|
render: React.ComponentType;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### PluginMessageInterpreter
|
||||||
|
|
||||||
|
插件消息解释器
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PluginMessageInterpreter {
|
||||||
|
name?: string;
|
||||||
|
explainMessage: (message: string) => React.ReactNode;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ChatInputAction
|
||||||
|
|
||||||
|
消息输入框操作对象
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ChatInputAction {
|
||||||
|
label: string;
|
||||||
|
onClick: (actions: ChatInputActionContextProps) => void;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### GroupPanel
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface GroupPanel {
|
||||||
|
id: string; // 在群组中唯一
|
||||||
|
name: string;
|
||||||
|
parentId?: string;
|
||||||
|
type: GroupPanelType;
|
||||||
|
provider?: string; // 面板提供者
|
||||||
|
pluginPanelName?: string; // 插件面板名
|
||||||
|
meta?: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### ModalProps
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ModalProps {
|
||||||
|
visible?: boolean;
|
||||||
|
onChangeVisible?: (visible: boolean) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否显示右上角的关闭按钮
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
closable?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 遮罩层是否可关闭
|
||||||
|
*/
|
||||||
|
maskClosable?: boolean;
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
title: "@capital/component"
|
||||||
|
---
|
||||||
|
|
||||||
|
### Button
|
||||||
|
|
||||||
|
组件来自 [antd](https://ant.design/)
|
||||||
|
|
||||||
|
组件文档: [Button](https://ant.design/components/button-cn/)
|
||||||
|
|
||||||
|
### TextArea
|
||||||
|
|
||||||
|
组件来自 [antd](https://ant.design/)
|
||||||
|
|
||||||
|
组件文档: [TextArea](https://ant.design/components/input-cn/#components-input-demo-textarea)
|
||||||
|
|
||||||
|
### Image
|
||||||
|
|
||||||
|
组件来自 [antd](https://ant.design/)
|
||||||
|
|
||||||
|
组件文档: [Image](https://ant.design/components/image-cn/)
|
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 3
|
||||||
|
title: 全局CSS变量
|
||||||
|
---
|
||||||
|
|
||||||
|
- `--tc-primary-color`: 主色调
|
||||||
|
- `--tc-background-image`: 背景图片
|
||||||
|
- `--tc-content-background-image`: 内容页背景图片
|
||||||
|
- `--tc-content-background-image-opacity`: 内容页背景图片透明度,默认 **0.15**
|
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
title: Icon 图标
|
||||||
|
---
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { Icon } from '@capital/component';
|
||||||
|
```
|
||||||
|
|
||||||
|
`tailchat` 的 icon 解决方案来自 `iconify`
|
||||||
|
|
||||||
|
使用方法很简单:
|
||||||
|
- 在下述网站中选择想要的图标: [https://icon-sets.iconify.design/](https://icon-sets.iconify.design/)
|
||||||
|
- 复制选中的key。传给 `Icon` 组件, 示例:
|
||||||
|
```tsx
|
||||||
|
<Icon icon="mdi:account" />
|
||||||
|
```
|
||||||
|
|
||||||
|
推荐使用`mdi`来统一化图标视觉设计:
|
||||||
|
[https://icon-sets.iconify.design/mdi/](https://icon-sets.iconify.design/mdi/)
|
@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
title: 开始开发插件
|
||||||
|
---
|
||||||
|
|
||||||
|
## 认识 MiniStar
|
||||||
|
|
||||||
|
`MiniStar` 是一套完整的微内核架构开发工具链,`tailchat`的插件架构就是基于 `MiniStar` 进行开发。
|
||||||
|
|
||||||
|
关于更多的 MiniStar 相关问题可以查看 MiniStar 的官方文档: [https://ministar.moonrailgun.com/](https://ministar.moonrailgun.com/)
|
||||||
|
|
||||||
|
## 创建一个基础项目
|
||||||
|
|
||||||
|
首先创建一个基本的 npm 项目, 并全局安装 `MiniStar`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install --global mini-star
|
||||||
|
```
|
||||||
|
|
||||||
|
在项目中执行: `ministar createPlugin` 来创建一个基本的插件
|
||||||
|
|
||||||
|
在项目中执行: `ministar buildPlugin` 来编译插件
|
||||||
|
|
||||||
|
> 值得一提的是, 虽然 `Tailchat` 并没有强制规定插件命名规范,但是还是推荐使用 `反域名` 的命名方式(类似于java中的包命名), 然后对插件中的部件,使用 `/` 进行分割
|
||||||
|
>
|
||||||
|
> 如:
|
||||||
|
> 插件名: `com.msgbyte.webview`
|
||||||
|
>
|
||||||
|
> 注册内容: `com.msgbyte.webview/grouppanel`
|
||||||
|
|
||||||
|
## 安装插件
|
||||||
|
|
||||||
|
### 手动安装插件
|
||||||
|
|
||||||
|
在不经过任何预设的情况下,一个通用的办法是自己构造一个 `manifest` 配置, 然后在 `tailchat` 提供手动安装插件 Tab 中将配置文件粘贴进去安装。
|
||||||
|
|
||||||
|
插件的url路径可以通过 `oss`/`static-server` 等办法代理
|
||||||
|
|
||||||
|
一个作为示例的`manifest`配置如下:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"label": "网页面板插件",
|
||||||
|
"name": "com.msgbyte.webview",
|
||||||
|
"url": "/plugins/com.msgbyte.webview/index.js",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"author": "msgbyte",
|
||||||
|
"description": "为群组提供创建网页面板的功能",
|
||||||
|
"requireRestart": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 其他有用的资源
|
||||||
|
|
||||||
|
- 来自基础项目提供的API: [API 文档](./api/common)
|
||||||
|
- 导出接口源码
|
||||||
|
- [@capital/common](https://github.com/msgbyte/tailchat/blob/master/web/src/plugin/common/index.ts)
|
||||||
|
- [@capital/component](https://github.com/msgbyte/tailchat/blob/master/web/src/plugin/component/index.tsx)
|
@ -0,0 +1,118 @@
|
|||||||
|
const lightCodeTheme = require('prism-react-renderer/themes/github');
|
||||||
|
const darkCodeTheme = require('prism-react-renderer/themes/dracula');
|
||||||
|
|
||||||
|
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
||||||
|
const themeConfig = {
|
||||||
|
navbar: {
|
||||||
|
title: 'Tailchat',
|
||||||
|
logo: {
|
||||||
|
alt: 'Tailchat Logo',
|
||||||
|
src: 'img/logo.svg',
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
docId: 'intro',
|
||||||
|
position: 'left',
|
||||||
|
label: '文档',
|
||||||
|
},
|
||||||
|
{ to: '/blog', label: '博客', position: 'left' },
|
||||||
|
{
|
||||||
|
href: 'https://github.com/msgbyte/tailchat',
|
||||||
|
label: 'GitHub',
|
||||||
|
position: 'right',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
style: 'dark',
|
||||||
|
// links: [
|
||||||
|
// {
|
||||||
|
// title: 'Docs',
|
||||||
|
// items: [
|
||||||
|
// {
|
||||||
|
// label: 'Tutorial',
|
||||||
|
// to: '/docs/intro',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// title: 'Community',
|
||||||
|
// items: [
|
||||||
|
// {
|
||||||
|
// label: 'Stack Overflow',
|
||||||
|
// href: 'https://stackoverflow.com/questions/tagged/docusaurus',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// label: 'Discord',
|
||||||
|
// href: 'https://discordapp.com/invite/docusaurus',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// label: 'Twitter',
|
||||||
|
// href: 'https://twitter.com/docusaurus',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// title: 'More',
|
||||||
|
// items: [
|
||||||
|
// {
|
||||||
|
// label: 'Blog',
|
||||||
|
// to: '/blog',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// label: 'GitHub',
|
||||||
|
// href: 'https://github.com/facebook/docusaurus',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
copyright: `Copyright © ${new Date().getFullYear()} MsgByte, Inc. Built with Docusaurus and ❤.`,
|
||||||
|
},
|
||||||
|
prism: {
|
||||||
|
theme: lightCodeTheme,
|
||||||
|
darkTheme: darkCodeTheme,
|
||||||
|
},
|
||||||
|
zoom: {
|
||||||
|
selector: '.markdown img',
|
||||||
|
config: {
|
||||||
|
// options you can specify via https://github.com/francoischalifour/medium-zoom#usage
|
||||||
|
background: {
|
||||||
|
light: 'rgb(255, 255, 255)',
|
||||||
|
dark: 'rgb(50, 50, 50)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @type {import('@docusaurus/preset-classic').Options} */
|
||||||
|
const presetClassicOptions = {
|
||||||
|
docs: {
|
||||||
|
sidebarPath: require.resolve('./sidebars.js'),
|
||||||
|
// Please change this to your repo.
|
||||||
|
editUrl: 'https://github.com/msgbyte/tailchat-website/edit/master/website/',
|
||||||
|
},
|
||||||
|
blog: {
|
||||||
|
postsPerPage: 5,
|
||||||
|
},
|
||||||
|
// blog: false,
|
||||||
|
theme: {
|
||||||
|
customCss: require.resolve('./src/css/custom.css'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @type {import('@docusaurus/types').DocusaurusConfig} */
|
||||||
|
module.exports = {
|
||||||
|
title: 'Tailchat',
|
||||||
|
tagline: '一个插件化易拓展的开源 IM 应用',
|
||||||
|
url: 'https://tailchat.msgbyte.com', // TODO: 待修改成文档主页
|
||||||
|
baseUrl: '/',
|
||||||
|
onBrokenLinks: 'throw',
|
||||||
|
onBrokenMarkdownLinks: 'warn',
|
||||||
|
favicon: 'img/logo.svg',
|
||||||
|
organizationName: 'msgbyte', // Usually your GitHub org/user name.
|
||||||
|
projectName: 'tailchat', // Usually your repo name.
|
||||||
|
themeConfig,
|
||||||
|
presets: [['@docusaurus/preset-classic', presetClassicOptions]],
|
||||||
|
plugins: [require.resolve('docusaurus-plugin-image-zoom')],
|
||||||
|
};
|
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "website",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"docusaurus": "docusaurus",
|
||||||
|
"start": "docusaurus start -p 11033",
|
||||||
|
"build": "docusaurus build",
|
||||||
|
"swizzle": "docusaurus swizzle --typescript",
|
||||||
|
"deploy": "docusaurus deploy",
|
||||||
|
"clear": "docusaurus clear",
|
||||||
|
"serve": "docusaurus serve",
|
||||||
|
"write-translations": "docusaurus write-translations",
|
||||||
|
"write-heading-ids": "docusaurus write-heading-ids"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@docusaurus/core": "2.0.0-beta.18",
|
||||||
|
"@docusaurus/preset-classic": "2.0.0-beta.18",
|
||||||
|
"@mdx-js/react": "^1.6.21",
|
||||||
|
"@svgr/webpack": "^5.5.0",
|
||||||
|
"clsx": "^1.1.1",
|
||||||
|
"docusaurus-plugin-image-zoom": "^0.0.2",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
|
"prism-react-renderer": "^1.2.1",
|
||||||
|
"react": "^17.0.1",
|
||||||
|
"react-dom": "^17.0.1",
|
||||||
|
"url-loader": "^4.1.1"
|
||||||
|
},
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.5%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@docusaurus/module-type-aliases": "^2.0.0-beta.18",
|
||||||
|
"@tsconfig/docusaurus": "^1.0.5",
|
||||||
|
"@types/react": "^17.0.26",
|
||||||
|
"@types/react-helmet": "^6.1.2",
|
||||||
|
"@types/react-router-dom": "^5.3.0",
|
||||||
|
"typescript": "^4.4.3"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Creating a sidebar enables you to:
|
||||||
|
- create an ordered group of docs
|
||||||
|
- render a sidebar for each doc of that group
|
||||||
|
- provide next/previous navigation
|
||||||
|
|
||||||
|
The sidebars can be generated from the filesystem, or explicitly defined here.
|
||||||
|
|
||||||
|
Create as many sidebars as you want.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// By default, Docusaurus generates a sidebar from the docs folder structure
|
||||||
|
tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }],
|
||||||
|
|
||||||
|
// But you can create a sidebar manually
|
||||||
|
/*
|
||||||
|
tutorialSidebar: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
label: 'Tutorial',
|
||||||
|
items: ['hello'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
*/
|
||||||
|
};
|
@ -0,0 +1,13 @@
|
|||||||
|
/* stylelint-disable docusaurus/copyright-header */
|
||||||
|
|
||||||
|
.features {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 2rem 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.featureSvg {
|
||||||
|
height: 200px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/* stylelint-disable docusaurus/copyright-header */
|
||||||
|
/**
|
||||||
|
* Any CSS included here will be global. The classic template
|
||||||
|
* bundles Infima by default. Infima is a CSS framework designed to
|
||||||
|
* work well for content-centric websites.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* You can override the default Infima variables here. */
|
||||||
|
:root {
|
||||||
|
--ifm-color-primary: #25c2a0;
|
||||||
|
--ifm-color-primary-dark: rgb(33, 175, 144);
|
||||||
|
--ifm-color-primary-darker: rgb(31, 165, 136);
|
||||||
|
--ifm-color-primary-darkest: rgb(26, 136, 112);
|
||||||
|
--ifm-color-primary-light: rgb(70, 203, 174);
|
||||||
|
--ifm-color-primary-lighter: rgb(102, 212, 189);
|
||||||
|
--ifm-color-primary-lightest: rgb(146, 224, 208);
|
||||||
|
--ifm-code-font-size: 95%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docusaurus-highlight-code-line {
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
display: block;
|
||||||
|
margin: 0 calc(-1 * var(--ifm-pre-padding));
|
||||||
|
padding: 0 var(--ifm-pre-padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme='dark'] .docusaurus-highlight-code-line {
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.medium-zoom-image--opened {
|
||||||
|
z-index: var(--ifm-z-index-fixed);
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/* stylelint-disable docusaurus/copyright-header */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSS files with the .module.css suffix will be treated as CSS modules
|
||||||
|
* and scoped locally.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.heroBanner {
|
||||||
|
padding: 4rem 0;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 966px) {
|
||||||
|
.heroBanner {
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoContainer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoIframe {
|
||||||
|
width: 640px;
|
||||||
|
height: 360px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 966px) {
|
||||||
|
.videoIframe {
|
||||||
|
width: 360px;
|
||||||
|
height: 240px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import Layout from '@theme/Layout';
|
||||||
|
import Link from '@docusaurus/Link';
|
||||||
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
|
import styles from './index.module.css';
|
||||||
|
import HomepageFeatures from '../components/HomepageFeatures';
|
||||||
|
|
||||||
|
function HomepageHeader() {
|
||||||
|
const { siteConfig } = useDocusaurusContext();
|
||||||
|
return (
|
||||||
|
<header className={clsx('hero hero--primary', styles.heroBanner)}>
|
||||||
|
<div className="container">
|
||||||
|
<h1 className="hero__title">{siteConfig.title}</h1>
|
||||||
|
<p className="hero__subtitle">{siteConfig.tagline}</p>
|
||||||
|
<div className={styles.buttons}>
|
||||||
|
<Link
|
||||||
|
className="button button--secondary button--lg"
|
||||||
|
to="https://nightly.paw.msgbyte.com/"
|
||||||
|
>
|
||||||
|
进入网页 Nightly 版
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function HomepageVideo() {
|
||||||
|
return (
|
||||||
|
<div className={styles.videoContainer}>
|
||||||
|
<iframe
|
||||||
|
className={styles.videoIframe}
|
||||||
|
src="//player.bilibili.com/player.html?aid=340398093&bvid=BV1394y1Z76n&cid=568332564&page=1"
|
||||||
|
scrolling="no"
|
||||||
|
border="0"
|
||||||
|
frameBorder="no"
|
||||||
|
framespacing="0"
|
||||||
|
allowFullScreen="true"
|
||||||
|
>
|
||||||
|
{' '}
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
const { siteConfig } = useDocusaurusContext();
|
||||||
|
return (
|
||||||
|
<Layout
|
||||||
|
title={`Hello from ${siteConfig.title}`}
|
||||||
|
description="Description will go into a meta tag in <head />"
|
||||||
|
>
|
||||||
|
<HomepageHeader />
|
||||||
|
<main>
|
||||||
|
<HomepageVideo />
|
||||||
|
|
||||||
|
<HomepageFeatures />
|
||||||
|
</main>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
title: Markdown page example
|
||||||
|
---
|
||||||
|
|
||||||
|
# Markdown page example
|
||||||
|
|
||||||
|
You don't need React to write simple standalone pages.
|
@ -0,0 +1 @@
|
|||||||
|
tailchat.msgbyte.com
|
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 485 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 482 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 498 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 419 KiB |
After Width: | Height: | Size: 324 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 9.8 KiB |
After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"extends": "@tsconfig/docusaurus/tsconfig.json",
|
||||||
|
"include": ["src/"]
|
||||||
|
}
|