Install
Inside DeepSeek Harness, with dsh-market
dsh plugin --profile web add dshmarket
Or from the command line
dsh plugin --profile web add dsh-settings-beautify
Installing runs third-party code with your own permissions — it can read your files, use your credentials and reach the network. Review the source first, and pin a commit (github:owner/repo#sha) when you can.
README
One design language for the DSH settings surface.
What it does
DSH's settings are composed from many plugins, and each page historically speaks a slightly different typography and surface language — page titles in 16/18/22px, explanations in 12/13/14px, cards with 8/10/12px radii, controls with their own heights and focus styles.
dsh-settings-beautify normalizes every settings page onto a single design language:
- Architecture: every page is built from the same three-part hierarchy — 标题 / Title → 解释 / Explanation → 内容 / Content (通用 General settings keeps its preference-row form, which is the same hierarchy in a compact variant).
- Typography: one size for every page title, one for every explanation, one for every item title and item description — regardless of which plugin contributed the page.
- Surfaces: consistent card radius/border/background, consistent rows,
controls, focus rings, tabs, chips and scrollbars, all driven by DSH's own
--dsw-*tokens, so light / dark / system themes keep working. - Motion: subtle, tasteful hover micro-motion that respects
prefers-reduced-motionand can be turned off. - Extensible: any page — including pages contributed by other plugins,
such as archived-conversation lists — opts into the same language with one
attribute (
data-dshb-scan), and the DOM normalizer handles the rest. - Headless: the plugin adds nothing to the settings nav rail — no
settings page of its own. Preferences are opt-in and live in
localStorage.
It works without touching DSH's source: the plugin observes the settings
panel, marks each structural role with a stable data-dshb-* attribute (the
built-in class names are build-hashed and can't be relied on), and a scoped
stylesheet applies the language on top.
What is covered
| Surface | Built in |
|---|---|
| Settings shell (nav rail, header, close, scrollbars) | ✅ |
| 通用 General — every preference row (language, appearance, font size, Enter behavior, agent presets, permissions, …) | ✅ |
| 模型 Models | ✅ |
| 智能体预设 Agent presets | ✅ |
| 内置插件 Built-in plugins (search, scope groups, catalog) | ✅ |
| Agent 预设 Agent presets (group headings, preset cards, tags) | ✅ |
Any third-party page that adds data-dshb-scan to its root (e.g. an archived-conversations page) |
✅ |
Installation
From the plugin market
dsh-settings-beautify follows the DSH community-market package contract
(dsh.bundle.patch + dsh.client manifest), so it can be installed from the
market or with:
dsh plugin --profile <profile> add dsh-settings-beautify
Manual install (development)
pnpm add dsh-settings-beautify # into the profile's package set
# and ensure the bundle entry is declared, e.g. via the profile patch:
# - insert:
# - id: dsh-settings-beautify
# name: dsh-settings-beautify
After install, restart DSH Desktop (or reload the web window). The design language is applied automatically — nothing is added to the settings nav rail.
Preferences (headless)
The plugin has no settings page of its own. Preferences are read from the
browser's localStorage under dsh-settings-beautify:prefs:
| Key | Values | Effect |
|---|---|---|
enabled |
true / false |
Apply the language or restore DSH's original look. |
density |
compact / default / comfortable |
Row and list spacing. |
motion |
true / false |
Card hover micro-motion. prefers-reduced-motion always wins. |
Defaults: {"enabled": true, "density": "default", "motion": true}. To tune
them, open the browser console and run:
window.DSHB.setPrefs({ density: "compact" }) // or { enabled: false }, { motion: false }
No host files or settings namespaces are touched.
The design language
The full specification — tokens, hierarchy, spacing/radius/motion scale, and
the data-dshb-* attribute contract — lives in
docs/DESIGN.md. A condensed version:
| Role | Font | Color |
|---|---|---|
| Page title (页面标题) | 18px / 600 / 26px | --dsw-alias-label-primary |
| Page explanation (页面解释) | 13px / 400 / 20px | --dsw-alias-label-tertiary |
| Group title (组标题) | 14px / 600 / 22px | --dsw-alias-label-primary |
| Item title (条目标题) | 14px / 500 / 22px | --dsw-alias-label-primary |
| Item description (条目解释) | 13px / 400 / 20px | --dsw-alias-label-tertiary |
| Body (正文) | 14px / 400 / 22px | --dsw-alias-label-primary |
| Caption (辅助文字) | 12px / 400 / 18px | --dsw-alias-label-tertiary |
Cards: 12px radius · --dsw-alias-border-l2 · --dsw-alias-bg-layer-3 (elevated over the panel).
Controls: 8px radius, 36px min-height, brand focus ring. The title → caption
gap is a uniform 4px everywhere the language applies (--dshb-gap-title-desc,
matching DSH's row convention). Radii are tokenized (--dshb-*) so a future
version can offer alternate palettes.
Contributing pages from other plugins
The DOM normalizer auto-tags the built-in pages. For your plugin's page, either:
- Add
data-dshb-scanto the page root (a third-party section hosted inside the settings dialog works the same way) — the normalizer then applies the same heading/prose/card/row/control rules generically, including the uniform 4px title → caption gap; or - Use the attributes directly (
data-dshb-page-title,data-dshb-item-title,data-dshb-card, …) for full control.
See the extensibility contract.
Design notes
The plugin is intentionally headless: it only restyles the settings surface. If you would rather have a visible control page, that is a small follow-up change — open an issue and it can be added behind a preference.
Development
pnpm install
pnpm check # syntax checks
pnpm test # fixture-driven jsdom tests (135 assertions)
pnpm sync-styles # regenerate lib/styles/settings.css from lib/client.js
pnpm capture-fixtures # re-record test/fixtures/ from a running DSH Desktop
The tests do not hand-write a stand-in DOM. test/fixtures/<version>.json is
captured from a running DSH Desktop — the settings panel's markup and the
stylesheets the host injects — and test/cascade.mjs recomputes the cascade in
jsdom (specificity, inheritance, var() substitution, the shorthands the tagger
reads). Every heuristic is therefore exercised against the computed styles the
real build produces, not against inline styles that would silently stop
matching it.
After a DSH upgrade: pnpm capture-fixtures, run pnpm test, and fix what the
new surface broke. The fixture is committed, so a regression is reproducible
offline without a browser.
Compatibility
- DSH 0.1.7-rc.2 (DSH Desktop, bundled web UI). Currently adapted through 0.1.7-rc.2 against a captured fixture of that build.
- What 0.1.7-rc.2 changed underneath the plugin: the settings shell kept its
contract (
nav/content/header/options/[data-slot="settings.section"]), but every page below it was re-laid out — cards moved from 12px to 20px radius, the plugin-market page is gone (replaced by a searchable built-in plugin inventory), the DSH Desktop settings page no longer contributes a settings section, the header gained a second button, and tag/chip labels became a shared_tag_*primitive. 0.3.0 removed the selectors that no longer exist and taught the tagger the new shapes (a preference row is now detected by its divider + padding, cards by their border box, chip labels by their pill radius). - If the whole settings surface suddenly reverts to its unstyled form,
first check whether another plugin in the same profile still imports
host APIs that 2.0.5 removed (e.g.
@deepseek-ai/dsh-typert-protocolstopped exportingTypertRemoteFailurein 0.1.2-rc.1) — one failing plugin import can take down the entire profile plugin tree and with it this plugin. The tagger is defensive: anything it cannot recognize is simply left untouched. - The stylesheet only runs inside the settings panel scope; nothing outside settings is restyled.
Security
No network requests, no host APIs, no file access, no remote code. Preferences
live in localStorage. See SECURITY.md.
License
MIT — see LICENSE.
Comments
Comments live in GitHub Discussions. Sign in with GitHub to post or react.