189-sketch / dsh-custom-logo

已收录

Replace the DSH top-left BrandWordmark/FishLogo with your own image or text — an inline ⚙ handle inside the wordmark, no floating widget

main工具 查看源代码

安装

npx -y @deepseek-ai/dsh plugin --profile web add github:189-sketch/dsh-custom-logo

此安装命令根据 GitHub 仓库地址生成,是未经验证的安装起点。

README

维护者编写的文档快照。

在 GitHub 查看 ↗
提交版本 9a2f15f同步于 2026年8月17日

Replace the top-left DSH logo (<BrandWordmark> + <FishLogo>) with your own image or text — directly inside the wordmark, no floating widget.

A standalone DeepSeek Harness (dsh) profile-bundle plugin. Replaces the hard-coded deepseek harness wordmark with a user-chosen image, text, or the original logo. The configuration handle (⚙) is inline inside the wordmark — hover the logo and the handle appears at the right edge; click it to open the settings panel.

dsh-custom-logo in action (drop a screenshot in docs/screenshot.png and replace this URL)

Why this plugin

The default DSH web UI shows a fixed deepseek harness wordmark in the top-left corner of the sidebar. Some users want their own brand there (their company name, a project codename, a logo), and there's no built-in option. This plugin adds that option without:

  • modifying DSH source
  • changing the "New session" click target on the wordmark button
  • obstructing the sidebar-collapsed rail (the toggle button is fully visible)
  • using a floating widget that hangs around the viewport

The replacement is scoped to image / text modes — in default mode the original wordmark renders untouched. The plugin is invisible until you configure it.

Features

  • Three modes: Default (no change) / Image (≤ 256 KB upload) / Text
  • Inline settings handle — hover the wordmark, ⚙ appears at the right edge, click to configure
  • Alignment for image and text modes: left / center / right
  • Font size for text mode: 10-48 px slider, double-click "auto" to fit the original wordmark height
  • Color picker for text mode
  • localStorage persistence — your choice survives page refresh, no login required
  • Sidebar-collapsed safe — when the DSH sidebar is in the rail state, the plugin removes everything so the toggle button is never obstructed
  • Settings panel lives in a Shadow DOM so its styles never bleed into the DSH shell
  • One-line install / uninstall via dsh plugin add

Installation

# Local development (links the checkout without copying)
dsh plugin --profile web add link:/path/to/dsh-custom-logo

# From GitHub (once published)
dsh plugin --profile web add git+https://github.com/<you>/dsh-custom-logo.git

# From npm (once published)
dsh plugin --profile web add dsh-custom-logo

Restart dsh web if it was already running. Hard-refresh the browser (Ctrl+F5) to bypass the client bundle cache.

Usage

  1. Hover the top-left deepseek harness wordmark → a small ⚙ handle fades in at the right edge.
  2. Click ⚙ → the settings panel opens.
  3. Choose a mode:
    • Default — close the panel; the original DSH logo returns
    • Image — upload a PNG / SVG / JPG (≤ 256 KB), pick alignment
    • Text — type your brand string, pick a color, font size, and alignment
  4. The change is instant and saved to localStorage automatically.
  5. Fold the sidebar to see the rail; your replacement does not obstruct the toggle button.

To reset, click Reset in the settings panel.

How it works

DSH renders the wordmark as a <button class="brand"> (see packages/client/ui-sidebar/src/client/SidebarRoot.tsx). The plugin appends a single <span data-clogo-handle> to that button. CSS hides the handle by default; JS hover listeners toggle inline opacity: 0 ↔ 1.

When the user picks Image or Text mode, the plugin also appends a <span data-clogo-slot> next to the BrandWordmark <svg>. A CSS general-sibling rule hides the original SVG when the slot exists ([data-clogo-slot] ~ svg { display: none }).

Both elements are owned by module-level singletons in the client bundle — paint() does not recreate them on every store change. This survives DSH re-rendering the sidebar (a real concern with React-based DSH) without losing hover state mid-interaction.

