DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

lizhanzhan89 /

lizhanzhan89/dsh-todo

Verified

Harness 侧边栏里的待办 + 笔记面板

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@d6fe0100

待办 (dsh-todo)

Harness 侧边栏里的事项面板,待办和笔记放在一起,按项目分块管理。

适合这样一个场景——事情分散在几个项目里,还有一堆不属于任何项目的小事, 不想为它们各开一个应用。所以这里的"项目"只是分组,不是工程:新建一个项目就是起个名字, 删掉它整个分组连同条目一起进回收站。

数据存成一个 JSON 文件,放在你自己的文稿目录里,不联网、不要账号、没有同步服务器。 备份就是一个文件,拷走、放进 Git、丢进网盘都行。

特性

  • 多行条目:Enter 换行,Ctrl/Cmd+Enter 保存;列表里完整显示,编辑框最多三行
  • 就地编辑:双击文字或点铅笔,不用弹窗
  • 拖动排序:项目拖导航行,条目拖行首的握把;「全部」里可跨类型混排
  • 搜索:就地隐藏不匹配的内容,不动数据
  • 回收站:删掉的条目和整个项目都能恢复,恢复时回到原来的位置
  • 行底色区分类型:未完成淡蓝、已完成淡绿、笔记更深的灰
  • 明暗主题:只用 Harness 的主题变量,跟随切换

安装

plugin_manager: install_bundle  target=/绝对路径/dsh-todo

装进当前 profile,所有会话共享同一个面板和同一份数据。

  • 插件包名:@local/dsh-todo
  • 侧边栏 id:todos(主面板 key 相同)
  • 数据文件:~/Documents/dsh-todo.json(macOS 中文系统即 ~/文稿/dsh-todo.json)
  • 路由:GET/POST /api/dsh-todo

需要 Harness 自带 webServer 和 connection 服务。数据文件走和页面相同的 cookie 鉴权。


数据文件在哪

~/Documents/dsh-todo.json

放在文稿目录,不放在工作区:工作区是随时会被清空、克隆、切换的地方, 而待办是个人数据,得活过这些操作。

想换位置(比如放进网盘同步目录),在 cordis.patch.yml 里给这一行加 fileName:

- id: dsh-todo
  name: '@local/dsh-todo'
  config:
    fileName: /Users/me/OneDrive/todo.json   # 绝对路径,原样使用

相对路径按文稿目录解析,不是工作区。这是普通的运行时读取,不是 Cordis 的 Config schema ——插件没有声明 Config,所以多余的键不会被校验或拒绝。

文件本身是纯文本,可以直接看、直接改、直接放进版本控制:

{
  "projects": [{ "id": "p1", "name": "工作" }],
  "todos": [
    {
      "id": "a1",
      "text": "写周报",
      "kind": "todo",          // "todo" | "entry"(entry = 笔记)
      "done": false,
      "completedAt": null,     // ISO 时间,完成时写入,重新打开时清空
      "projectId": "p1"        // null = 默认组
    }
  ],
  "trash": [
    // 单条:带 index,恢复时放回原位
    { "id": "…", "kind": "todo", "text": "…", "deletedAt": "ISO",
      "projectId": "p1", "projectName": "工作", "index": 0, "item": { } },
    // 整个项目:项目与其全部条目一起恢复
    { "id": "…", "kind": "project", "text": "工作", "deletedAt": "ISO",
      "index": 0, "project": { }, "items": [ ] }
  ],
  // 「包含已完成」开关:「全部」标签页和搜索结果共用这一个值
  "includeDone": true
}

数组顺序就是显示顺序,projects 决定分组顺序,todos 决定条目顺序。

每次改动都把完整状态 POST 给 Host,Host 写临时文件后 rename, 磁盘上永远是完整副本,不会读到写了一半的文件。


功能一览

