├── .gitignore ├── LICENSE ├── README.md ├── README.zh.md ├── bun.lock ├── example.svg ├── package.json ├── scripts └── build │ ├── index.ts │ └── plugins.ts ├── src ├── components │ └── index.tsx ├── icons │ ├── mac │ │ ├── close.svg │ │ ├── minimize.svg │ │ └── stretch.svg │ └── windows │ │ ├── close.svg │ │ ├── minimize.svg │ │ └── stretch.svg ├── index.tsx ├── styles │ └── index.scss └── util.ts ├── tsconfig.json └── types ├── docsify.d.ts └── index.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Yuki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docsify-chat 2 | 3 | A docsify plugin for generate chat panel from markdown 4 | 5 | Read this in other languages: English | [简体中文](./README.zh.md) 6 | 7 | ```markdown 8 | 9 | 10 | #### **Yuki** 11 | 12 | Hello 13 | 14 | #### **Robot** 15 | 16 | Ciallo ~(∠·ω< )⌒★ 17 | 18 | 19 | ``` 20 | 21 | ![docsify_chat](https://cdn.sa.net/2024/12/09/cI9ewyEFLNG6roZ.png) 22 | 23 | ## Installation 24 | 25 | 1. Add the docsify-chat plugin to your `index.html` after docsify. 26 | 27 | ```html 28 | 29 | 30 | 31 | 32 | 33 | ``` 34 | 35 | 2. Review the [Options](#options) section and configure as needed. 36 | 37 | ```javascript 38 | window.$docsify = { 39 | // ... 40 | chat: { 41 | // chat panel title 42 | title: "Dialog", 43 | // set avatar url 44 | users: [ 45 | { nickname: "Yuki", avatar: "" }, 46 | { nickname: "Robot", avatar: "" }, 47 | ], 48 | }, 49 | }; 50 | ``` 51 | 52 | ## Usage 53 | 54 | 1. Define a chat set using `chat:start` and `chat:end` HTML comments. 55 | 56 | HTML comments are used to mark the start and end of a chat set. 57 | 58 | ```markdown 59 | 60 | 61 | ... 62 | 63 | 64 | ``` 65 | 66 | 2. Define chat within a message set using heading + bold markdown. 67 | 68 | Heading text will be used as the user nickname, and all proceeding content will be associated with that chat up to start of the next message or a `chat:end` comment. 69 | 70 | ```markdown 71 | 72 | 73 | #### **Yuki** 74 | 75 | hello 76 | 77 | #### **Robot** 78 | 79 | hello world 80 | 81 | 82 | ``` 83 | 84 | 3. Generate and display your chat panel. 85 | 86 | If you do not specify a user avatar, the initials of the nickname will be displayed by default. 87 | 88 | ![example](/example.svg) 89 | 90 | ## Options 91 | 92 | Options are set within the [`window.$docsify`](https://docsify.js.org/#/configuration) configuration under the `chat` key: 93 | 94 | ```html 95 | 112 | ``` 113 | 114 | ### title 115 | 116 | - Type: `string` 117 | - Default: `'Dialog'` 118 | 119 | Sets the chat panel title. 120 | 121 | You can also set the title for each chat panel individually in ``. 122 | 123 | **Configuration** 124 | 125 | ```javascript 126 | window.$docsify = { 127 | // ... 128 | chat: { 129 | title: 'chat history', 130 | }, 131 | }; 132 | ``` 133 | 134 | **Example** 135 | 136 | ```markdown 137 | 138 | 139 | 140 | 141 | 142 | ``` 143 | 144 | ### users 145 | 146 | - Type: `array` 147 | - Default: `[]` 148 | 149 | Specify a nickname to match the user's avatar, support network URL. 150 | 151 | **Configuration** 152 | 153 | ```javascript 154 | window.$docsify = { 155 | // ... 156 | chat: { 157 | users: [ 158 | { nickname: 'Yuki', avatar: 'images/yuki.png' }, 159 | { nickname: 'Robot', avatar: 'images/robot.png' }, 160 | ], 161 | }, 162 | }; 163 | ``` 164 | 165 | ### self 166 | 167 | > Before v0.5.0, this attribute was named `"myself"`, but it has now been renamed 'self'. 168 | 169 | - Type: `string` 170 | - Default: `null` 171 | 172 | Set your own global nickname, the dialog will be displayed on the right side of the chat panel. 173 | 174 | You can also set the user for each chat panel individually in ``. 175 | 176 | **Configuration** 177 | 178 | ```javascript 179 | window.$docsify = { 180 | // ... 181 | chat: { 182 | self: 'Yuki', 183 | }, 184 | }; 185 | ``` 186 | 187 | **Example** 188 | 189 | ```markdown 190 | 191 | 192 | 193 | 194 | 195 | ``` 196 | 197 | ### animation 198 | 199 | - Type: `number` 200 | - Default: `50` 201 | 202 | Adjust the duration of the chat panel fade-in and fade-out animation. 203 | 204 | **Configuration** 205 | 206 | ```javascript 207 | window.$docsify = { 208 | // ... 209 | chat: { 210 | animation: 50, 211 | }, 212 | }; 213 | ``` 214 | 215 | ### os 216 | 217 | - Type: `string` 218 | - Default: `null` 219 | 220 | Define the system style of the title bar, support `"mac"` and `"windows"`. 221 | 222 | If it is not set, it will be based on the current browser `navigator Platform` Automatic rendering. 223 | 224 | **Configuration** 225 | 226 | ```javascript 227 | window.$docsify = { 228 | // ... 229 | chat: { 230 | os: 'mac', 231 | }, 232 | }; 233 | ``` 234 | 235 | ## Postscript 236 | 237 | Because I wrote a chatbot framework, I needed a chat panel for illustrate. before I took screenshots directly in the software, but it felt too troublesome. I was thinking why can't it be generated directly with markdown? I've been looking for a long time, but I can't find any similar plugins, so I made one myself. 238 | 239 | In order to save time, the syntax refers to [docsify-tabs](https://github.com/jhildenbiddle/docsify-tabs), which took only half a day to make. Although it basically meets daily use, there may be some unknown bugs. 240 | -------------------------------------------------------------------------------- /README.zh.md: -------------------------------------------------------------------------------- 1 | # docsify-chat 2 | 3 | 一个基于 docsify 的插件,可在 markdown 中生成聊天对话 4 | 5 | 使用其他语言阅读:[English](./README.md) | 简体中文 6 | 7 | ```markdown 8 | 9 | 10 | #### **Yuki** 11 | 12 | Hello 13 | 14 | #### **Robot** 15 | 16 | Ciallo ~(∠·ω< )⌒★ 17 | 18 | 19 | ``` 20 | 21 | ![docsify_chat](https://cdn.sa.net/2024/12/09/cI9ewyEFLNG6roZ.png) 22 | 23 | ## 安装 24 | 25 | 1. 在 `index.html` 中添加 docsify-chat,必须在 docsify 之后引入。 26 | 27 | ```html 28 | 29 | 30 | 31 | 32 | 33 | ``` 34 | 35 | 2. 可以在 [配置项](#配置项) 中根据自身需要来进行相关配置。 36 | 37 | ```javascript 38 | window.$docsify = { 39 | // ... 40 | chat: { 41 | // 聊天面板标题 42 | title: "窗口", 43 | // 设置头像 44 | users: [ 45 | { nickname: "Yuki", avatar: "" }, 46 | { nickname: "Robot", avatar: "" }, 47 | ], 48 | }, 49 | }; 50 | ``` 51 | 52 | ## 使用 53 | 54 | 1. 使用 `chat:start` 与 `chat:end` 的 HTML 注释来定义聊天面板。 55 | 56 | HTML 注释用于标记聊天面板的开始和结束。 57 | 58 | ```markdown 59 | 60 | 61 | ... 62 | 63 | 64 | ``` 65 | 66 | 2. 使用标题 + 粗体标记在聊天面板中定义消息。 67 | 68 | 标题文本将被用作用户昵称,后续所有内容都将视为对话框内容,直到下一个标题或 `chat:end` 标记结束。 69 | 70 | ```markdown 71 | 72 | 73 | #### **Yuki** 74 | 75 | hello 76 | 77 | #### **Robot** 78 | 79 | hello world 80 | 81 | 82 | ``` 83 | 84 | 3. 若上述步骤无误,页面将会生成并显示聊天面板。 85 | 86 | 如果未指定用户头像,则默认情况下将显示昵称的首字母。 87 | 88 | ![example](/example.svg) 89 | 90 | ## 配置项 91 | 92 | 相关配置可以在 [`window.$docsify`](https://docsify.js.org/#/configuration) 下的 `chat` 字段中定义: 93 | 94 | ```html 95 | 112 | ``` 113 | 114 | ### title 115 | 116 | - 类型: `string` 117 | - 默认: `'Dialog'` 118 | 119 | 设置聊天面板的全局标题。 120 | 121 | 你还可以在 `` 中分别为每个聊天面板单独设置标题。 122 | 123 | **配置** 124 | 125 | ```javascript 126 | window.$docsify = { 127 | // ... 128 | chat: { 129 | title: '聊天记录', 130 | }, 131 | }; 132 | ``` 133 | 134 | **语法** 135 | 136 | ```markdown 137 | 138 | 139 | 140 | 141 | 142 | ``` 143 | 144 | ### users 145 | 146 | - 类型: `array` 147 | - 默认: `[]` 148 | 149 | 设置用户的头像与昵称,支持网络地址。 150 | 151 | **配置** 152 | 153 | ```javascript 154 | window.$docsify = { 155 | // ... 156 | chat: { 157 | users: [ 158 | { nickname: 'Yuki', avatar: 'images/yuki.png' }, 159 | { nickname: 'Robot', avatar: 'images/robot.png' }, 160 | ], 161 | }, 162 | }; 163 | ``` 164 | 165 | ### self 166 | 167 | > 在 v0.5.0 以前,该属性名为 `"myself"`,现已更名为 `"self"`。 168 | 169 | - 类型: `string` 170 | - 默认: `null` 171 | 172 | 定义一个昵称,该用户的对话框将显示在聊天面板的右侧。 173 | 174 | 你还可以在 `` 中分别为每个聊天面板单独设置用户。 175 | 176 | **配置** 177 | 178 | ```javascript 179 | window.$docsify = { 180 | // ... 181 | chat: { 182 | self: 'Yuki', 183 | }, 184 | }; 185 | ``` 186 | 187 | **语法** 188 | 189 | ```markdown 190 | 191 | 192 | 193 | 194 | 195 | ``` 196 | 197 | ### animation 198 | 199 | - 类型: `number` 200 | - 默认: `50` 201 | 202 | 调整聊天对话框淡入淡出的动画时长。 203 | 204 | **设置** 205 | 206 | ```javascript 207 | window.$docsify = { 208 | // ... 209 | chat: { 210 | animation: 50, 211 | }, 212 | }; 213 | ``` 214 | 215 | ### os 216 | 217 | - 类型: `string` 218 | - 默认: `null` 219 | 220 | 定义标题栏的系统风格,支持 `"mac"` 与 `"windows"`。 221 | 222 | 如果不设置,将会根据当前浏览器 `navigator.platform` 自动渲染。 223 | 224 | **设置** 225 | 226 | ```javascript 227 | window.$docsify = { 228 | // ... 229 | chat: { 230 | os: 'mac', 231 | }, 232 | }; 233 | ``` 234 | 235 | ## 补充 236 | 237 | 因为我写了一个 QQ 机器人框架,所以需要一个聊天面板在文档中做相关演示。在这之前我是直接在 QQ 里截图后丢到文档的,但这样感觉太麻烦了。突发奇想为什么不能直接用 markdown 来生成咧?但是我找了很长时间,都没有类似的插件,所以就自己做了一个。 238 | 239 | 为了节省时间,相关语法完全参照 [docsify-tabs](https://github.com/jhildenbiddle/docsify-tabs),只花了半天时间就做好了。虽然它基本满足日常使用,但可能会存在一些未知的 bug。 240 | -------------------------------------------------------------------------------- /bun.lock: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1, 3 | "workspaces": { 4 | "": { 5 | "name": "docsify-chat", 6 | "devDependencies": { 7 | "@types/bun": "latest", 8 | "hanno": "^0.0.1", 9 | "sass": "latest", 10 | }, 11 | "peerDependencies": { 12 | "typescript": "latest", 13 | }, 14 | }, 15 | }, 16 | "packages": { 17 | "@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="], 18 | 19 | "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="], 20 | 21 | "@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw=="], 22 | 23 | "@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg=="], 24 | 25 | "@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ=="], 26 | 27 | "@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="], 28 | 29 | "@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="], 30 | 31 | "@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="], 32 | 33 | "@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="], 34 | 35 | "@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="], 36 | 37 | "@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="], 38 | 39 | "@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw=="], 40 | 41 | "@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ=="], 42 | 43 | "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="], 44 | 45 | "@types/bun": ["@types/bun@1.2.9", "", { "dependencies": { "bun-types": "1.2.9" } }, "sha512-epShhLGQYc4Bv/aceHbmBhOz1XgUnuTZgcxjxk+WXwNyDXavv5QHD1QEFV0FwbTSQtNq6g4ZcV6y0vZakTjswg=="], 46 | 47 | "@types/node": ["@types/node@22.10.10", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww=="], 48 | 49 | "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], 50 | 51 | "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], 52 | 53 | "bun-types": ["bun-types@1.2.9", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-dk/kOEfQbajENN/D6FyiSgOKEuUi9PWfqKQJEgwKrCMWbjS/S6tEXp178mWvWAcUSYm9ArDlWHZKO3T/4cLXiw=="], 54 | 55 | "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], 56 | 57 | "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], 58 | 59 | "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], 60 | 61 | "hanno": ["hanno@0.0.1", "", { "peerDependencies": { "typescript": "latest" } }, "sha512-8Qz+sLC+eWDf2VuL+L6//LyYSQO+cATMaf14BMbOum5nUybZr1ahyNhGp9dG7uHR2Cb7PclOAN7c07DTmvMzLg=="], 62 | 63 | "immutable": ["immutable@5.0.3", "", {}, "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw=="], 64 | 65 | "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], 66 | 67 | "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], 68 | 69 | "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], 70 | 71 | "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], 72 | 73 | "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], 74 | 75 | "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], 76 | 77 | "readdirp": ["readdirp@4.1.1", "", {}, "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw=="], 78 | 79 | "sass": ["sass@1.86.3", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw=="], 80 | 81 | "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], 82 | 83 | "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], 84 | 85 | "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], 86 | 87 | "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /example.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 157 | 158 |
159 |
160 |
161 | 167 | 172 | 179 |
180 | Dialog 181 |
182 |
183 |
184 |
185 |
Yuki
186 |
hello
187 |
188 |
Y
189 |
190 |
191 |
R
192 |
193 |
Robot
194 |
hello world
195 |
196 |
197 |
198 |
199 |
200 |
201 |
-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docsify-chat", 3 | "version": "1.0.2", 4 | "description": "A docsify plugin for generate chat panel from markdown", 5 | "main": "lib/docsify-chat.js", 6 | "packageManager": "bun@1.2.9", 7 | "files": [ 8 | "lib" 9 | ], 10 | "scripts": { 11 | "build": "NODE_ENV=production bun ./scripts/build/index.ts" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/xueelf/docsify-chat.git" 16 | }, 17 | "keywords": [ 18 | "docs", 19 | "docsify", 20 | "docsify.js", 21 | "documentation", 22 | "javascript", 23 | "js", 24 | "markdown", 25 | "md", 26 | "plugin", 27 | "chat" 28 | ], 29 | "author": "Yuki ", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/xueelf/docsify-chat/issues" 33 | }, 34 | "homepage": "https://github.com/xueelf/docsify-chat#readme", 35 | "devDependencies": { 36 | "@types/bun": "latest", 37 | "hanno": "^0.0.1", 38 | "sass": "latest" 39 | }, 40 | "peerDependencies": { 41 | "typescript": "latest" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/build/index.ts: -------------------------------------------------------------------------------- 1 | import { build, type BuildConfig } from 'bun'; 2 | import { sassPlugin, svgPlugin } from './plugins'; 3 | 4 | const buildConfig: BuildConfig = { 5 | entrypoints: ['src/index.tsx'], 6 | outdir: 'lib', 7 | plugins: [sassPlugin(), svgPlugin()], 8 | }; 9 | 10 | await build({ 11 | ...buildConfig, 12 | naming: 'docsify-chat.[ext]', 13 | }); 14 | await build({ 15 | ...buildConfig, 16 | minify: true, 17 | naming: 'docsify-chat.min.[ext]', 18 | }); 19 | -------------------------------------------------------------------------------- /scripts/build/plugins.ts: -------------------------------------------------------------------------------- 1 | import type { BunPlugin, PluginBuilder } from 'bun'; 2 | import { compileAsync } from 'sass'; 3 | 4 | export function sassPlugin(): BunPlugin { 5 | return { 6 | name: 'sass', 7 | setup(builder: PluginBuilder) { 8 | builder.onLoad({ filter: /\.scss$/ }, async ({ path }) => { 9 | const { css } = await compileAsync(path, { 10 | style: builder.config.minify ? 'compressed' : 'expanded', 11 | }); 12 | 13 | return { 14 | loader: 'text', 15 | contents: css, 16 | }; 17 | }); 18 | }, 19 | }; 20 | } 21 | 22 | export function svgPlugin(): BunPlugin { 23 | return { 24 | name: 'svg', 25 | setup(builder: PluginBuilder) { 26 | builder.onLoad({ filter: /\.svg$/ }, async ({ path }) => { 27 | let contents = await Bun.file(path).text(); 28 | 29 | if (builder.config.minify) { 30 | contents = contents.replace(/\n(\s{2})*/g, ''); 31 | } 32 | return { 33 | loader: 'text', 34 | contents, 35 | }; 36 | }); 37 | }, 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/components/index.tsx: -------------------------------------------------------------------------------- 1 | import { stringToColor } from '@/util'; 2 | import macClose from '@/icons//mac/close.svg'; 3 | import macMinimize from '@/icons/mac/minimize.svg'; 4 | import macStretch from '@/icons/mac/stretch.svg'; 5 | import windowsClose from '@/icons/windows/close.svg'; 6 | import windowsMinimize from '@/icons/windows/minimize.svg'; 7 | import windowsStretch from '@/icons/windows/stretch.svg'; 8 | 9 | function MacControls() { 10 | return ( 11 | <> 12 |