paint() measures [data-clogo-row] (a marker set on DSH's .brand button on first paint). If the row is narrower than 90 px, the plugin treats the sidebar as collapsed and removes everything — DSH has unmounted the entire .brand button in the rail state, so the original toggle button has the space it needs.

Why not DSH's ctx.styles.insert?

The plugin uses tsdown's CSS Modules inliner (not DSH's ctx.styles.insert) because:

  • ctx.styles is a DSH client builtin, but its TS signature lives in DSH's own type declarations; standalone plugins without monorepo type access can use it but lose type safety
  • CSS Modules lets the plugin ship a single self-contained bundle that DSH's module table loads without a separate runtime API call
  • The file is named *.module.css so tsdown's inliner picks it up — plain .css requires @tsdown/css (a separate dependency)

Layout

dsh-custom-logo/
├── package.json          # dsh.bundle.patch + dsh.client declarations
├── cordis.patch.yml      # the layer applied to the user's profile
├── tsconfig.json         # self-contained (no monorepo paths)
├── tsdown.config.ts      # inlines the DSH clientBundle preset
├── README.md
├── LICENSE
├── src/
│   ├── plugin/
│   │   ├── index.ts          # Host half: typed `apply(ctx: Context)`
│   │   └── invariant.ts      # dsh-invariants companion (no-op installer)
│   └── client/
│       ├── index.ts          # Browser half: paint, store, settings modal
│       └── logo.module.css   # CSS Modules — inlined into lib/client.js
└── lib/                     # build output (`pnpm run build`)
    ├── index.js             # ESM — Host half
    ├── invariant.js         # ESM — dsh-invariants companion
    ├── client.js            # CJS — browser bundle (window.__ModuleLoader__)
    └── types/
        ├── plugin/{index,invariant}.d.ts
        └── client/index.d.ts

Development

# Install deps
pnpm install

# Type-check + bundle (tsc + tsdown)
pnpm run build

# Watch mode
pnpm run watch

After pnpm run build, the bundle at lib/client.js is what DSH loads through the module table.

Configuration

The runtime choice is persisted in window.localStorage under dsh.custom-logo.v1. The state shape:

{
  mode: 'default' | 'image' | 'text',
  imageDataUrl: string,  // data URL; only used in image mode
  text: string,           // brand string; only used in text mode
  color: string,          // hex color; only used in text mode
  align: 'left' | 'center' | 'right',
  fontSize: number | null  // null = auto-fit the original wordmark height
}

This plugin is a workspace bundle — it does NOT receive a config argument to apply() (that channel is reserved for dynamic plugins through cordis-client-runner). Deployment defaults are encoded in src/client/index.ts.

Uninstall

dsh plugin --profile web remove dsh-custom-logo

Then restart dsh web. The plugin removes its localStorage entry only on user-driven reset — it survives uninstall to ease re-install.

Known limitations

  • DSH 内部 logo DOM 变化:DSH 重渲染 sidebar 时 <button class="brand"> 可能被 unmount + 重新 mount。paint() 通过 module-level singleton 复用 handle 元素并重新 attach,但首次延迟后用户可能看到一秒的不可见。
  • localStorage scope:状态按浏览器 profile 隔离,多 profile / 多浏览器不共享。
  • Image size:客户端 <input type="file"> 限制 256 KB(用 FileReader 转 data URL 内嵌)。
  • No SSR / no Node.js runtime:仅浏览器侧运行;Cordis 宿主侧只是 no-op。
  • No file watcher in production:修改 src/ 后必须 pnpm run build 一次;watch 仅用于开发。

License

MIT

仓库信息

开发语言
TypeScript
许可证
MIT
最新发布
v0.1.0
最后更新
2026年8月17日 08:08

谨慎安装

请检查源代码、权限、生命周期脚本、依赖与网络访问;不受信任的插件应先在隔离环境中测试。