功能 说明
项目分组 「默认」组固定在最前、不可拖动、不可删除;其余项目可增删
四个标签页 每个组有 全部 / 未完成 / 已完成 / 笔记,各带图标;每个组的选中页独立记忆
「全部」的顺序 笔记在最上,然后是未完成待办,最后是已完成待办
「全部」的已完成 「全部」标签页里有「包含已完成」勾选框,取消后不再列出已完成待办;这个状态存进 JSON,刷新后保持
添加 添加按钮只显示「+」图标,文字在占位符和提示里;输入框因此更宽
待办 复选框标记完成,自动记录完成时间;重新打开时清空时间
笔记 无复选框的纯文字条目,适合记录说明
编辑 双击文字或点铅笔按钮;Ctrl/Cmd+Enter 保存、Esc 取消、失焦保存、清空即取消
多行 添加框和编辑框里 Enter 是换行,保存用 Ctrl/Cmd+Enter
长文本 列表里完整显示,不截断;只有编辑框限制最多三行(内容少时按实际行数显示),超出在框内滚动
只读 已完成的待办不可编辑,需先取消完成
项目排序 拖动左侧快速导航里的项目行
条目排序 只能拖动行首的图标;单类型标签页里限同组同类型,「全部」里可在同组内跨类型混排
删除项目 把导航行拖到底部的删除区域(导航里没有删除按钮)
删除条目 行尾垃圾桶按钮
回收站 删除的条目和整个项目先进回收站,可恢复或永久删除
搜索 标题右侧搜索框,就地隐藏不匹配内容;旁边的「包含已完成」与「全部」标签页的勾选框是同一个开关
快速跳转 点导航里的组名,滚动到对应分组
导出 导航底部「导出」,把全部内容下载成一个带日期的 JSON 文件
导入 导航底部「导入」,从 JSON 备份合并进来,已有内容不删除
同步 导航底部「同步」,立刻把当前内容写入数据文件并报告结果
行底色 没有左侧色条,改用很淡的底色:未完成待办淡蓝、已完成待办淡绿、笔记更深的灰;导航底部的导出/导入/同步区域同色

导出 / 导入 / 同步

三个按钮在左侧导航底部、"新建项目"上方。

同步是一次手动、可确认的写入。改动本来就会自动保存(每次状态变化都 POST 一次), 所以「同步」的作用不是补做保存,而是:

  • 强制立刻写一次,不用等下一次改动
  • 把写入结果告诉你——自动保存是静默的,失败了不会有任何提示;同步成功显示 「已同步到 JSON 文件:N 个项目、M 个条目…」,失败则显示红色错误提示,需要手动关闭

如果怀疑数据没落盘(比如换了一台机器读不到刚加的内容),点一下就知道。

导出下载 dsh-todo-YYYY-MM-DD.json,内容是完整状态(项目、待办、笔记、回收站)。文件带一个信封:

{
  "format": "dsh-todo",
  "version": 1,
  "exportedAt": "2024-05-01T10:00:00.000Z",
  "projects": [ … ],
  "todos": [ … ],
  "trash": [ … ]
}

导入是合并,不是覆盖,这样可以安心地在一台设备上恢复、或把别人的清单并进来:

情况 结果
同名项目 两个都保留(项目靠 id 区分,不靠名字)
条目所属项目不存在 落到「默认」组
导入两次同一个文件 出现两份,但 id 全部重新生成,不会互相覆盖
文件不是 JSON / 不是待办备份 / 没有任何条目 拒绝导入,状态完全不变,右下角显示错误提示
裸状态文件(没有 format 信封、没有 trash) 接受,按待办处理
结构损坏的单行 丢弃该行,其余照常导入

导入后右下角显示「已导入 N 个项目、M 个条目…」,成功提示 5 秒自动消失,错误提示需手动关闭。 整个操作只改浏览器里的状态,随后照常写入 JSON 文件,所以导入结果立刻落盘。

想「用备份完全替换」而不是合并:先导出当前内容留底,再在应用里删掉不要的内容,然后导入备份。


目录结构

dsh-todo/
├── package.json          # 包清单:exports / files / dsh.bundle / dsh.client
├── cordis.patch.yml      # 往 profile 组合里插入插件行
├── index.js              # Host 半部分:数据文件 + HTTP 路由
├── icon.svg              # 插件图标(侧边栏和插件管理页共用)
├── locale/
│   ├── en.json           # 插件管理页显示的标题/描述(英文)
│   └── zh.json           # 同上(中文)
├── build.mjs             # 把 src/ 拼成 client/index.js
├── client/
│   └── index.js          # ← 生成物,浏览器实际加载的产物
└── src/                  # 源码(唯一需要手改的地方)
    ├── constants.js      # id、路由、标签页和类型常量
    ├── board-ops.js      # 纯数据操作(增删改、排序、回收站)
    ├── storage.js        # 读写 Host 的 JSON 文件
    ├── backup.js         # 导出格式、校验、合并导入
    ├── styles.js         # 整份 CSS(只用 --dsw-alias-* 主题变量)
    ├── icons.js          # 内联 SVG 图标
    ├── format.js         # 时间格式化
    ├── page.js           # 页面:状态、事件处理、装配
    ├── plugin.js         # apply():注册语言包、样式、图标、页面
    ├── locale/
    │   ├── en.js         # 界面文案(英文)
    │   └── zh.js         # 界面文案(中文)
    └── components/
        ├── row.js        # 单条待办/笔记,含就地编辑器
        ├── group.js      # 一个项目分组(标签页 + 标题 + 添加框 + 列表)
        ├── nav.js        # 左侧快速导航、删除区、新建项目
        ├── search.js     # 搜索框 + 包含已完成
        └── trash.js      # 回收站视图

