Back to home@CSlawyer1985

dsh-excalidraw-board

DSH Web GUI 画板插件:右上角一键打开全屏 Excalidraw 白板,直接嵌入官方原站,侧边栏感知不遮挡

Stars
0
Language
JavaScript
Created
Aug 19, 2026
Updated
Aug 20, 2026
GitHub repo

Introduction

dsh-excalidraw-board

License Version PRs Welcome
让 DSH 拥有一个全功能的白板
右上角一键打开,直接嵌入官方 Excalidraw 原站
绘图 · 协作 · 素材库 · 导出 · 快捷键 —— 与独立浏览器访问完全一致


新用户?安装 开始——两步注册,右上角立刻出现铅笔图标。

核心承诺:原站即功能。 不转码、不自托管、不加沙箱限制,iframe 里跑的就是 excalidraw.com 本体,官方怎么用,这里就怎么用。


运行效果

① 右上角入口 —— 会话窗口右上角(工具区最右)的铅笔图标,点击打开、再点关闭(浮层右上角的圆形 X 也可关闭):

状态行为
侧边栏展开画板从侧边栏右侧铺开,左侧会话列表完全可见可点,不遮挡
侧边栏折叠(56px rail)画板全屏铺满
打开期间拖拽侧边栏画板左边缘每 250ms 自动跟随,实时调整

② Excalidraw 编辑器(浅色主题) —— 打开后即官方编辑器全貌:

Excalidraw 编辑器(浅色)

③ Excalidraw 编辑器(深色主题) —— 与官方站点一致支持暗色模式:

Excalidraw 编辑器(深色)

④ 实际绘图效果 —— 手绘风格图形、箭头、文字标签、自由绘制,全部可用:

Excalidraw 绘图效果

为什么直接嵌入原站

顾虑结论
官方是否允许嵌入?✅ 允许。实测响应头无 X-Frame-Options、无 CSP frame-ancestors 拦截,且页面内置了 iframe 场景的适配代码(官方明确支持嵌入场景)
功能是否完整?✅ 完全一致。iframe 加载同一 URL、同一份线上代码,零裁剪、零转码、零自托管
剪贴板 / 全屏 / 分享?✅ 显式授予 clipboard-readclipboard-writefullscreenweb-sharecamera/microphone 等权限
会不会被沙箱限制?✅ 不加 sandbox 属性,不限制任何站点能力
版本更新?✅ 永远跟随官方最新版,无需维护本地副本

特性

来自 Excalidraw(官方原站能力,引用自 Excalidraw 官方 README

能力说明
✍️ 手绘风格独有 hand-drawn 观感,图纸/线框/草图都好看
🎨 无限画布基于 canvas 的无限大画板,缩放平移流畅
⚒️ 全工具集矩形、圆形、菱形、箭头、直线、自由绘制、橡皮……
➡️ 箭头绑定箭头吸附形状,带标签箭头
🔙 撤销 / 重做完整历史栈
🔍 缩放与平移滚轮缩放、抓手平移
😀 素材库内建形状库 + 社区素材库
📷 图片支持插入图片、调整裁剪
🖼️ 导出PNG / SVG / 剪贴板 / .excalidraw JSON 开放格式
🌓 深色模式明暗主题一键切换
🌐 本地化支持中文等 i18n
📡 PWA离线可用(官方站点能力)
🤼 实时协作多人实时协作白板
🔒 端到端加密协作内容端到端加密
💾 本地优先自动保存到浏览器
🔗 分享链接导出只读分享链接

本插件的 DSH 集成能力

能力说明
右上角一键开关铅笔图标 ⇄ X 图标,状态高亮(品牌色),悬停反馈
侧边栏感知展开不遮挡、折叠全屏、拖拽实时跟随(250ms 轮询测量)
全屏浮层shell.overlay 浮层 + 圆形 X 关闭按钮
主题自适应按钮颜色走 DSH 主题 token,明暗主题自动适配
零侵入全部注册在 replaceRisk: none 槽位,不替换任何原生 UI
可卸载停止插件即完全清理(样式、定时器、槽位注册全部随生命周期释放)

安装

本插件是 DSH 静态 Client 模块(v0.2.0 起):随 DSH 启动自动加载,重启/升级不丢,无需每次 cordis_define。源码见 lib/client.js(静态版)与 lib/plugin.client.js(动态版,备选)。

方式 A:静态 Client 模块(推荐,自动加载、升级不丢)

  1. 安装包到 DSH 主 node_modules(部署根目录):

    # 从 GitHub 安装
    npm install --no-save CSlawyer1985/dsh-excalidraw-board
    # 或本地目录
    npm install --no-save /path/to/dsh-excalidraw-board
    

    包内 package.json 已声明 dsh.clientplatform: web),DSH 启动时自动把它编入 window.__DSH_BOOT__ 条目,浏览器按需加载 /plugins/dsh-excalidraw-board/client.js——无需本地构建。

  2. 在 DSH profile 的补丁层声明该行(如 ~/.dsh/profiles/web/cordis.patch.yml):

    - insert:
        - id: ui-excalidraw-board
          name: 'dsh-excalidraw-board'
    
  3. 重启 DSH(dsh --profile web 或你的启动命令)。重启后插件自动生效,此后升级 DSH 不再丢失。

方式 B:动态插件(备选,无需重启)

  1. 复制 lib/plugin.client.jsreturn { ... } 的函数体;
  2. 在 DSH 会话中调用 cordis_define(Client 代码粘贴到 code.client),再 cordis_run 激活;
  3. 批准运行后,右上角即出现铅笔图标。

注意:动态插件注册在进程内,DSH 重启后需要重新加载;静态模块方式无此限制,是本插件主推路径。

使用

  1. 点击会话右上角铅笔图标 → 画板打开(侧边栏展开时从侧边栏右侧开始铺开);
  2. 绘图、插入素材、协作、导出……与独立访问 excalidraw.com 完全一致;
  3. 再点右上角 X 图标(或浮层右上角圆形 X)→ 关闭画板。

实现方法

架构总览

DSH Web GUI(浏览器端)
        │
        ├─ conversation.session.header.utilities  右上角开关按钮(铅笔 ⇄ X)
        │        └─ 共享 store(open / sidebarLeft + 订阅)
        ├─ conversation.input.dock                0 尺寸测量元素(每 250ms 读 rect.left)
        │        └─ 侧边栏右边缘 = 对话列左边缘
        └─ shell.overlay                          全屏浮层
                 ├─ iframe → https://excalidraw.com/(权限全开,无 sandbox)
                 └─ 圆形 X 关闭按钮

核心机制

机制实现解决的问题
侧边栏感知在对话列全宽行(conversation.input.dock)挂 0 尺寸隐藏元素,timer.interval 250ms 轮询 getBoundingClientRect().left,该值即侧边栏右边缘(DSH 布局常量:展开默认 280px / 可拖 264–420px,折叠 rail 56px)展开时不遮左侧栏,折叠时全屏
全屏浮层shell.overlay(root 级、点击穿透层,条目自行 opt-in pointer-events),position: fixed + 动态 left浮层永远盖在所有列之上、滚动容器之外
样式作用域免疫全部样式走 React 内联 style(不依赖 styles.insert 类名选择器)浮层渲染在插件根作用域之外时样式不失效(v0.1.0 修复)
状态共享apply 闭包内 store + 订阅集合,两个槽位组件通过 hook 同步 open / sidebarLeft按钮与浮层状态一致
生命周期定时器、订阅、DOM 全部挂在 Cordis fiber 上,stop/undefine 自动清理卸载无残留
权限全开allow="clipboard-read; clipboard-write; fullscreen; camera; microphone; display-capture; autoplay; encrypted-media; picture-in-picture; web-share; geolocation" + allowFullScreen剪贴板、全屏、分享、演示等与独立访问一致

目录结构

dsh-excalidraw-board/
├── lib/
│   ├── index.js            # Host 半入口(空 apply)+ 元数据 + 动态版源码引用
│   ├── client.js           # 静态 Client 模块(__ModuleLoader__.load 格式,主推)
│   └── plugin.client.js    # 动态插件版源码(备选,可喂给 cordis_define)
├── docs/
│   ├── scene-demo.json     # 效果图所用示例场景
│   ├── shot-excalidraw.js  # 效果图生成脚本(headless Chrome + CDP)
│   └── screenshots/        # 运行效果插图
├── package.json            # dsh.client 声明 + exports["./client"]
└── README.md

设计原则

  1. 原站即功能——不转码、不自托管、不加沙箱。官方站点允许嵌入(无 frame 拦截头),就用最忠实的方式嵌入。
  2. 零侵入——只注册 replaceRisk: none 的增量槽位,不替换、不遮挡任何原生 UI。
  3. 感知优先——浮层位置由实时测量驱动,拖拽侧边栏、切换折叠均即时跟随,不依赖任何内部状态 API。
  4. 可逆——所有副作用(样式、定时器、订阅、注册)挂在插件生命周期上,卸载即完全清理。
  5. 内联优先——渲染在插件作用域之外的 UI 一律用内联样式,免疫作用域隔离。

迭代日志

日期版本类型要点
2026-08-19v0.1.0初始发布右上角铅笔图标开关 + 全屏 iframe 嵌入 Excalidraw 原站 + 权限全开
2026-08-19v0.1.0增强侧边栏感知:展开不遮挡、折叠全屏、拖拽实时跟随(250ms 测量)
2026-08-19v0.1.0修复浮层样式作用域失效(左上角小窗口)→ 全量改内联样式
2026-08-20v0.2.0架构改为静态 Client 模块(dsh.client 声明 + __ModuleLoader__.load),随 DSH 启动自动加载、重启/升级不丢;保留动态插件版为备选

许可证

MIT。Excalidraw 本体为 MIT 协议的开源项目(github.com/excalidraw/excalidraw),本站点为官方托管版本。