为什么有 build.mjs

Harness 的静态 Client 半部分是单个纯 JS 文件:没有 import、没有 JSX、没有打包器,浏览器只加载一个调用 window.__ModuleLoader__.load({ id, factory }) 的产物。为了让代码分文件又能直接跑,build.mjs 按依赖顺序把 src/ 下的模块拼进同一个 factory 作用域:

node build.mjs          # 生成 client/index.js
node build.mjs --check  # 检查产物是否最新(CI 用)

改了 src/ 里的任何文件后,必须重新 node build.mjs,否则运行的是旧代码。 client/index.js 是生成物,不要直接编辑——下次构建会覆盖。


开发

Host 半部分 (index.js)

  • 写入走 pickState() 白名单:只有 projects / todos / trash / includeDone 会进文件。 新增字段时必须同时加到这个函数里,否则 Client 提交了也会被静默丢弃,刷新后回到默认值—— 这个坑真的踩过:includeDone 加了、Client 也 POST 了,白名单没认,于是每次刷新都回到勾选状态。
  • 数据文件路径的默认值来自 documentsDir()(home/Documents)。不要改成工作区:工作区会被清空或切换。
  • 路由与页面一样走 connection.authorizeIndex 鉴权,用浏览器 cookie 认证。
  • GET / HEAD 返回状态;POST 覆盖写入(400 = 非法 JSON,405 = 其他方法,500 = 内部错误)。

Client 半部分 (src/)

  • 数据流:TodoPage 持有 state;初始 loadState(),之后每次 state 变化 saveState()。 加载完成前的第一次渲染不写盘(loadedRef)。
  • 所有数据修改都是 board-ops.js 里的纯函数 (prev, ...) => next,页面只负责调用 setState。
  • 组件是普通渲染函数(不是 React 组件),接收一个统一的 api 对象,因此不需要传一堆 props。
  • 样式全部在 styles.js,用 <style data-dsh-todo> 注入,卸载时移除;类名统一 tp- 前缀,只引用 --dsw-alias-* 主题变量,跟随明暗主题。

改界面时从哪下手

想改什么 改哪里
文案(中/英) src/locale/zh.js、src/locale/en.js(两边键必须一致)
颜色、间距、圆角 src/styles.js
单条待办/笔记的外观 src/components/row.js
分组头(标签页、标题、添加框) src/components/group.js
左侧导航、删除区 src/components/nav.js
搜索行为 src/page.js(needle/matches/visibleInSearch)+ src/components/group.js(计数)
数据规则(排序、回收站) src/board-ops.js
导出格式、导入合并规则 src/backup.js
数据文件路径、路由 index.js

改完怎么生效

  1. node build.mjs(重新生成 client/index.js)
  2. node build.mjs --check 与 node --check client/index.js 自检
  3. 重启 Host(Client 产物是按文件元数据缓存的,只有 Host 重启才会重新取快照)
  4. 浏览器刷新页面

面板标题旁边有一个版本号(如 v2026-11-05.6),它就是用来确认浏览器到底加载了哪份代码。 改完记得在 src/constants.js 里把 BUILD 往上挪一位;看到旧版本号说明没生效,别急着怀疑 CSS。

样式问题优先看层叠,不是看规则在不在。同特异性时后写的赢,一条看起来正确的规则完全可能被 下面的规则覆盖掉——改完先在 DevTools 里确认最终生效值。

卸载

plugin_manager: remove_bundle  target=@local/dsh-todo

数据文件不会跟着删;想清空就手动删掉 ~/Documents/dsh-todo.json。

—/ 5

No ratings yet

Verified DSH bundle

Commit d6fe01008012

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout